• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender / 1046247406

23 Oct 2023 09:07AM UTC coverage: 80.105% (-0.1%) from 80.226%
1046247406

push

gitlab-ci

oleorhagen
feat(crypto): Add HSM support

This adds support for HSM key storage. This is a wrapper around the existing
OpenSSL external crypto support, and supports both the deprecated `ENGINE` API
in OpenSSL 1.x, and the new `Provider` API in OpenSSL 3.x.

Ticket: MEN-6668
Changelog: The client's HSM crypto-module support is changed so that the
`PrivateKey` used for `authentication` is always taken from the configurations:
`security.AuthPrivateKey`, and the `HttpsClient.private_key` is only used as the
key for the associated certificate `HttpsClient.client_certificate`. The two can
still use the same key, but this means now that you add the same key `url` in
both places.

Signed-off-by: Ole Petter <ole.orhagen@northern.tech>

66 of 66 new or added lines in 7 files covered. (100.0%)

6845 of 8545 relevant lines covered (80.11%)

9412.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

59.49
/mender-auth/cli/actions.cpp
1
// Copyright 2023 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
#include <mender-auth/cli/actions.hpp>
16

17
#include <string>
18
#include <memory>
19

20
#include <api/auth.hpp>
21

22
#include <mender-auth/context.hpp>
23
#include <mender-auth/cli/keystore.hpp>
24

25
#include <common/conf.hpp>
26
#include <common/events.hpp>
27
#include <common/log.hpp>
28

29
#include <mender-auth/ipc/server.hpp>
30

