Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
keymanager.cc
1 #include "keymanager.h"
2 
3 #include <stdexcept>
4 #include <utility>
5 
6 #include <boost/scoped_array.hpp>
7 
8 #include "crypto/openssl_compat.h"
9 #include "storage/invstorage.h"
10 #include "utilities/types.h"
11 
12 #if defined(ANDROID)
13 #include "androidkeystore.h"
14 #endif
15 
16 // by using constexpr the compiler can optimize out method calls when the
17 // feature is disabled. We won't then need to link with the actual p11 engine
18 // implementation
19 #ifdef BUILD_P11
20 static constexpr bool built_with_p11 = true;
21 #else
22 static constexpr bool built_with_p11 = false;
23 #endif
24 
25 KeyManager::KeyManager(std::shared_ptr<INvStorage> backend, KeyManagerConfig config)
26  : backend_(std::move(backend)), config_(std::move(config)) {
27  if (built_with_p11) {
28  p11_ = std_::make_unique<P11EngineGuard>(config_.p11);
29  }
30 }
31 
32 void KeyManager::loadKeys(const std::string *pkey_content, const std::string *cert_content,
33  const std::string *ca_content) {
34  if (config_.tls_pkey_source == CryptoSource::kFile || config_.tls_pkey_source == CryptoSource::kAndroid) {
35  std::string pkey;
36  if (pkey_content != nullptr) {
37  pkey = *pkey_content;
38  } else {
39  backend_->loadTlsPkey(&pkey);
40  }
41  if (!pkey.empty()) {
42  if (tmp_pkey_file == nullptr) {
43  tmp_pkey_file = std_::make_unique<TemporaryFile>("tls-pkey");
44  }
45  tmp_pkey_file->PutContents(pkey);
46  }
47  }
48  if (config_.tls_cert_source == CryptoSource::kFile || config_.tls_cert_source == CryptoSource::kAndroid) {
49  std::string cert;
50  if (cert_content != nullptr) {
51  cert = *cert_content;
52  } else {
53  backend_->loadTlsCert(&cert);
54  }
55  if (!cert.empty()) {
56  if (tmp_cert_file == nullptr) {
57  tmp_cert_file = std_::make_unique<TemporaryFile>("tls-cert");
58  }
59  tmp_cert_file->PutContents(cert);
60  }
61  }
62  if (config_.tls_ca_source == CryptoSource::kFile || config_.tls_ca_source == CryptoSource::kAndroid) {
63  std::string ca;
64  if (ca_content != nullptr) {
65  ca = *ca_content;
66  } else {
67  backend_->loadTlsCa(&ca);
68  }
69  if (!ca.empty()) {
70  if (tmp_ca_file == nullptr) {
71  tmp_ca_file = std_::make_unique<TemporaryFile>("tls-ca");
72  }
73  tmp_ca_file->PutContents(ca);
74  }
75  }
76 }
77 
78 std::string KeyManager::getPkeyFile() const {
79  std::string pkey_file;
80  if (config_.tls_pkey_source == CryptoSource::kPkcs11) {
81  if (!built_with_p11) {
82  throw std::runtime_error("Aktualizr was built without PKCS#11");
83  }
84  pkey_file = (*p11_)->getTlsPkeyId();
85  }
86  if (config_.tls_pkey_source == CryptoSource::kFile || config_.tls_pkey_source == CryptoSource::kAndroid) {
87  if (tmp_pkey_file && !boost::filesystem::is_empty(tmp_pkey_file->PathString())) {
88  pkey_file = tmp_pkey_file->PathString();
89  }
90  }
91  return pkey_file;
92 }
93 
94 std::string KeyManager::getCertFile() const {
95  std::string cert_file;
96  if (config_.tls_cert_source == CryptoSource::kPkcs11) {
97  if (!built_with_p11) {
98  throw std::runtime_error("Aktualizr was built without PKCS#11");
99  }
100  cert_file = (*p11_)->getTlsCertId();
101  }
102  if (config_.tls_cert_source == CryptoSource::kFile || config_.tls_cert_source == CryptoSource::kAndroid) {
103  if (tmp_cert_file && !boost::filesystem::is_empty(tmp_cert_file->PathString())) {
104  cert_file = tmp_cert_file->PathString();
105  }
106  }
107  return cert_file;
108 }
109 
110 std::string KeyManager::getCaFile() const {
111  std::string ca_file;
112  if (config_.tls_ca_source == CryptoSource::kPkcs11) {
113  if (!built_with_p11) {
114  throw std::runtime_error("Aktualizr was built without PKCS#11");
115  }
116  ca_file = (*p11_)->getTlsCacertId();
117  }
118  if (config_.tls_ca_source == CryptoSource::kFile || config_.tls_ca_source == CryptoSource::kAndroid) {
119  if (tmp_ca_file && !boost::filesystem::is_empty(tmp_ca_file->PathString())) {
120  ca_file = tmp_ca_file->PathString();
121  }
122  }
123  return ca_file;
124 }
125 
126 std::string KeyManager::getPkey() const {
127  std::string pkey;
128  if (config_.tls_pkey_source == CryptoSource::kPkcs11) {
129  if (!built_with_p11) {
130  throw std::runtime_error("Aktualizr was built without PKCS#11");
131  }
132  pkey = (*p11_)->getTlsPkeyId();
133  }
134  if (config_.tls_pkey_source == CryptoSource::kFile || config_.tls_pkey_source == CryptoSource::kAndroid) {
135  backend_->loadTlsPkey(&pkey);
136  }
137  return pkey;
138 }
139 
140 std::string KeyManager::getCert() const {
141  std::string cert;
142  if (config_.tls_cert_source == CryptoSource::kPkcs11) {
143  if (!built_with_p11) {
144  throw std::runtime_error("Aktualizr was built without PKCS#11");
145  }
146  cert = (*p11_)->getTlsCertId();
147  }
148  if (config_.tls_cert_source == CryptoSource::kFile || config_.tls_cert_source == CryptoSource::kAndroid) {
149  backend_->loadTlsCert(&cert);
150  }
151  return cert;
152 }
153 
154 std::string KeyManager::getCa() const {
155  std::string ca;
156  if (config_.tls_ca_source == CryptoSource::kPkcs11) {
157  if (!built_with_p11) {
158  throw std::runtime_error("Aktualizr was built without PKCS#11");
159  }
160  ca = (*p11_)->getTlsCacertId();
161  }
162  if (config_.tls_ca_source == CryptoSource::kFile || config_.tls_ca_source == CryptoSource::kAndroid) {
163  backend_->loadTlsCa(&ca);
164  }
165  return ca;
166 }
167 
168 std::string KeyManager::getCN() const {
169  std::string not_found_cert_message = "Certificate is not found, can't extract device_id";
170  std::string cert;
171  if (config_.tls_cert_source == CryptoSource::kFile || config_.tls_cert_source == CryptoSource::kAndroid) {
172  if (!backend_->loadTlsCert(&cert)) {
173  throw std::runtime_error(not_found_cert_message);
174  }
175  } else { // CryptoSource::kPkcs11
176  if (!built_with_p11) {
177  throw std::runtime_error("Aktualizr was built without PKCS#11 support, can't extract device_id");
178  }
179  if (!(*p11_)->readTlsCert(&cert)) {
180  throw std::runtime_error(not_found_cert_message);
181  }
182  }
183 
184  StructGuard<BIO> bio(BIO_new_mem_buf(const_cast<char *>(cert.c_str()), static_cast<int>(cert.size())), BIO_vfree);
185  StructGuard<X509> x(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr), X509_free);
186  if (x == nullptr) {
187  throw std::runtime_error("Could not parse certificate");
188  }
189 
190  int len = X509_NAME_get_text_by_NID(X509_get_subject_name(x.get()), NID_commonName, nullptr, 0);
191  if (len < 0) {
192  throw std::runtime_error("Could not get CN from certificate");
193  }
194  boost::scoped_array<char> buf(new char[len + 1]);
195  X509_NAME_get_text_by_NID(X509_get_subject_name(x.get()), NID_commonName, buf.get(), len + 1);
196  const std::string cn(buf.get());
197  return cn;
198 }
199 
200 void KeyManager::getCertInfo(std::string *subject, std::string *issuer, std::string *not_before,
201  std::string *not_after) const {
202  std::string not_found_cert_message = "Certificate is not found, can't extract device certificate";
203  std::string cert;
204  if (config_.tls_cert_source == CryptoSource::kFile || config_.tls_cert_source == CryptoSource::kAndroid) {
205  if (!backend_->loadTlsCert(&cert)) {
206  throw std::runtime_error(not_found_cert_message);
207  }
208  } else { // CryptoSource::kPkcs11
209  if (!built_with_p11) {
210  throw std::runtime_error("Aktualizr was built without PKCS#11 support, can't extract device certificate");
211  }
212  if (!(*p11_)->readTlsCert(&cert)) {
213  throw std::runtime_error(not_found_cert_message);
214  }
215  }
216 
217  StructGuard<BIO> bio(BIO_new_mem_buf(const_cast<char *>(cert.c_str()), static_cast<int>(cert.size())), BIO_vfree);
218  StructGuard<X509> x(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr), X509_free);
219  if (x == nullptr) {
220  throw std::runtime_error("Could not parse certificate");
221  }
222 
223  StructGuard<BIO> subj_bio(BIO_new(BIO_s_mem()), BIO_vfree);
224  X509_NAME_print_ex(subj_bio.get(), X509_get_subject_name(x.get()), 1, 0);
225  char *subj_buf = nullptr;
226  auto subj_len = BIO_get_mem_data(subj_bio.get(), &subj_buf); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
227  if (subj_buf == nullptr) {
228  throw std::runtime_error("Could not parse certificate subject");
229  }
230  *subject = std::string(subj_buf, static_cast<size_t>(subj_len));
231 
232  StructGuard<BIO> issuer_bio(BIO_new(BIO_s_mem()), BIO_vfree);
233  X509_NAME_print_ex(issuer_bio.get(), X509_get_issuer_name(x.get()), 1, 0);
234  char *issuer_buf = nullptr;
235  auto issuer_len = BIO_get_mem_data(issuer_bio.get(), &issuer_buf); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
236  if (issuer_buf == nullptr) {
237  throw std::runtime_error("Could not parse certificate issuer");
238  }
239  *issuer = std::string(issuer_buf, static_cast<size_t>(issuer_len));
240 
241 #if AKTUALIZR_OPENSSL_PRE_11
242  const ASN1_TIME *nb_asn1 = X509_get_notBefore(x.get());
243 #else
244  const ASN1_TIME *nb_asn1 = X509_get0_notBefore(x.get());
245 #endif
246  StructGuard<BIO> nb_bio(BIO_new(BIO_s_mem()), BIO_vfree);
247  ASN1_TIME_print(nb_bio.get(), nb_asn1);
248  char *nb_buf;
249  auto nb_len = BIO_get_mem_data(nb_bio.get(), &nb_buf); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
250  *not_before = std::string(nb_buf, static_cast<size_t>(nb_len));
251 
252 #if AKTUALIZR_OPENSSL_PRE_11
253  const ASN1_TIME *na_asn1 = X509_get_notAfter(x.get());
254 #else
255  const ASN1_TIME *na_asn1 = X509_get0_notAfter(x.get());
256 #endif
257  StructGuard<BIO> na_bio(BIO_new(BIO_s_mem()), BIO_vfree);
258  ASN1_TIME_print(na_bio.get(), na_asn1);
259  char *na_buf;
260  auto na_len = BIO_get_mem_data(na_bio.get(), &na_buf); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
261  *not_after = std::string(na_buf, static_cast<size_t>(na_len));
262 }
263 
264 void KeyManager::copyCertsToCurl(HttpInterface &http) {
265  std::string pkey = getPkey();
266  std::string cert = getCert();
267  std::string ca = getCa();
268 
269  if ((pkey.size() != 0u) && (cert.size() != 0u) && (ca.size() != 0u)) {
270  http.setCerts(ca, config_.tls_ca_source, cert, config_.tls_cert_source, pkey, config_.tls_pkey_source);
271  }
272 }
273 
274 Json::Value KeyManager::signTuf(const Json::Value &in_data) const {
275  ENGINE *crypto_engine = nullptr;
276  std::string private_key;
277  if (config_.uptane_key_source == CryptoSource::kPkcs11) {
278  if (!built_with_p11) {
279  throw std::runtime_error("Aktualizr was built without PKCS#11");
280  }
281  crypto_engine = (*p11_)->getEngine();
282  private_key = config_.p11.uptane_key_id;
283  }
284 
285  std::string b64sig;
286  if (config_.uptane_key_source == CryptoSource::kAndroid) {
287 #if defined(ANDROID)
288  b64sig = AndroidKeyStore::instance().signData(Utils::jsonToCanonicalStr(in_data));
289 #else
290  throw std::runtime_error("Aktualizr was built without Android support");
291 #endif
292  } else {
293  if (config_.uptane_key_source == CryptoSource::kFile) {
294  backend_->loadPrimaryPrivate(&private_key);
295  }
296  b64sig = Utils::toBase64(
297  Crypto::Sign(config_.uptane_key_type, crypto_engine, private_key, Utils::jsonToCanonicalStr(in_data)));
298  }
299 
300  Json::Value signature;
301  signature["method"] = "rsassa-pss";
302  signature["sig"] = b64sig;
303 
304  Json::Value out_data;
305  signature["keyid"] = UptanePublicKey().KeyId();
306  out_data["signed"] = in_data;
307  out_data["signatures"] = Json::Value(Json::arrayValue);
308  out_data["signatures"].append(signature);
309  return out_data;
310 }
311 
312 std::string KeyManager::generateUptaneKeyPair() {
313  std::string primary_public;
314 
315  if (config_.uptane_key_source == CryptoSource::kFile) {
316  std::string primary_private;
317  if (!backend_->loadPrimaryKeys(&primary_public, &primary_private)) {
318  bool result_ = Crypto::generateKeyPair(config_.uptane_key_type, &primary_public, &primary_private);
319  if (result_) {
320  backend_->storePrimaryKeys(primary_public, primary_private);
321  }
322  }
323  if (primary_public.empty() && primary_private.empty()) {
324  throw std::runtime_error("Could not get uptane keys");
325  }
326  } else if (config_.uptane_key_source == CryptoSource::kAndroid) {
327 #if defined(ANDROID)
328  primary_public = AndroidKeyStore::instance().getPublicKey();
329  if (primary_public.empty()) {
330  primary_public = AndroidKeyStore::instance().generateKeyPair();
331  }
332 #else
333  throw std::runtime_error("Aktualizr was built without Android support");
334 #endif
335  if (primary_public.empty()) {
336  throw std::runtime_error("Could not get uptane keys");
337  }
338  } else {
339  if (!built_with_p11) {
340  throw std::runtime_error("Aktualizr was built without pkcs11 support!");
341  }
342  // dummy read to check if the key is present
343  if (!(*p11_)->readUptanePublicKey(&primary_public)) {
344  (*p11_)->generateUptaneKeyPair();
345  }
346  // really read the key
347  if (primary_public.empty() && !(*p11_)->readUptanePublicKey(&primary_public)) {
348  throw std::runtime_error("Could not get uptane keys");
349  }
350  }
351  return primary_public;
352 }
353 
354 PublicKey KeyManager::UptanePublicKey() const {
355  std::string primary_public;
356  if (config_.uptane_key_source == CryptoSource::kFile) {
357  if (!backend_->loadPrimaryPublic(&primary_public)) {
358  throw std::runtime_error("Could not get uptane public key!");
359  }
360  } else if (config_.uptane_key_source == CryptoSource::kAndroid) {
361 #if defined(ANDROID)
362  primary_public = AndroidKeyStore::instance().getPublicKey();
363 #else
364  throw std::runtime_error("Aktualizr was built without Android support");
365 #endif
366  if (primary_public.empty()) {
367  throw std::runtime_error("Could not get uptane public key!");
368  }
369  } else {
370  if (!built_with_p11) {
371  throw std::runtime_error("Aktualizr was built without pkcs11 support!");
372  }
373  // dummy read to check if the key is present
374  if (!(*p11_)->readUptanePublicKey(&primary_public)) {
375  throw std::runtime_error("Could not get uptane public key!");
376  }
377  }
378  return PublicKey(primary_public, config_.uptane_key_type);
379 }
types.h
HttpInterface
Definition: httpinterface.h:38
PublicKey
Definition: crypto.h:26
KeyManagerConfig
Definition: keymanager_config.h:9