1 #include "keymanager.h"
6 #include <boost/scoped_array.hpp>
8 #include "crypto/openssl_compat.h"
10 #include "storage/invstorage.h"
16 static constexpr
bool built_with_p11 =
true;
18 static constexpr
bool built_with_p11 =
false;
21 KeyManager::KeyManager(std::shared_ptr<INvStorage> backend,
KeyManagerConfig config)
22 : backend_(std::move(backend)), config_(std::move(config)) {
24 p11_ = std_::make_unique<P11EngineGuard>(config_.p11);
28 void KeyManager::loadKeys(
const std::string *pkey_content,
const std::string *cert_content,
29 const std::string *ca_content) {
30 if (config_.tls_pkey_source == CryptoSource::kFile) {
32 if (pkey_content !=
nullptr) {
35 backend_->loadTlsPkey(&pkey);
38 if (tmp_pkey_file ==
nullptr) {
39 tmp_pkey_file = std_::make_unique<TemporaryFile>(
"tls-pkey");
41 tmp_pkey_file->PutContents(pkey);
44 if (config_.tls_cert_source == CryptoSource::kFile) {
46 if (cert_content !=
nullptr) {
49 backend_->loadTlsCert(&cert);
52 if (tmp_cert_file ==
nullptr) {
53 tmp_cert_file = std_::make_unique<TemporaryFile>(
"tls-cert");
55 tmp_cert_file->PutContents(cert);
58 if (config_.tls_ca_source == CryptoSource::kFile) {
60 if (ca_content !=
nullptr) {
63 backend_->loadTlsCa(&ca);
66 if (tmp_ca_file ==
nullptr) {
67 tmp_ca_file = std_::make_unique<TemporaryFile>(
"tls-ca");
69 tmp_ca_file->PutContents(ca);
74 std::string KeyManager::getPkeyFile()
const {
75 std::string pkey_file;
76 if (config_.tls_pkey_source == CryptoSource::kPkcs11) {
77 if (!built_with_p11) {
78 throw std::runtime_error(
"Aktualizr was built without PKCS#11");
80 pkey_file = (*p11_)->getTlsPkeyId();
82 if (config_.tls_pkey_source == CryptoSource::kFile) {
83 if (tmp_pkey_file && !boost::filesystem::is_empty(tmp_pkey_file->PathString())) {
84 pkey_file = tmp_pkey_file->PathString();
90 std::string KeyManager::getCertFile()
const {
91 std::string cert_file;
92 if (config_.tls_cert_source == CryptoSource::kPkcs11) {
93 if (!built_with_p11) {
94 throw std::runtime_error(
"Aktualizr was built without PKCS#11");
96 cert_file = (*p11_)->getTlsCertId();
98 if (config_.tls_cert_source == CryptoSource::kFile) {
99 if (tmp_cert_file && !boost::filesystem::is_empty(tmp_cert_file->PathString())) {
100 cert_file = tmp_cert_file->PathString();
106 std::string KeyManager::getCaFile()
const {
108 if (config_.tls_ca_source == CryptoSource::kPkcs11) {
109 if (!built_with_p11) {
110 throw std::runtime_error(
"Aktualizr was built without PKCS#11");
112 ca_file = (*p11_)->getTlsCacertId();
114 if (config_.tls_ca_source == CryptoSource::kFile) {
115 if (tmp_ca_file && !boost::filesystem::is_empty(tmp_ca_file->PathString())) {
116 ca_file = tmp_ca_file->PathString();
122 std::string KeyManager::getPkey()
const {
124 if (config_.tls_pkey_source == CryptoSource::kPkcs11) {
125 if (!built_with_p11) {
126 throw std::runtime_error(
"Aktualizr was built without PKCS#11");
128 pkey = (*p11_)->getTlsPkeyId();
130 if (config_.tls_pkey_source == CryptoSource::kFile) {
131 backend_->loadTlsPkey(&pkey);
136 std::string KeyManager::getCert()
const {
138 if (config_.tls_cert_source == CryptoSource::kPkcs11) {
139 if (!built_with_p11) {
140 throw std::runtime_error(
"Aktualizr was built without PKCS#11");
142 cert = (*p11_)->getTlsCertId();
144 if (config_.tls_cert_source == CryptoSource::kFile) {
145 backend_->loadTlsCert(&cert);
150 std::string KeyManager::getCa()
const {
152 if (config_.tls_ca_source == CryptoSource::kPkcs11) {
153 if (!built_with_p11) {
154 throw std::runtime_error(
"Aktualizr was built without PKCS#11");
156 ca = (*p11_)->getTlsCacertId();
158 if (config_.tls_ca_source == CryptoSource::kFile) {
159 backend_->loadTlsCa(&ca);
164 std::string KeyManager::getCN()
const {
165 const std::string not_found_cert_message =
"Certificate is not found, can't extract device_id";
167 if (config_.tls_cert_source == CryptoSource::kFile) {
168 if (!backend_->loadTlsCert(&cert)) {
169 throw std::runtime_error(not_found_cert_message);
172 if (!built_with_p11) {
173 throw std::runtime_error(
"Aktualizr was built without PKCS#11 support, can't extract device_id");
175 if (!(*p11_)->readTlsCert(&cert)) {
176 throw std::runtime_error(not_found_cert_message);
180 return Crypto::extractSubjectCN(cert);
183 void KeyManager::getCertInfo(std::string *subject, std::string *issuer, std::string *not_before,
184 std::string *not_after)
const {
185 std::string not_found_cert_message =
"Certificate is not found, can't extract device certificate";
187 if (config_.tls_cert_source == CryptoSource::kFile) {
188 if (!backend_->loadTlsCert(&cert)) {
189 throw std::runtime_error(not_found_cert_message);
192 if (!built_with_p11) {
193 throw std::runtime_error(
"Aktualizr was built without PKCS#11 support, can't extract device certificate");
195 if (!(*p11_)->readTlsCert(&cert)) {
196 throw std::runtime_error(not_found_cert_message);
200 StructGuard<BIO> bio(BIO_new_mem_buf(
const_cast<char *
>(cert.c_str()),
static_cast<int>(cert.size())), BIO_vfree);
201 StructGuard<X509> x(PEM_read_bio_X509(bio.get(),
nullptr,
nullptr,
nullptr), X509_free);
203 throw std::runtime_error(
"Could not parse certificate");
206 StructGuard<BIO> subj_bio(BIO_new(BIO_s_mem()), BIO_vfree);
207 X509_NAME_print_ex(subj_bio.get(), X509_get_subject_name(x.get()), 1, 0);
208 char *subj_buf =
nullptr;
209 auto subj_len = BIO_get_mem_data(subj_bio.get(), &subj_buf);
210 if (subj_buf ==
nullptr) {
211 throw std::runtime_error(
"Could not parse certificate subject");
213 *subject = std::string(subj_buf,
static_cast<size_t>(subj_len));
215 StructGuard<BIO> issuer_bio(BIO_new(BIO_s_mem()), BIO_vfree);
216 X509_NAME_print_ex(issuer_bio.get(), X509_get_issuer_name(x.get()), 1, 0);
217 char *issuer_buf =
nullptr;
218 auto issuer_len = BIO_get_mem_data(issuer_bio.get(), &issuer_buf);
219 if (issuer_buf ==
nullptr) {
220 throw std::runtime_error(
"Could not parse certificate issuer");
222 *issuer = std::string(issuer_buf,
static_cast<size_t>(issuer_len));
224 #if AKTUALIZR_OPENSSL_PRE_11
225 const ASN1_TIME *nb_asn1 = X509_get_notBefore(x.get());
227 const ASN1_TIME *nb_asn1 = X509_get0_notBefore(x.get());
229 StructGuard<BIO> nb_bio(BIO_new(BIO_s_mem()), BIO_vfree);
230 ASN1_TIME_print(nb_bio.get(), nb_asn1);
232 auto nb_len = BIO_get_mem_data(nb_bio.get(), &nb_buf);
233 *not_before = std::string(nb_buf,
static_cast<size_t>(nb_len));
235 #if AKTUALIZR_OPENSSL_PRE_11
236 const ASN1_TIME *na_asn1 = X509_get_notAfter(x.get());
238 const ASN1_TIME *na_asn1 = X509_get0_notAfter(x.get());
240 StructGuard<BIO> na_bio(BIO_new(BIO_s_mem()), BIO_vfree);
241 ASN1_TIME_print(na_bio.get(), na_asn1);
243 auto na_len = BIO_get_mem_data(na_bio.get(), &na_buf);
244 *not_after = std::string(na_buf,
static_cast<size_t>(na_len));
247 void KeyManager::copyCertsToCurl(
HttpInterface &http)
const {
248 std::string pkey = getPkey();
249 std::string cert = getCert();
250 std::string ca = getCa();
252 if (!pkey.empty() && !cert.empty() && !ca.empty()) {
253 http.setCerts(ca, config_.tls_ca_source, cert, config_.tls_cert_source, pkey, config_.tls_pkey_source);
257 Json::Value KeyManager::signTuf(
const Json::Value &in_data)
const {
258 ENGINE *crypto_engine =
nullptr;
259 std::string private_key;
260 if (config_.uptane_key_source == CryptoSource::kPkcs11) {
261 if (!built_with_p11) {
262 throw std::runtime_error(
"Aktualizr was built without PKCS#11");
264 crypto_engine = (*p11_)->getEngine();
265 private_key = config_.p11.uptane_key_id;
269 if (config_.uptane_key_source == CryptoSource::kFile) {
270 backend_->loadPrimaryPrivate(&private_key);
272 b64sig = Utils::toBase64(
273 Crypto::Sign(config_.uptane_key_type, crypto_engine, private_key, Utils::jsonToCanonicalStr(in_data)));
275 Json::Value signature;
276 switch (config_.uptane_key_type) {
277 case KeyType::kRSA2048:
278 case KeyType::kRSA3072:
279 case KeyType::kRSA4096:
280 signature[
"method"] =
"rsassa-pss";
282 case KeyType::kED25519:
283 signature[
"method"] =
"ed25519";
286 throw std::runtime_error(
"Unknown key type");
288 signature[
"sig"] = b64sig;
290 Json::Value out_data;
291 signature[
"keyid"] = UptanePublicKey().KeyId();
292 out_data[
"signed"] = in_data;
293 out_data[
"signatures"] = Json::Value(Json::arrayValue);
294 out_data[
"signatures"].append(signature);
298 std::string KeyManager::generateUptaneKeyPair() {
299 std::string primary_public;
301 if (config_.uptane_key_source == CryptoSource::kFile) {
302 std::string primary_private;
303 if (!backend_->loadPrimaryKeys(&primary_public, &primary_private)) {
304 bool result_ = Crypto::generateKeyPair(config_.uptane_key_type, &primary_public, &primary_private);
306 backend_->storePrimaryKeys(primary_public, primary_private);
309 if (primary_public.empty() && primary_private.empty()) {
310 throw std::runtime_error(
"Could not get Uptane keys");
313 if (!built_with_p11) {
314 throw std::runtime_error(
"Aktualizr was built without PKCS#11 support!");
317 if (!(*p11_)->readUptanePublicKey(&primary_public)) {
318 (*p11_)->generateUptaneKeyPair();
321 if (primary_public.empty() && !(*p11_)->readUptanePublicKey(&primary_public)) {
322 throw std::runtime_error(
"Could not get Uptane keys");
325 return primary_public;
328 PublicKey KeyManager::UptanePublicKey()
const {
329 std::string primary_public;
330 if (config_.uptane_key_source == CryptoSource::kFile) {
331 if (!backend_->loadPrimaryPublic(&primary_public)) {
332 throw std::runtime_error(
"Could not get Uptane public key!");
335 if (!built_with_p11) {
336 throw std::runtime_error(
"Aktualizr was built without PKCS#11 support!");
339 if (!(*p11_)->readUptanePublicKey(&primary_public)) {
340 throw std::runtime_error(
"Could not get Uptane public key!");
343 return PublicKey(primary_public, config_.uptane_key_type);