Aktualizr
C++ SOTA Client
crypto.cc
1 #include "crypto.h"
2 
3 #include <array>
4 #include <iostream>
5 #include <random>
6 
7 #include <sodium.h>
8 #include <boost/algorithm/hex.hpp>
9 #include <boost/scoped_array.hpp>
10 
11 #include "libaktualizr/types.h"
12 #include "logging/logging.h"
13 #include "openssl_compat.h"
14 #include "utilities/utils.h"
15 
16 PublicKey::PublicKey(const boost::filesystem::path &path) : value_(Utils::readFile(path)) {
17  type_ = Crypto::IdentifyRSAKeyType(value_);
18 }
19 
20 PublicKey::PublicKey(const Json::Value &uptane_json) {
21  std::string keytype;
22  std::string keyvalue;
23 
24  try {
25  if (!uptane_json["keytype"].isString()) {
26  type_ = KeyType::kUnknown;
27  return;
28  }
29  if (!uptane_json["keyval"].isObject()) {
30  type_ = KeyType::kUnknown;
31  return;
32  }
33 
34  if (!uptane_json["keyval"]["public"].isString()) {
35  type_ = KeyType::kUnknown;
36  return;
37  }
38 
39  keytype = uptane_json["keytype"].asString();
40  keyvalue = uptane_json["keyval"]["public"].asString();
41  } catch (const std::exception &ex) {
42  LOG_ERROR << "Failed to initialize public key: " << ex.what();
43  type_ = KeyType::kUnknown;
44  return;
45  }
46 
47  std::transform(keytype.begin(), keytype.end(), keytype.begin(), ::tolower);
48 
49  KeyType type;
50  if (keytype == "ed25519") {
51  type = KeyType::kED25519;
52  } else if (keytype == "rsa") {
53  type = Crypto::IdentifyRSAKeyType(keyvalue);
54  if (type == KeyType::kUnknown) {
55  LOG_WARNING << "Couldn't identify length of RSA key";
56  }
57  } else {
58  type = KeyType::kUnknown;
59  }
60  type_ = type;
61  value_ = keyvalue;
62 }
63 
64 PublicKey::PublicKey(const std::string &value, KeyType type) : value_(value), type_(type) {
65  if (Crypto::IsRsaKeyType(type)) {
66  if (type != Crypto::IdentifyRSAKeyType(value)) {
67  throw std::logic_error("RSA key length is incorrect");
68  }
69  }
70 }
71 
72 bool PublicKey::VerifySignature(const std::string &signature, const std::string &message) const {
73  switch (type_) {
74  case KeyType::kED25519:
75  return Crypto::ED25519Verify(boost::algorithm::unhex(value_), Utils::fromBase64(signature), message);
76  case KeyType::kRSA2048:
77  case KeyType::kRSA3072:
78  case KeyType::kRSA4096:
79  return Crypto::RSAPSSVerify(value_, Utils::fromBase64(signature), message);
80  default:
81  return false;
82  }
83 }
84 
85 bool PublicKey::operator==(const PublicKey &rhs) const { return value_ == rhs.value_ && type_ == rhs.type_; }
86 Json::Value PublicKey::ToUptane() const {
87  Json::Value res;
88  switch (type_) {
89  case KeyType::kRSA2048:
90  case KeyType::kRSA3072:
91  case KeyType::kRSA4096:
92  res["keytype"] = "RSA";
93  break;
94  case KeyType::kED25519:
95  res["keytype"] = "ED25519";
96  break;
97  case KeyType::kUnknown:
98  res["keytype"] = "unknown";
99  break;
100  default:
101  throw std::range_error("Unknown key type in PublicKey::ToUptane");
102  }
103  res["keyval"]["public"] = value_;
104  return res;
105 }
106 
107 std::string PublicKey::KeyId() const {
108  std::string key_content = value_;
109  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
110  boost::algorithm::trim_right_if(key_content, boost::algorithm::is_any_of("\n"));
111  std::string keyid = boost::algorithm::hex(Crypto::sha256digest(Utils::jsonToCanonicalStr(Json::Value(key_content))));
112  std::transform(keyid.begin(), keyid.end(), keyid.begin(), ::tolower);
113  return keyid;
114 }
115 
116 std::string Crypto::sha256digest(const std::string &text) {
117  std::array<unsigned char, crypto_hash_sha256_BYTES> sha256_hash{};
118  crypto_hash_sha256(sha256_hash.data(), reinterpret_cast<const unsigned char *>(text.c_str()), text.size());
119  return std::string(reinterpret_cast<char *>(sha256_hash.data()), crypto_hash_sha256_BYTES);
120 }
121 
122 std::string Crypto::sha512digest(const std::string &text) {
123  std::array<unsigned char, crypto_hash_sha512_BYTES> sha512_hash{};
124  crypto_hash_sha512(sha512_hash.data(), reinterpret_cast<const unsigned char *>(text.c_str()), text.size());
125  return std::string(reinterpret_cast<char *>(sha512_hash.data()), crypto_hash_sha512_BYTES);
126 }
127 
128 std::string Crypto::RSAPSSSign(ENGINE *engine, const std::string &private_key, const std::string &message) {
129  StructGuard<EVP_PKEY> key(nullptr, EVP_PKEY_free);
130  StructGuard<RSA> rsa(nullptr, RSA_free);
131  if (engine != nullptr) {
132  // TODO(OTA-2138): this call leaks memory somehow...
133  key.reset(ENGINE_load_private_key(engine, private_key.c_str(), nullptr, nullptr));
134 
135  if (key == nullptr) {
136  LOG_ERROR << "ENGINE_load_private_key failed with error " << ERR_error_string(ERR_get_error(), nullptr);
137  return std::string();
138  }
139 
140  rsa.reset(EVP_PKEY_get1_RSA(key.get()));
141  if (rsa == nullptr) {
142  LOG_ERROR << "EVP_PKEY_get1_RSA failed with error " << ERR_error_string(ERR_get_error(), nullptr);
143  return std::string();
144  }
145  } else {
146  StructGuard<BIO> bio(BIO_new_mem_buf(const_cast<char *>(private_key.c_str()), static_cast<int>(private_key.size())),
147  BIO_vfree);
148  key.reset(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
149  if (key != nullptr) {
150  rsa.reset(EVP_PKEY_get1_RSA(key.get()));
151  }
152 
153  if (rsa == nullptr) {
154  LOG_ERROR << "PEM_read_bio_PrivateKey failed with error " << ERR_error_string(ERR_get_error(), nullptr);
155  return std::string();
156  }
157 
158 #if AKTUALIZR_OPENSSL_PRE_11
159  RSA_set_method(rsa.get(), RSA_PKCS1_SSLeay());
160 #else
161  RSA_set_method(rsa.get(), RSA_PKCS1_OpenSSL());
162 #endif
163  }
164 
165  const auto sign_size = static_cast<unsigned int>(RSA_size(rsa.get()));
166  boost::scoped_array<unsigned char> EM(new unsigned char[sign_size]);
167  boost::scoped_array<unsigned char> pSignature(new unsigned char[sign_size]);
168 
169  std::string digest = Crypto::sha256digest(message);
170  int status = RSA_padding_add_PKCS1_PSS(rsa.get(), EM.get(), reinterpret_cast<const unsigned char *>(digest.c_str()),
171  EVP_sha256(), -1 /* maximum salt length*/);
172  if (status == 0) {
173  LOG_ERROR << "RSA_padding_add_PKCS1_PSS failed with error " << ERR_error_string(ERR_get_error(), nullptr);
174  return std::string();
175  }
176 
177  /* perform digital signature */
178  status = RSA_private_encrypt(RSA_size(rsa.get()), EM.get(), pSignature.get(), rsa.get(), RSA_NO_PADDING);
179  if (status == -1) {
180  LOG_ERROR << "RSA_private_encrypt failed with error " << ERR_error_string(ERR_get_error(), nullptr);
181  return std::string();
182  }
183  std::string retval = std::string(reinterpret_cast<char *>(pSignature.get()), sign_size);
184  return retval;
185 }
186 
187 std::string Crypto::Sign(KeyType key_type, ENGINE *engine, const std::string &private_key, const std::string &message) {
188  if (key_type == KeyType::kED25519) {
189  return Crypto::ED25519Sign(boost::algorithm::unhex(private_key), message);
190  }
191  return Crypto::RSAPSSSign(engine, private_key, message);
192 }
193 
194 std::string Crypto::ED25519Sign(const std::string &private_key, const std::string &message) {
195  std::array<unsigned char, crypto_sign_BYTES> sig{};
196  crypto_sign_detached(sig.data(), nullptr, reinterpret_cast<const unsigned char *>(message.c_str()), message.size(),
197  reinterpret_cast<const unsigned char *>(private_key.c_str()));
198  return std::string(reinterpret_cast<char *>(sig.data()), crypto_sign_BYTES);
199 }
200 
201 bool Crypto::RSAPSSVerify(const std::string &public_key, const std::string &signature, const std::string &message) {
202  StructGuard<RSA> rsa(nullptr, RSA_free);
203  StructGuard<BIO> bio(BIO_new_mem_buf(const_cast<char *>(public_key.c_str()), static_cast<int>(public_key.size())),
204  BIO_vfree);
205  {
206  RSA *r = nullptr;
207  if (PEM_read_bio_RSA_PUBKEY(bio.get(), &r, nullptr, nullptr) == nullptr) {
208  LOG_ERROR << "PEM_read_bio_RSA_PUBKEY failed with error " << ERR_error_string(ERR_get_error(), nullptr);
209  return false;
210  }
211  rsa.reset(r);
212  }
213 
214 #if AKTUALIZR_OPENSSL_PRE_11
215  RSA_set_method(rsa.get(), RSA_PKCS1_SSLeay());
216 #else
217  RSA_set_method(rsa.get(), RSA_PKCS1_OpenSSL());
218 #endif
219 
220  const auto size = static_cast<unsigned int>(RSA_size(rsa.get()));
221  boost::scoped_array<unsigned char> pDecrypted(new unsigned char[size]);
222  /* now we will verify the signature
223  Start by a RAW decrypt of the signature
224  */
225  int status =
226  RSA_public_decrypt(static_cast<int>(signature.size()), reinterpret_cast<const unsigned char *>(signature.c_str()),
227  pDecrypted.get(), rsa.get(), RSA_NO_PADDING);
228  if (status == -1) {
229  LOG_ERROR << "RSA_public_decrypt failed with error " << ERR_error_string(ERR_get_error(), nullptr);
230  return false;
231  }
232 
233  std::string digest = Crypto::sha256digest(message);
234 
235  /* verify the data */
236  status = RSA_verify_PKCS1_PSS(rsa.get(), reinterpret_cast<const unsigned char *>(digest.c_str()), EVP_sha256(),
237  pDecrypted.get(), -2 /* salt length recovered from signature*/);
238 
239  return status == 1;
240 }
241 bool Crypto::ED25519Verify(const std::string &public_key, const std::string &signature, const std::string &message) {
242  if (public_key.size() < crypto_sign_PUBLICKEYBYTES || signature.size() < crypto_sign_BYTES) {
243  return false;
244  }
245  return crypto_sign_verify_detached(reinterpret_cast<const unsigned char *>(signature.c_str()),
246  reinterpret_cast<const unsigned char *>(message.c_str()), message.size(),
247  reinterpret_cast<const unsigned char *>(public_key.c_str())) == 0;
248 }
249 
250 bool Crypto::parseP12(BIO *p12_bio, const std::string &p12_password, std::string *out_pkey, std::string *out_cert,
251  std::string *out_ca) {
252 #if AKTUALIZR_OPENSSL_PRE_11
253  SSLeay_add_all_algorithms();
254 #endif
255  StructGuard<PKCS12> p12(d2i_PKCS12_bio(p12_bio, nullptr), PKCS12_free);
256  if (p12 == nullptr) {
257  LOG_ERROR << "Could not read from " << p12_bio << " file pointer";
258  return false;
259  }
260 
261  // use a lambda here because sk_X509_pop_free is a macro
262  auto stackx509_free = [](STACK_OF(X509) * stack) {
263  sk_X509_pop_free(stack, X509_free); // NOLINT
264  };
265 
266  StructGuard<EVP_PKEY> pkey(nullptr, EVP_PKEY_free);
267  StructGuard<X509> x509_cert(nullptr, X509_free);
268  StructGuard<STACK_OF(X509)> ca_certs(nullptr, stackx509_free);
269  {
270  EVP_PKEY *pk;
271  X509 *x509c = nullptr;
272  STACK_OF(X509) *cacs = nullptr;
273  if (PKCS12_parse(p12.get(), p12_password.c_str(), &pk, &x509c, &cacs) == 0) {
274  LOG_ERROR << "Could not parse file from " << p12_bio << " source pointer";
275  return false;
276  }
277  pkey.reset(pk);
278  x509_cert.reset(x509c);
279  ca_certs.reset(cacs);
280  }
281 
282  StructGuard<BIO> pkey_pem_sink(BIO_new(BIO_s_mem()), BIO_vfree);
283  if (pkey_pem_sink == nullptr) {
284  LOG_ERROR << "Could not open pkey buffer for writing";
285  return false;
286  }
287  PEM_write_bio_PrivateKey(pkey_pem_sink.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr);
288 
289  char *pkey_buf;
290  auto pkey_len = BIO_get_mem_data(pkey_pem_sink.get(), &pkey_buf); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
291  *out_pkey = std::string(pkey_buf, static_cast<size_t>(pkey_len));
292 
293  char *cert_buf;
294  size_t cert_len;
295  StructGuard<BIO> cert_sink(BIO_new(BIO_s_mem()), BIO_vfree);
296  if (cert_sink == nullptr) {
297  LOG_ERROR << "Could not open certificate buffer for writing";
298  return false;
299  }
300  PEM_write_bio_X509(cert_sink.get(), x509_cert.get());
301 
302  char *ca_buf;
303  size_t ca_len;
304  StructGuard<BIO> ca_sink(BIO_new(BIO_s_mem()), BIO_vfree);
305  if (ca_sink == nullptr) {
306  LOG_ERROR << "Could not open ca buffer for writing";
307  return false;
308  }
309  X509 *ca_cert = nullptr;
310  for (int i = 0; i < sk_X509_num(ca_certs.get()); i++) { // NOLINT
311  ca_cert = sk_X509_value(ca_certs.get(), i); // NOLINT
312  PEM_write_bio_X509(ca_sink.get(), ca_cert);
313  PEM_write_bio_X509(cert_sink.get(), ca_cert);
314  }
315  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
316  ca_len = static_cast<size_t>(BIO_get_mem_data(ca_sink.get(), &ca_buf));
317  *out_ca = std::string(ca_buf, ca_len);
318 
319  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
320  cert_len = static_cast<size_t>(BIO_get_mem_data(cert_sink.get(), &cert_buf));
321  *out_cert = std::string(cert_buf, cert_len);
322 
323  return true;
324 }
325 
326 std::string Crypto::extractSubjectCN(const std::string &cert) {
327  StructGuard<BIO> bio(BIO_new_mem_buf(const_cast<char *>(cert.c_str()), static_cast<int>(cert.size())), BIO_vfree);
328  StructGuard<X509> x(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr), X509_free);
329  if (x == nullptr) {
330  throw std::runtime_error("Could not parse certificate");
331  }
332 
333  int len = X509_NAME_get_text_by_NID(X509_get_subject_name(x.get()), NID_commonName, nullptr, 0);
334  if (len < 0) {
335  throw std::runtime_error("Could not get CN from certificate");
336  }
337  boost::scoped_array<char> buf(new char[len + 1]);
338  X509_NAME_get_text_by_NID(X509_get_subject_name(x.get()), NID_commonName, buf.get(), len + 1);
339  return std::string(buf.get());
340 }
341 
342 StructGuard<EVP_PKEY> Crypto::generateRSAKeyPairEVP(KeyType key_type) {
343  int bits;
344  switch (key_type) {
345  case KeyType::kRSA2048:
346  bits = 2048;
347  break;
348  case KeyType::kRSA3072:
349  bits = 3072;
350  break;
351  case KeyType::kRSA4096:
352  bits = 4096;
353  break;
354  default:
355  return {nullptr, EVP_PKEY_free};
356  }
357 
358  return Crypto::generateRSAKeyPairEVP(bits);
359 }
360 
361 StructGuard<EVP_PKEY> Crypto::generateRSAKeyPairEVP(const int bits) {
362  if (bits < 31) { // sic!
363  throw std::runtime_error("RSA key size can't be smaller than 31 bits");
364  }
365 
366  int ret = RAND_status();
367  if (ret != 1) { /* random generator has NOT been seeded with enough data */
368  ret = RAND_poll();
369  if (ret != 1) { /* seed data was NOT generated */
370  throw std::runtime_error("Random generator has not been sufficiently seeded.");
371  }
372  }
373 
374  /* exponent - RSA_F4 is defined as 0x10001L */
375  StructGuard<BIGNUM> bne(BN_new(), BN_free);
376  if (BN_set_word(bne.get(), RSA_F4) != 1) {
377  throw std::runtime_error(std::string("BN_set_word failed: ") + ERR_error_string(ERR_get_error(), nullptr));
378  }
379 
380  StructGuard<RSA> rsa(RSA_new(), RSA_free);
381  if (RSA_generate_key_ex(rsa.get(), bits, bne.get(), nullptr) != 1) {
382  throw std::runtime_error(std::string("RSA_generate_key_ex failed: ") + ERR_error_string(ERR_get_error(), nullptr));
383  }
384 
385  StructGuard<EVP_PKEY> pkey(EVP_PKEY_new(), EVP_PKEY_free);
386  if (pkey.get() == nullptr) {
387  throw std::runtime_error(std::string("EVP_PKEY_new failed: ") + ERR_error_string(ERR_get_error(), nullptr));
388  }
389 
390  // release the rsa pointer here, pkey is the new owner
391  if (!EVP_PKEY_assign_RSA(pkey.get(), rsa.release())) { // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
392  throw std::runtime_error(std::string("EVP_PKEY_assign_RSA failed: ") + ERR_error_string(ERR_get_error(), nullptr));
393  }
394  return pkey;
395 }
396 
397 /**
398  * Generate a RSA keypair
399  * @param key_type Algorithm used to generate the key
400  * @param public_key Generated public part of key
401  * @param private_key Generated private part of key
402  * @return true if the keys are present at the end of this function (either they were created or existed already)
403  * false if key generation failed
404  */
405 bool Crypto::generateRSAKeyPair(KeyType key_type, std::string *public_key, std::string *private_key) {
406  int ret = 0;
407  StructGuard<EVP_PKEY> pkey = generateRSAKeyPairEVP(key_type);
408  if (pkey == nullptr) {
409  return false;
410  }
411 
412  char *pubkey_buf;
413  StructGuard<BIO> pubkey_sink(BIO_new(BIO_s_mem()), BIO_vfree);
414  if (pubkey_sink == nullptr) {
415  return false;
416  }
417  ret = PEM_write_bio_PUBKEY(pubkey_sink.get(), pkey.get());
418  if (ret != 1) {
419  return false;
420  }
421  auto pubkey_len = BIO_get_mem_data(pubkey_sink.get(), &pubkey_buf); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
422  *public_key = std::string(pubkey_buf, static_cast<size_t>(pubkey_len));
423 
424  char *privkey_buf;
425  StructGuard<BIO> privkey_sink(BIO_new(BIO_s_mem()), BIO_vfree);
426  if (privkey_sink == nullptr) {
427  return false;
428  }
429 
430  ret = PEM_write_bio_RSAPrivateKey(privkey_sink.get(), static_cast<RSA *>(EVP_PKEY_get0(pkey.get())), nullptr, nullptr,
431  0, nullptr, nullptr);
432  if (ret != 1) {
433  return false;
434  }
435  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
436  auto privkey_len = BIO_get_mem_data(privkey_sink.get(), &privkey_buf);
437  *private_key = std::string(privkey_buf, static_cast<size_t>(privkey_len));
438  return true;
439 }
440 
441 bool Crypto::generateEDKeyPair(std::string *public_key, std::string *private_key) {
442  std::array<unsigned char, crypto_sign_PUBLICKEYBYTES> pk{};
443  std::array<unsigned char, crypto_sign_SECRETKEYBYTES> sk{};
444  crypto_sign_keypair(pk.data(), sk.data());
445  *public_key = boost::algorithm::hex(std::string(reinterpret_cast<char *>(pk.data()), crypto_sign_PUBLICKEYBYTES));
446  // std::transform(public_key->begin(), public_key->end(), public_key->begin(), ::tolower);
447  *private_key = boost::algorithm::hex(std::string(reinterpret_cast<char *>(sk.data()), crypto_sign_SECRETKEYBYTES));
448  // std::transform(private_key->begin(), private_key->end(), private_key->begin(), ::tolower);
449  return true;
450 }
451 
452 bool Crypto::generateKeyPair(KeyType key_type, std::string *public_key, std::string *private_key) {
453  if (key_type == KeyType::kED25519) {
454  return Crypto::generateEDKeyPair(public_key, private_key);
455  }
456  return Crypto::generateRSAKeyPair(key_type, public_key, private_key);
457 }
458 
459 bool Crypto::IsRsaKeyType(KeyType type) {
460  switch (type) {
461  case KeyType::kRSA2048:
462  case KeyType::kRSA3072:
463  case KeyType::kRSA4096:
464  return true;
465  default:
466  return false;
467  }
468 }
469 
470 KeyType Crypto::IdentifyRSAKeyType(const std::string &public_key_pem) {
471  StructGuard<BIO> bufio(BIO_new_mem_buf(reinterpret_cast<const void *>(public_key_pem.c_str()),
472  static_cast<int>(public_key_pem.length())),
473  BIO_vfree);
474  if (bufio.get() == nullptr) {
475  throw std::runtime_error("BIO_new_mem_buf failed");
476  }
477  StructGuard<::RSA> rsa(PEM_read_bio_RSA_PUBKEY(bufio.get(), nullptr, nullptr, nullptr), RSA_free);
478 
479  if (rsa.get() == nullptr) {
480  return KeyType::kUnknown;
481  }
482 
483  int key_length = RSA_size(rsa.get()) * 8;
484  // It is not clear from the OpenSSL documentation if RSA_size returns
485  // exactly 2048 or 4096, or if this can vary. For now we will assume that if
486  // OpenSSL has been asked to generate a 'N bit' key, RSA_size() will return
487  // exactly N
488  switch (key_length) {
489  case 2048:
490  return KeyType::kRSA2048;
491  case 3072:
492  return KeyType::kRSA3072;
493  case 4096:
494  return KeyType::kRSA4096;
495  default:
496  LOG_WARNING << "Weird key length:" << key_length;
497  return KeyType::kUnknown;
498  }
499 }
500 
501 StructGuard<X509> Crypto::generateCert(const int rsa_bits, const int cert_days, const std::string &cert_c,
502  const std::string &cert_st, const std::string &cert_o,
503  const std::string &cert_cn, bool self_sign) {
504  // create certificate
505  StructGuard<X509> certificate(X509_new(), X509_free);
506  if (certificate.get() == nullptr) {
507  throw std::runtime_error(std::string("X509_new failed: ") + ERR_error_string(ERR_get_error(), nullptr));
508  }
509 
510  X509_set_version(certificate.get(), 2); // X509v3
511 
512  {
513  std::random_device urandom;
514  std::uniform_int_distribution<> serial_dist(0, (1UL << 20) - 1);
515  ASN1_INTEGER_set(X509_get_serialNumber(certificate.get()), serial_dist(urandom));
516  }
517 
518  // create and set certificate subject name
519  StructGuard<X509_NAME> subj(X509_NAME_new(), X509_NAME_free);
520  if (subj.get() == nullptr) {
521  throw std::runtime_error(std::string("X509_NAME_new failed: ") + ERR_error_string(ERR_get_error(), nullptr));
522  }
523 
524  if (!cert_c.empty()) {
525  if (X509_NAME_add_entry_by_txt(subj.get(), "C", MBSTRING_ASC,
526  reinterpret_cast<const unsigned char *>(cert_c.c_str()), -1, -1, 0) == 0) {
527  throw std::runtime_error(std::string("X509_NAME_add_entry_by_txt failed: ") +
528  ERR_error_string(ERR_get_error(), nullptr));
529  }
530  }
531 
532  if (!cert_st.empty()) {
533  if (X509_NAME_add_entry_by_txt(subj.get(), "ST", MBSTRING_ASC,
534  reinterpret_cast<const unsigned char *>(cert_st.c_str()), -1, -1, 0) == 0) {
535  throw std::runtime_error(std::string("X509_NAME_add_entry_by_txt failed: ") +
536  ERR_error_string(ERR_get_error(), nullptr));
537  }
538  }
539 
540  if (!cert_o.empty()) {
541  if (X509_NAME_add_entry_by_txt(subj.get(), "O", MBSTRING_ASC,
542  reinterpret_cast<const unsigned char *>(cert_o.c_str()), -1, -1, 0) == 0) {
543  throw std::runtime_error(std::string("X509_NAME_add_entry_by_txt failed: ") +
544  ERR_error_string(ERR_get_error(), nullptr));
545  }
546  }
547 
548  assert(!cert_cn.empty());
549  if (X509_NAME_add_entry_by_txt(subj.get(), "CN", MBSTRING_ASC,
550  reinterpret_cast<const unsigned char *>(cert_cn.c_str()), -1, -1, 0) == 0) {
551  throw std::runtime_error(std::string("X509_NAME_add_entry_by_txt failed: ") +
552  ERR_error_string(ERR_get_error(), nullptr));
553  }
554 
555  if (X509_set_subject_name(certificate.get(), subj.get()) == 0) {
556  throw std::runtime_error(std::string("X509_set_subject_name failed: ") +
557  ERR_error_string(ERR_get_error(), nullptr));
558  }
559 
560  // create and set key.
561  StructGuard<EVP_PKEY> certificate_pkey(Crypto::generateRSAKeyPairEVP(rsa_bits));
562 
563  if (X509_set_pubkey(certificate.get(), certificate_pkey.get()) == 0) {
564  throw std::runtime_error(std::string("X509_set_pubkey failed: ") + ERR_error_string(ERR_get_error(), nullptr));
565  }
566 
567  // set validity period
568  if (X509_gmtime_adj(X509_get_notBefore(certificate.get()), 0) == nullptr) {
569  throw std::runtime_error(std::string("X509_gmtime_adj failed: ") + ERR_error_string(ERR_get_error(), nullptr));
570  }
571 
572  if (X509_gmtime_adj(X509_get_notAfter(certificate.get()), 60L * 60L * 24L * cert_days) == nullptr) {
573  throw std::runtime_error(std::string("X509_gmtime_adj failed: ") + ERR_error_string(ERR_get_error(), nullptr));
574  }
575 
576  // self-sign
577  if (self_sign) {
578  const EVP_MD *cert_digest = EVP_sha256();
579  if (X509_sign(certificate.get(), certificate_pkey.get(), cert_digest) == 0) {
580  throw std::runtime_error(std::string("X509_sign failed: ") + ERR_error_string(ERR_get_error(), nullptr));
581  }
582  LOG_INFO << "Successfully self-signed the generated certificate. This should not be used in production!";
583  }
584 
585  return certificate;
586 }
587 
588 void Crypto::signCert(const std::string &cacert_path, const std::string &capkey_path, X509 *const certificate) {
589  // read CA certificate
590  std::string cacert_contents = Utils::readFile(cacert_path);
591  StructGuard<BIO> bio_in_cacert(BIO_new_mem_buf(cacert_contents.c_str(), static_cast<int>(cacert_contents.size())),
592  BIO_free_all);
593  StructGuard<X509> ca_certificate(PEM_read_bio_X509(bio_in_cacert.get(), nullptr, nullptr, nullptr), X509_free);
594  if (ca_certificate.get() == nullptr) {
595  throw std::runtime_error(std::string("Reading CA certificate failed: ") +
596  ERR_error_string(ERR_get_error(), nullptr));
597  }
598 
599  // read CA private key
600  std::string capkey_contents = Utils::readFile(capkey_path);
601  StructGuard<BIO> bio_in_capkey(BIO_new_mem_buf(capkey_contents.c_str(), static_cast<int>(capkey_contents.size())),
602  BIO_free_all);
603  StructGuard<EVP_PKEY> ca_privkey(PEM_read_bio_PrivateKey(bio_in_capkey.get(), nullptr, nullptr, nullptr),
604  EVP_PKEY_free);
605  if (ca_privkey.get() == nullptr) {
606  throw std::runtime_error(std::string("PEM_read_bio_PrivateKey failed: ") +
607  ERR_error_string(ERR_get_error(), nullptr));
608  }
609 
610  // set issuer name
611  X509_NAME *ca_subj = X509_get_subject_name(ca_certificate.get());
612  if (ca_subj == nullptr) {
613  throw std::runtime_error(std::string("X509_get_subject_name failed: ") +
614  ERR_error_string(ERR_get_error(), nullptr));
615  }
616 
617  if (X509_set_issuer_name(certificate, ca_subj) == 0) {
618  throw std::runtime_error(std::string("X509_set_issuer_name failed: ") + ERR_error_string(ERR_get_error(), nullptr));
619  }
620 
621  // sign
622  const EVP_MD *cert_digest = EVP_sha256();
623  if (X509_sign(certificate, ca_privkey.get(), cert_digest) == 0) {
624  throw std::runtime_error(std::string("X509_sign failed: ") + ERR_error_string(ERR_get_error(), nullptr));
625  }
626 }
627 
628 void Crypto::serializeCert(std::string *pkey, std::string *cert, X509 *const certificate) {
629  // serialize private key
630  char *privkey_buf;
631  StructGuard<BIO> privkey_file(BIO_new(BIO_s_mem()), BIO_vfree);
632  if (privkey_file == nullptr) {
633  throw std::runtime_error(std::string("BIO_new failed: ") + ERR_error_string(ERR_get_error(), nullptr));
634  }
635 
636  StructGuard<EVP_PKEY> certificate_pkey(X509_get_pubkey(certificate), EVP_PKEY_free);
637  if (certificate_pkey == nullptr) {
638  throw std::runtime_error(std::string("X509_get_pubkey failed: ") + ERR_error_string(ERR_get_error(), nullptr));
639  }
640 
641  StructGuard<RSA> certificate_rsa(EVP_PKEY_get1_RSA(certificate_pkey.get()), RSA_free);
642  if (certificate_rsa == nullptr) {
643  throw std::runtime_error(std::string("EVP_PKEY_get1_RSA failed: ") + ERR_error_string(ERR_get_error(), nullptr));
644  }
645 
646  int ret =
647  PEM_write_bio_RSAPrivateKey(privkey_file.get(), certificate_rsa.get(), nullptr, nullptr, 0, nullptr, nullptr);
648  if (ret == 0) {
649  throw std::runtime_error(std::string("PEM_write_RSAPrivateKey failed: ") +
650  ERR_error_string(ERR_get_error(), nullptr));
651  }
652  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
653  auto privkey_len = BIO_get_mem_data(privkey_file.get(), &privkey_buf);
654  *pkey = std::string(privkey_buf, static_cast<size_t>(privkey_len));
655 
656  // serialize certificate
657  char *cert_buf;
658  StructGuard<BIO> cert_file(BIO_new(BIO_s_mem()), BIO_vfree);
659  if (cert_file == nullptr) {
660  throw std::runtime_error(std::string("BIO_new failed: ") + ERR_error_string(ERR_get_error(), nullptr));
661  }
662  ret = PEM_write_bio_X509(cert_file.get(), certificate);
663  if (ret == 0) {
664  throw std::runtime_error(std::string("PEM_write_bio_X509 failed: ") + ERR_error_string(ERR_get_error(), nullptr));
665  }
666  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
667  auto cert_len = BIO_get_mem_data(cert_file.get(), &cert_buf);
668  *cert = std::string(cert_buf, static_cast<size_t>(cert_len));
669 }
670 
671 MultiPartHasher::Ptr MultiPartHasher::create(Hash::Type hash_type) {
672  switch (hash_type) {
673  case Hash::Type::kSha256: {
674  return std::make_shared<MultiPartSHA256Hasher>();
675  }
676  case Hash::Type::kSha512: {
677  return std::make_shared<MultiPartSHA512Hasher>();
678  }
679  default: {
680  LOG_ERROR << "Unsupported type of hashing: " << Hash::TypeString(hash_type);
681  return nullptr;
682  }
683  }
684 }
685 
686 Hash Hash::generate(Type type, const std::string &data) {
687  std::string hash;
688 
689  switch (type) {
690  case Type::kSha256: {
691  hash = boost::algorithm::hex(Crypto::sha256digest(data));
692  break;
693  }
694  case Type::kSha512: {
695  hash = boost::algorithm::hex(Crypto::sha512digest(data));
696  break;
697  }
698  default: {
699  throw std::invalid_argument("Unsupported hash type");
700  }
701  }
702 
703  return Hash(type, hash);
704 }
705 
706 Hash::Hash(const std::string &type, const std::string &hash) : hash_(boost::algorithm::to_upper_copy(hash)) {
707  if (type == "sha512") {
708  type_ = Hash::Type::kSha512;
709  } else if (type == "sha256") {
710  type_ = Hash::Type::kSha256;
711  } else {
712  type_ = Hash::Type::kUnknownAlgorithm;
713  }
714 }
715 
716 Hash::Hash(Type type, const std::string &hash) : type_(type), hash_(boost::algorithm::to_upper_copy(hash)) {}
717 
718 bool Hash::operator==(const Hash &other) const { return type_ == other.type_ && hash_ == other.hash_; }
719 
720 std::string Hash::TypeString(Type type) {
721  switch (type) {
722  case Type::kSha256:
723  return "sha256";
724  case Type::kSha512:
725  return "sha512";
726  default:
727  return "unknown";
728  }
729 }
730 
731 std::string Hash::TypeString() const { return TypeString(type_); }
732 
733 Hash::Type Hash::type() const { return type_; }
734 
735 std::ostream &operator<<(std::ostream &os, const Hash &h) {
736  os << "Hash: " << h.hash_;
737  return os;
738 }
Hash
The Hash class The hash of a file or Uptane metadata.
Definition: types.h:159
types.h
PublicKey::ToUptane
Json::Value ToUptane() const
Uptane Json representation of this public key.
Definition: crypto.cc:86
data
General data structures.
Definition: types.h:217
Utils
Definition: utils.h:13
PublicKey
Definition: types.h:119
Crypto::generateRSAKeyPair
static bool generateRSAKeyPair(KeyType key_type, std::string *public_key, std::string *private_key)
Generate a RSA keypair.
Definition: crypto.cc:405
PublicKey::VerifySignature
bool VerifySignature(const std::string &signature, const std::string &message) const
Verify a signature using this public key.
Definition: crypto.cc:72