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