Aktualizr
C++ SOTA Client
crypto.cc
1 #include "crypto.h"
2 
3 #include <boost/algorithm/hex.hpp>
4 #include <boost/scoped_array.hpp>
5 #include <iostream>
6 
7 #include <sodium.h>
8 
9 #include "logging/logging.h"
10 #include "openssl_compat.h"
11 #include "utilities/utils.h"
12 
13 PublicKey::PublicKey(const boost::filesystem::path &path) : value_(Utils::readFile(path)) {
14  type_ = Crypto::IdentifyRSAKeyType(value_);
15 }
16 PublicKey::PublicKey(Json::Value uptane_json) {
17  if (!uptane_json["keytype"].isString()) {
18  type_ = KeyType::kUnknown;
19  return;
20  }
21  if (!uptane_json["keyval"].isObject()) {
22  type_ = KeyType::kUnknown;
23  return;
24  }
25 
26  if (!uptane_json["keyval"]["public"].isString()) {
27  type_ = KeyType::kUnknown;
28  return;
29  }
30 
31  std::string keytype = uptane_json["keytype"].asString();
32  std::string keyvalue = uptane_json["keyval"]["public"].asString();
33 
34  std::transform(keytype.begin(), keytype.end(), keytype.begin(), ::tolower);
35 
36  KeyType type;
37  if (keytype == "ed25519") {
38  type = KeyType::kED25519;
39  } else if (keytype == "rsa") {
40  type = Crypto::IdentifyRSAKeyType(keyvalue);
41  if (type == KeyType::kUnknown) {
42  LOG_WARNING << "Couldn't identify length of RSA key";
43  }
44  } else {
45  type = KeyType::kUnknown;
46  }
47  type_ = type;
48  value_ = keyvalue;
49 }
50 PublicKey::PublicKey(std::string value, KeyType type) : value_(std::move(value)), type_(type) {
51  if (Crypto::IsRsaKeyType(type)) {
52  if (type != Crypto::IdentifyRSAKeyType(value)) {
53  std::logic_error("RSA key length is incorrect");
54  }
55  }
56 }
57 
58 bool PublicKey::VerifySignature(const std::string &signature, const std::string &message) const {
59  switch (type_) {
60  case KeyType::kED25519:
61  return Crypto::ED25519Verify(boost::algorithm::unhex(value_), Utils::fromBase64(signature), message);
62  case KeyType::kRSA2048:
63  case KeyType::kRSA3072:
64  case KeyType::kRSA4096:
65  return Crypto::RSAPSSVerify(value_, Utils::fromBase64(signature), message);
66  default:
67  return false;
68  }
69 }
70 
71 bool PublicKey::operator==(const PublicKey &rhs) const { return value_ == rhs.value_ && type_ == rhs.type_; }
72 Json::Value PublicKey::ToUptane() const {
73  Json::Value res;
74  switch (type_) {
75  case KeyType::kRSA2048:
76  case KeyType::kRSA3072:
77  case KeyType::kRSA4096:
78  res["keytype"] = "RSA";
79  break;
80  case KeyType::kED25519:
81  res["keytype"] = "ED25519";
82  break;
83  case KeyType::kUnknown:
84  res["keytype"] = "unknown";
85  break;
86  default:
87  throw new std::range_error("Unknown key type in PublicKey::ToUptane");
88  }
89  res["keyval"]["public"] = value_;
90  return res;
91 }
92 
93 std::string PublicKey::KeyId() const {
94  std::string key_content = value_;
95  boost::algorithm::trim_right_if(key_content, boost::algorithm::is_any_of("\n"));
96  std::string keyid = boost::algorithm::hex(Crypto::sha256digest(Json::FastWriter().write(Json::Value(key_content))));
97  std::transform(keyid.begin(), keyid.end(), keyid.begin(), ::tolower);
98  return keyid;
99 }
100 
101 std::string Crypto::sha256digest(const std::string &text) {
102  unsigned char sha256_hash[crypto_hash_sha256_BYTES];
103  crypto_hash_sha256(sha256_hash, reinterpret_cast<const unsigned char *>(text.c_str()), text.size());
104  return std::string(reinterpret_cast<char *>(sha256_hash), crypto_hash_sha256_BYTES);
105 }
106 
107 std::string Crypto::sha512digest(const std::string &text) {
108  unsigned char sha512_hash[crypto_hash_sha512_BYTES];
109  crypto_hash_sha512(sha512_hash, reinterpret_cast<const unsigned char *>(text.c_str()), text.size());
110  return std::string(reinterpret_cast<char *>(sha512_hash), crypto_hash_sha512_BYTES);
111 }
112 
113 std::string Crypto::RSAPSSSign(ENGINE *engine, const std::string &private_key, const std::string &message) {
114  StructGuard<EVP_PKEY> key(nullptr, EVP_PKEY_free);
115  StructGuard<RSA> rsa(nullptr, RSA_free);
116  if (engine != nullptr) {
117  // FIXME: this call leaks memory somehow...
118  key.reset(ENGINE_load_private_key(engine, private_key.c_str(), nullptr, nullptr));
119 
120  if (key == nullptr) {
121  LOG_ERROR << "ENGINE_load_private_key failed with error " << ERR_error_string(ERR_get_error(), nullptr);
122  return std::string();
123  }
124 
125  rsa.reset(EVP_PKEY_get1_RSA(key.get()));
126  if (rsa == nullptr) {
127  LOG_ERROR << "EVP_PKEY_get1_RSA failed with error " << ERR_error_string(ERR_get_error(), nullptr);
128  return std::string();
129  }
130  } else {
131  StructGuard<BIO> bio(BIO_new_mem_buf(const_cast<char *>(private_key.c_str()), static_cast<int>(private_key.size())),
132  BIO_vfree);
133  key.reset(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
134  if (key != nullptr) {
135  rsa.reset(EVP_PKEY_get1_RSA(key.get()));
136  }
137 
138  if (rsa == nullptr) {
139  LOG_ERROR << "PEM_read_bio_PrivateKey failed with error " << ERR_error_string(ERR_get_error(), nullptr);
140  return std::string();
141  }
142 
143 #if AKTUALIZR_OPENSSL_PRE_11
144  RSA_set_method(rsa.get(), RSA_PKCS1_SSLeay());
145 #else
146  RSA_set_method(rsa.get(), RSA_PKCS1_OpenSSL());
147 #endif
148  }
149 
150  const auto sign_size = static_cast<unsigned int>(RSA_size(rsa.get()));
151  boost::scoped_array<unsigned char> EM(new unsigned char[sign_size]);
152  boost::scoped_array<unsigned char> pSignature(new unsigned char[sign_size]);
153 
154  std::string digest = Crypto::sha256digest(message);
155  int status = RSA_padding_add_PKCS1_PSS(rsa.get(), EM.get(), reinterpret_cast<const unsigned char *>(digest.c_str()),
156  EVP_sha256(), -1 /* maximum salt length*/);
157  if (status == 0) {
158  LOG_ERROR << "RSA_padding_add_PKCS1_PSS failed with error " << ERR_error_string(ERR_get_error(), nullptr);
159  return std::string();
160  }
161 
162  /* perform digital signature */
163  status = RSA_private_encrypt(RSA_size(rsa.get()), EM.get(), pSignature.get(), rsa.get(), RSA_NO_PADDING);
164  if (status == -1) {
165  LOG_ERROR << "RSA_private_encrypt failed with error " << ERR_error_string(ERR_get_error(), nullptr);
166  return std::string();
167  }
168  std::string retval = std::string(reinterpret_cast<char *>(pSignature.get()), sign_size);
169  return retval;
170 }
171 
172 std::string Crypto::Sign(KeyType key_type, ENGINE *engine, const std::string &private_key, const std::string &message) {
173  if (key_type == KeyType::kED25519) {
174  return Crypto::ED25519Sign(boost::algorithm::unhex(private_key), message);
175  }
176  return Crypto::RSAPSSSign(engine, private_key, message);
177 }
178 
179 std::string Crypto::ED25519Sign(const std::string &private_key, const std::string &message) {
180  unsigned char sig[crypto_sign_BYTES];
181  crypto_sign_detached(sig, nullptr, reinterpret_cast<const unsigned char *>(message.c_str()), message.size(),
182  reinterpret_cast<const unsigned char *>(private_key.c_str()));
183  return std::string(reinterpret_cast<char *>(sig), crypto_sign_BYTES);
184 }
185 
186 bool Crypto::RSAPSSVerify(const std::string &public_key, const std::string &signature, const std::string &message) {
187  StructGuard<RSA> rsa(nullptr, RSA_free);
188  StructGuard<BIO> bio(BIO_new_mem_buf(const_cast<char *>(public_key.c_str()), static_cast<int>(public_key.size())),
189  BIO_vfree);
190  {
191  RSA *r = nullptr;
192  if (PEM_read_bio_RSA_PUBKEY(bio.get(), &r, nullptr, nullptr) == nullptr) {
193  LOG_ERROR << "PEM_read_bio_RSA_PUBKEY failed with error " << ERR_error_string(ERR_get_error(), nullptr);
194  return false;
195  }
196  rsa.reset(r);
197  }
198 
199 #if AKTUALIZR_OPENSSL_PRE_11
200  RSA_set_method(rsa.get(), RSA_PKCS1_SSLeay());
201 #else
202  RSA_set_method(rsa.get(), RSA_PKCS1_OpenSSL());
203 #endif
204 
205  const auto size = static_cast<unsigned int>(RSA_size(rsa.get()));
206  boost::scoped_array<unsigned char> pDecrypted(new unsigned char[size]);
207  /* now we will verify the signature
208  Start by a RAW decrypt of the signature
209  */
210  int status =
211  RSA_public_decrypt(static_cast<int>(signature.size()), reinterpret_cast<const unsigned char *>(signature.c_str()),
212  pDecrypted.get(), rsa.get(), RSA_NO_PADDING);
213  if (status == -1) {
214  LOG_ERROR << "RSA_public_decrypt failed with error " << ERR_error_string(ERR_get_error(), nullptr);
215  return false;
216  }
217 
218  std::string digest = Crypto::sha256digest(message);
219 
220  /* verify the data */
221  status = RSA_verify_PKCS1_PSS(rsa.get(), reinterpret_cast<const unsigned char *>(digest.c_str()), EVP_sha256(),
222  pDecrypted.get(), -2 /* salt length recovered from signature*/);
223 
224  return status == 1;
225 }
226 bool Crypto::ED25519Verify(const std::string &public_key, const std::string &signature, const std::string &message) {
227  return crypto_sign_verify_detached(reinterpret_cast<const unsigned char *>(signature.c_str()),
228  reinterpret_cast<const unsigned char *>(message.c_str()), message.size(),
229  reinterpret_cast<const unsigned char *>(public_key.c_str())) == 0;
230 }
231 
232 bool Crypto::parseP12(BIO *p12_bio, const std::string &p12_password, std::string *out_pkey, std::string *out_cert,
233  std::string *out_ca) {
234 #if AKTUALIZR_OPENSSL_PRE_11
235  SSLeay_add_all_algorithms();
236 #endif
237  StructGuard<PKCS12> p12(d2i_PKCS12_bio(p12_bio, nullptr), PKCS12_free);
238  if (p12 == nullptr) {
239  LOG_ERROR << "Could not read from " << p12_bio << " file pointer";
240  return false;
241  }
242 
243  // use a lambda here because sk_X509_pop_free is a macro
244  auto stackx509_free = [](STACK_OF(X509) * stack) {
245  sk_X509_pop_free(stack, X509_free); // NOLINT
246  };
247 
248  StructGuard<EVP_PKEY> pkey(nullptr, EVP_PKEY_free);
249  StructGuard<X509> x509_cert(nullptr, X509_free);
250  StructGuard<STACK_OF(X509)> ca_certs(nullptr, stackx509_free);
251  {
252  EVP_PKEY *pk;
253  X509 *x509c = nullptr;
254  STACK_OF(X509) *cacs = nullptr;
255  if (PKCS12_parse(p12.get(), p12_password.c_str(), &pk, &x509c, &cacs) == 0) {
256  LOG_ERROR << "Could not parse file from " << p12_bio << " source pointer";
257  return false;
258  }
259  pkey.reset(pk);
260  x509_cert.reset(x509c);
261  ca_certs.reset(cacs);
262  }
263 
264  StructGuard<BIO> pkey_pem_sink(BIO_new(BIO_s_mem()), BIO_vfree);
265  if (pkey_pem_sink == nullptr) {
266  LOG_ERROR << "Could not open pkey buffer for writing";
267  return false;
268  }
269  PEM_write_bio_PrivateKey(pkey_pem_sink.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr);
270 
271  char *pkey_buf;
272  auto pkey_len = BIO_get_mem_data(pkey_pem_sink.get(), &pkey_buf); // NOLINT
273  *out_pkey = std::string(pkey_buf, static_cast<size_t>(pkey_len));
274 
275  char *cert_buf;
276  size_t cert_len;
277  StructGuard<BIO> cert_sink(BIO_new(BIO_s_mem()), BIO_vfree);
278  if (cert_sink == nullptr) {
279  LOG_ERROR << "Could not open certificate buffer for writing";
280  return false;
281  }
282  PEM_write_bio_X509(cert_sink.get(), x509_cert.get());
283 
284  char *ca_buf;
285  size_t ca_len;
286  StructGuard<BIO> ca_sink(BIO_new(BIO_s_mem()), BIO_vfree);
287  if (ca_sink == nullptr) {
288  LOG_ERROR << "Could not open ca buffer for writing";
289  return false;
290  }
291  X509 *ca_cert = nullptr;
292  for (int i = 0; i < sk_X509_num(ca_certs.get()); i++) { // NOLINT
293  ca_cert = sk_X509_value(ca_certs.get(), i); // NOLINT
294  PEM_write_bio_X509(ca_sink.get(), ca_cert);
295  PEM_write_bio_X509(cert_sink.get(), ca_cert);
296  }
297  ca_len = static_cast<size_t>(BIO_get_mem_data(ca_sink.get(), &ca_buf)); // NOLINT
298  *out_ca = std::string(ca_buf, ca_len);
299 
300  cert_len = static_cast<size_t>(BIO_get_mem_data(cert_sink.get(), &cert_buf)); // NOLINT
301  *out_cert = std::string(cert_buf, cert_len);
302 
303  return true;
304 }
305 
306 bool Crypto::extractSubjectCN(const std::string &cert, std::string *cn) {
307  StructGuard<BIO> bio(BIO_new_mem_buf(const_cast<char *>(cert.c_str()), static_cast<int>(cert.size())), BIO_vfree);
308  StructGuard<X509> x(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr), X509_free);
309  if (x == nullptr) {
310  return false;
311  }
312 
313  int len = X509_NAME_get_text_by_NID(X509_get_subject_name(x.get()), NID_commonName, nullptr, 0);
314  if (len < 0) {
315  return false;
316  }
317  boost::scoped_array<char> buf(new char[len + 1]);
318  X509_NAME_get_text_by_NID(X509_get_subject_name(x.get()), NID_commonName, buf.get(), len + 1);
319  *cn = std::string(buf.get());
320  return true;
321 }
322 
323 /**
324  * Generate a RSA keypair
325  * @param key_type Algorithm used to generate the key
326  * @param public_key Generated public part of key
327  * @param private_key Generated private part of key
328  * @return true if the keys are present at the end of this function (either they were created or existed already)
329  * false if key generation failed
330  */
331 bool Crypto::generateRSAKeyPair(KeyType key_type, std::string *public_key, std::string *private_key) {
332  int bits;
333  switch (key_type) {
334  case KeyType::kRSA2048:
335  bits = 2048;
336  break;
337  case KeyType::kRSA3072:
338  bits = 3072;
339  break;
340  case KeyType::kRSA4096:
341  bits = 4096;
342  break;
343  default:
344  return false;
345  }
346  int ret = 0;
347 
348 #if AKTUALIZR_OPENSSL_PRE_11
349  StructGuard<RSA> rsa(RSA_generate_key(bits, /* number of bits for the key - 2048 is a sensible value */
350  RSA_F4, /* exponent - RSA_F4 is defined as 0x10001L */
351  nullptr, /* callback - can be NULL if we aren't displaying progress */
352  nullptr /* callback argument - not needed in this case */
353  ),
354  RSA_free);
355 #else
356  StructGuard<BIGNUM> bne(BN_new(), BN_free);
357  ret = BN_set_word(bne.get(), RSA_F4);
358  if (ret != 1) {
359  return false;
360  }
361  StructGuard<RSA> rsa(RSA_new(), RSA_free);
362  ret = RSA_generate_key_ex(rsa.get(), bits, /* number of bits for the key - 2048 is a sensible value */
363  bne.get(), /* exponent - RSA_F4 is defined as 0x10001L */
364  nullptr /* callback argument - not needed in this case */
365  );
366  if (ret != 1) {
367  return false;
368  }
369 #endif
370 
371  StructGuard<EVP_PKEY> pkey(EVP_PKEY_new(), EVP_PKEY_free);
372  // release the rsa pointer here, pkey is the new owner
373  EVP_PKEY_assign_RSA(pkey.get(), rsa.release()); // NOLINT
374  char *pubkey_buf;
375  StructGuard<BIO> pubkey_sink(BIO_new(BIO_s_mem()), BIO_vfree);
376  if (pubkey_sink == nullptr) {
377  return false;
378  }
379  ret = PEM_write_bio_PUBKEY(pubkey_sink.get(), pkey.get());
380  if (ret != 1) {
381  return false;
382  }
383  auto pubkey_len = BIO_get_mem_data(pubkey_sink.get(), &pubkey_buf); // NOLINT
384  *public_key = std::string(pubkey_buf, static_cast<size_t>(pubkey_len));
385 
386  char *privkey_buf;
387  StructGuard<BIO> privkey_sink(BIO_new(BIO_s_mem()), BIO_vfree);
388  if (privkey_sink == nullptr) {
389  return false;
390  }
391 
392  ret = PEM_write_bio_RSAPrivateKey(privkey_sink.get(), static_cast<RSA *>(EVP_PKEY_get0(pkey.get())), nullptr, nullptr,
393  0, nullptr, nullptr);
394  if (ret != 1) {
395  return false;
396  }
397  auto privkey_len = BIO_get_mem_data(privkey_sink.get(), &privkey_buf); // NOLINT
398  *private_key = std::string(privkey_buf, static_cast<size_t>(privkey_len));
399  return true;
400 }
401 
402 bool Crypto::generateEDKeyPair(std::string *public_key, std::string *private_key) {
403  unsigned char pk[crypto_sign_PUBLICKEYBYTES];
404  unsigned char sk[crypto_sign_SECRETKEYBYTES];
405  crypto_sign_keypair(pk, sk);
406  *public_key = boost::algorithm::hex(std::string(reinterpret_cast<char *>(pk), crypto_sign_PUBLICKEYBYTES));
407  // std::transform(public_key->begin(), public_key->end(), public_key->begin(), ::tolower);
408  *private_key = boost::algorithm::hex(std::string(reinterpret_cast<char *>(sk), crypto_sign_SECRETKEYBYTES));
409  // std::transform(private_key->begin(), private_key->end(), private_key->begin(), ::tolower);
410  return true;
411 }
412 
413 bool Crypto::generateKeyPair(KeyType key_type, std::string *public_key, std::string *private_key) {
414  if (key_type == KeyType::kED25519) {
415  return Crypto::generateEDKeyPair(public_key, private_key);
416  }
417  return Crypto::generateRSAKeyPair(key_type, public_key, private_key);
418 }
419 
420 bool Crypto::IsRsaKeyType(KeyType type) {
421  switch (type) {
422  case KeyType::kRSA2048:
423  case KeyType::kRSA3072:
424  case KeyType::kRSA4096:
425  return true;
426  default:
427  return false;
428  }
429 }
430 KeyType Crypto::IdentifyRSAKeyType(const std::string &public_key_pem) {
431  StructGuard<BIO> bufio(BIO_new_mem_buf(reinterpret_cast<const void *>(public_key_pem.c_str()),
432  static_cast<int>(public_key_pem.length())),
433  BIO_vfree);
434  if (bufio.get() == nullptr) {
435  throw std::runtime_error("BIO_new_mem_buf failed");
436  }
437  StructGuard<::RSA> rsa(PEM_read_bio_RSA_PUBKEY(bufio.get(), nullptr, nullptr, nullptr), RSA_free);
438 
439  if (rsa.get() == nullptr) {
440  return KeyType::kUnknown;
441  }
442 
443  int key_length = RSA_size(rsa.get()) * 8;
444  // It is not clear from the OpenSSL documentation if RSA_size returns
445  // exactly 2048 or 4096, or if this can vary. For now we will assume that if
446  // OpenSSL has been asked to generate a 'N bit' key, RSA_size() will return
447  // exactly N
448  switch (key_length) {
449  case 2048:
450  return KeyType::kRSA2048;
451  case 3072:
452  return KeyType::kRSA3072;
453  case 4096:
454  return KeyType::kRSA4096;
455  default:
456  LOG_WARNING << "Weird key length:" << key_length;
457  return KeyType::kUnknown;
458  }
459 }
STL namespace.
Json::Value ToUptane() const
Uptane Json representation of this public key.
Definition: crypto.cc:72
bool VerifySignature(const std::string &signature, const std::string &message) const
Verify a signature using this public key.
Definition: crypto.cc:58
Definition: utils.h:14
static bool generateRSAKeyPair(KeyType key_type, std::string *public_key, std::string *private_key)
Generate a RSA keypair.
Definition: crypto.cc:331