31
namespace mender {
32
namespace auth {
33
namespace cli {
34

35
using namespace std;
36

37
namespace auth_client = mender::api::auth;
38
namespace events = mender::common::events;
39
namespace ipc = mender::auth::ipc;
40
namespace log = mender::common::log;
41

42
shared_ptr<MenderKeyStore> KeystoreFromConfig(
4✔
43
        const conf::MenderConfig &config, const string &passphrase) {
44
        cli::StaticKey static_key = cli::StaticKey::No;
4✔
45
        string pem_file;
46
        string ssl_engine;
47

48
        if (config.security.auth_private_key != "") {
4✔
49
                pem_file = config.security.auth_private_key;
50
                ssl_engine = config.security.ssl_engine;
×
51
                static_key = cli::StaticKey::Yes;
×
52
        } else {
53
                pem_file = config.paths.GetKeyFile();
4✔
54
                static_key = cli::StaticKey::No;
4✔
55
        }
56

57
        return make_shared<MenderKeyStore>(pem_file, ssl_engine, static_key, passphrase);
8✔
58
}
59

60
error::Error DoBootstrap(shared_ptr<MenderKeyStore> keystore, const bool force) {
4✔
61
        auto err = keystore->Load();
4✔
62
        if (err != error::NoError && err.code != MakeError(NoKeysError, "").code) {
10✔
63
                return err;
64
        }
65
        if (err.code == MakeError(NoKeysError, "").code || force) {
8✔
66
                log::Info("Generating new RSA key");
6✔
67
                err = keystore->Generate();
3✔
68
                if (err != error::NoError) {
3✔
69
                        return err;
70
                }
71
                err = keystore->Save();
6✔
72
                if (err != error::NoError) {
73
                        return err;
74
                }
75
        }
76
        return err;
77
}
78

79
error::Error DoAuthenticate(context::MenderContext &main_context) {
4✔
80
        events::EventLoop loop;
81
        auto &config = main_context.GetConfig();
82
        if (config.servers.size() == 0) {
4✔
83
                log::Info("No server set in the configuration, skipping authentication");
6✔
84
                return error::NoError;
3✔
85
        }
86
        mender::common::events::Timer timer {loop};
2✔
87
        http::Client client {main_context.GetConfig().GetHttpClientConfig(), loop};
3✔
88
        auto err = auth_client::FetchJWTToken(
89
                client,
90
                config.servers,
1✔
91
                {
92
                        config.security.auth_private_key == "" ? config.paths.GetKeyFile()
1✔
93
                                                                                                   : config.security.auth_private_key,
94
                        "",
95
                        config.security.ssl_engine,
1✔
96
                },
97
                config.paths.GetInventoryScriptsDir(),
1✔
98
                [&loop, &timer](auth_client::APIResponse resp) {
3✔
99
                        log::Info("Got Auth response");
2✔
100
                        if (resp) {
1✔
101
                                log::Info(
1✔
102
                                        "Successfully authorized with the server '" + resp.value().server_url + "'");
2✔
103
                        } else {
104
                                log::Error(resp.error().String());
×
105
                        }
106
                        timer.Cancel();
1✔
107
                        loop.Stop();
1✔
108
                },
1✔
109
                config.tenant_token);
4✔
110
        if (err != error::NoError) {
1✔
111
                return err;
×
112
        }
113
        timer.AsyncWait(chrono::seconds {30}, [&loop](error::Error err) { loop.Stop(); });
1✔
114
        loop.Run();
1✔
115
        return error::NoError;
1✔
116
}
117

118
DaemonAction::DaemonAction(shared_ptr<MenderKeyStore> keystore, const bool force_bootstrap) :
×
119
        keystore_(keystore),
120
        force_bootstrap_(force_bootstrap) {
×
121
}
×
122

123
ExpectedActionPtr DaemonAction::Create(
×
124
        const conf::MenderConfig &config, const string &passphrase, const bool force_bootstrap) {
125
        auto key_store = KeystoreFromConfig(config, passphrase);
×
126

127
        return make_shared<DaemonAction>(key_store, force_bootstrap);
×
128
}
129

130
error::Error DaemonAction::Execute(context::MenderContext &main_context) {
×
131
        auto &config = main_context.GetConfig();
132
        if (!none_of(config.servers.cbegin(), config.servers.cend(), [](const string &it) {
×
133
                        return it != "";
×
134
                })) {
135
                log::Error("Cannot run in daemon mode with no server URL specified");
×
136
                return error::MakeError(error::ExitWithFailureError, "");
×
137
        }
138

139
        auto err = DoBootstrap(keystore_, force_bootstrap_);
×
140
        if (err != error::NoError) {
×
141
                log::Error("Failed to bootstrap: " + err.String());
×
142
                return error::MakeError(error::ExitWithFailureError, "");
×
143
        }
144

145
        events::EventLoop loop {};
×
146

147
        ipc::Server ipc_server {loop, config};
×
148

149
        err = ipc_server.Listen(
×
150
                {config.security.auth_private_key == "" ? config.paths.GetKeyFile()
×
151
                                                                                                : config.security.auth_private_key,
152
                 "",
153
                 config.security.ssl_engine},
×
154
                config.paths.GetIdentityScript());
×
155
        if (err != error::NoError) {
×
156
                log::Error("Failed to start the listen loop");
×
157
                log::Error(err.String());
×
158
                return error::MakeError(error::ExitWithFailureError, "");
×
159
        }
160

161
        loop.Run();
×
162

163
        return error::NoError;
×
164
}
165

166
BootstrapAction::BootstrapAction(shared_ptr<MenderKeyStore> keystore, bool force_bootstrap) :
4✔
167
        keystore_(keystore),
168
        force_bootstrap_(force_bootstrap) {
8✔
169
}
4✔
170

171
ExpectedActionPtr BootstrapAction::Create(
4✔
172
        const conf::MenderConfig &config, const string &passphrase, bool force_bootstrap) {
173
        auto key_store = KeystoreFromConfig(config, passphrase);
4✔
174

175
        return make_shared<BootstrapAction>(key_store, force_bootstrap);
8✔
176
}
177

178
error::Error BootstrapAction::Execute(context::MenderContext &main_context) {
4✔
179
        auto err = DoBootstrap(keystore_, force_bootstrap_);
4✔
180
        if (err != error::NoError) {
4✔
181
                return err;
×
182
        }
183
        return DoAuthenticate(main_context);
4✔
184
}
185

186
} // namespace cli
187
} // namespace auth
188
} // namespace mender
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc