certificate.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. /**
  2. * Copyright (c) 2019 Paul-Louis Ageneau
  3. *
  4. * This Source Code Form is subject to the terms of the Mozilla Public
  5. * License, v. 2.0. If a copy of the MPL was not distributed with this
  6. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
  7. */
  8. #include "certificate.hpp"
  9. #include "threadpool.hpp"
  10. #include <algorithm>
  11. #include <cassert>
  12. #include <chrono>
  13. #include <iomanip>
  14. #include <mutex>
  15. #include <sstream>
  16. #include <unordered_map>
  17. namespace rtc::impl {
  18. #if USE_GNUTLS
  19. Certificate Certificate::FromString(string crt_pem, string key_pem) {
  20. PLOG_DEBUG << "Importing certificate from PEM string (GnuTLS)";
  21. shared_ptr<gnutls_certificate_credentials_t> creds(gnutls::new_credentials(),
  22. gnutls::free_credentials);
  23. gnutls_datum_t crt_datum = gnutls::make_datum(crt_pem.data(), crt_pem.size());
  24. gnutls_datum_t key_datum = gnutls::make_datum(key_pem.data(), key_pem.size());
  25. gnutls::check(
  26. gnutls_certificate_set_x509_key_mem(*creds, &crt_datum, &key_datum, GNUTLS_X509_FMT_PEM),
  27. "Unable to import PEM certificate and key");
  28. return Certificate(std::move(creds));
  29. }
  30. Certificate Certificate::FromFile(const string &crt_pem_file, const string &key_pem_file,
  31. const string &pass) {
  32. PLOG_DEBUG << "Importing certificate from PEM file (GnuTLS): " << crt_pem_file;
  33. shared_ptr<gnutls_certificate_credentials_t> creds(gnutls::new_credentials(),
  34. gnutls::free_credentials);
  35. gnutls::check(gnutls_certificate_set_x509_key_file2(*creds, crt_pem_file.c_str(),
  36. key_pem_file.c_str(), GNUTLS_X509_FMT_PEM,
  37. pass.c_str(), 0),
  38. "Unable to import PEM certificate and key from file");
  39. return Certificate(std::move(creds));
  40. }
  41. Certificate Certificate::Generate(CertificateType type, const string &commonName) {
  42. PLOG_DEBUG << "Generating certificate (GnuTLS)";
  43. using namespace gnutls;
  44. unique_ptr<gnutls_x509_crt_t, decltype(&free_crt)> crt(new_crt(), free_crt);
  45. unique_ptr<gnutls_x509_privkey_t, decltype(&free_privkey)> privkey(new_privkey(), free_privkey);
  46. switch (type) {
  47. // RFC 8827 WebRTC Security Architecture 6.5. Communications Security
  48. // All implementations MUST support DTLS 1.2 with the TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  49. // cipher suite and the P-256 curve
  50. // See https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5
  51. case CertificateType::Default:
  52. case CertificateType::Ecdsa: {
  53. gnutls::check(gnutls_x509_privkey_generate(*privkey, GNUTLS_PK_ECDSA,
  54. GNUTLS_CURVE_TO_BITS(GNUTLS_ECC_CURVE_SECP256R1),
  55. 0),
  56. "Unable to generate ECDSA P-256 key pair");
  57. break;
  58. }
  59. case CertificateType::Rsa: {
  60. const unsigned int bits = 2048;
  61. gnutls::check(gnutls_x509_privkey_generate(*privkey, GNUTLS_PK_RSA, bits, 0),
  62. "Unable to generate RSA key pair");
  63. break;
  64. }
  65. default:
  66. throw std::invalid_argument("Unknown certificate type");
  67. }
  68. using namespace std::chrono;
  69. auto now = time_point_cast<seconds>(system_clock::now());
  70. gnutls_x509_crt_set_activation_time(*crt, (now - hours(1)).time_since_epoch().count());
  71. gnutls_x509_crt_set_expiration_time(*crt, (now + hours(24 * 365)).time_since_epoch().count());
  72. gnutls_x509_crt_set_version(*crt, 1);
  73. gnutls_x509_crt_set_key(*crt, *privkey);
  74. gnutls_x509_crt_set_dn_by_oid(*crt, GNUTLS_OID_X520_COMMON_NAME, 0, commonName.data(),
  75. commonName.size());
  76. const size_t serialSize = 16;
  77. char serial[serialSize];
  78. gnutls_rnd(GNUTLS_RND_NONCE, serial, serialSize);
  79. gnutls_x509_crt_set_serial(*crt, serial, serialSize);
  80. gnutls::check(gnutls_x509_crt_sign2(*crt, *crt, *privkey, GNUTLS_DIG_SHA256, 0),
  81. "Unable to auto-sign certificate");
  82. return Certificate(*crt, *privkey);
  83. }
  84. Certificate::Certificate(gnutls_x509_crt_t crt, gnutls_x509_privkey_t privkey)
  85. : mCredentials(gnutls::new_credentials(), gnutls::free_credentials),
  86. mFingerprint(make_fingerprint(crt, CertificateFingerprint::Algorithm::Sha256)) {
  87. gnutls::check(gnutls_certificate_set_x509_key(*mCredentials, &crt, 1, privkey),
  88. "Unable to set certificate and key pair in credentials");
  89. }
  90. Certificate::Certificate(shared_ptr<gnutls_certificate_credentials_t> creds)
  91. : mCredentials(std::move(creds)),
  92. mFingerprint(make_fingerprint(*mCredentials, CertificateFingerprint::Algorithm::Sha256)) {}
  93. gnutls_certificate_credentials_t Certificate::credentials() const { return *mCredentials; }
  94. string make_fingerprint(gnutls_certificate_credentials_t credentials,
  95. CertificateFingerprint::Algorithm fingerprintAlgorithm) {
  96. auto new_crt_list = [credentials]() -> gnutls_x509_crt_t * {
  97. gnutls_x509_crt_t *crt_list = nullptr;
  98. unsigned int crt_list_size = 0;
  99. gnutls::check(gnutls_certificate_get_x509_crt(credentials, 0, &crt_list, &crt_list_size));
  100. assert(crt_list_size == 1);
  101. return crt_list;
  102. };
  103. auto free_crt_list = [](gnutls_x509_crt_t *crt_list) {
  104. gnutls_x509_crt_deinit(crt_list[0]);
  105. gnutls_free(crt_list);
  106. };
  107. unique_ptr<gnutls_x509_crt_t, decltype(free_crt_list)> crt_list(new_crt_list(), free_crt_list);
  108. return make_fingerprint(*crt_list, fingerprintAlgorithm);
  109. }
  110. string make_fingerprint(gnutls_x509_crt_t crt,
  111. CertificateFingerprint::Algorithm fingerprintAlgorithm) {
  112. const size_t size = CertificateFingerprint::AlgorithmSize(fingerprintAlgorithm);
  113. std::vector<unsigned char> buffer(size);
  114. size_t len = size;
  115. gnutls_digest_algorithm_t hashFunc;
  116. switch (fingerprintAlgorithm) {
  117. case CertificateFingerprint::Algorithm::Sha1:
  118. hashFunc = GNUTLS_DIG_SHA1;
  119. break;
  120. case CertificateFingerprint::Algorithm::Sha224:
  121. hashFunc = GNUTLS_DIG_SHA224;
  122. break;
  123. case CertificateFingerprint::Algorithm::Sha256:
  124. hashFunc = GNUTLS_DIG_SHA256;
  125. break;
  126. case CertificateFingerprint::Algorithm::Sha384:
  127. hashFunc = GNUTLS_DIG_SHA384;
  128. break;
  129. case CertificateFingerprint::Algorithm::Sha512:
  130. hashFunc = GNUTLS_DIG_SHA512;
  131. break;
  132. default:
  133. throw std::invalid_argument("Unknown fingerprint algorithm");
  134. }
  135. gnutls::check(gnutls_x509_crt_get_fingerprint(crt, hashFunc, buffer.data(), &len),
  136. "X509 fingerprint error");
  137. std::ostringstream oss;
  138. oss << std::hex << std::uppercase << std::setfill('0');
  139. for (size_t i = 0; i < len; ++i) {
  140. if (i)
  141. oss << std::setw(1) << ':';
  142. oss << std::setw(2) << unsigned(buffer.at(i));
  143. }
  144. return oss.str();
  145. }
  146. #elif USE_MBEDTLS
  147. string make_fingerprint(mbedtls_x509_crt *crt,
  148. CertificateFingerprint::Algorithm fingerprintAlgorithm) {
  149. const int size = CertificateFingerprint::AlgorithmSize(fingerprintAlgorithm);
  150. std::vector<unsigned char> buffer(size);
  151. std::stringstream fingerprint;
  152. switch (fingerprintAlgorithm) {
  153. case CertificateFingerprint::Algorithm::Sha1:
  154. mbedtls::check(mbedtls_sha1(crt->raw.p, crt->raw.len, buffer.data()),
  155. "Failed to generate certificate fingerprint");
  156. break;
  157. case CertificateFingerprint::Algorithm::Sha224:
  158. mbedtls::check(mbedtls_sha256(crt->raw.p, crt->raw.len, buffer.data(), 1),
  159. "Failed to generate certificate fingerprint");
  160. break;
  161. case CertificateFingerprint::Algorithm::Sha256:
  162. mbedtls::check(mbedtls_sha256(crt->raw.p, crt->raw.len, buffer.data(), 0),
  163. "Failed to generate certificate fingerprint");
  164. break;
  165. case CertificateFingerprint::Algorithm::Sha384:
  166. mbedtls::check(mbedtls_sha512(crt->raw.p, crt->raw.len, buffer.data(), 1),
  167. "Failed to generate certificate fingerprint");
  168. break;
  169. case CertificateFingerprint::Algorithm::Sha512:
  170. mbedtls::check(mbedtls_sha512(crt->raw.p, crt->raw.len, buffer.data(), 0),
  171. "Failed to generate certificate fingerprint");
  172. break;
  173. default:
  174. throw std::invalid_argument("Unknown fingerprint algorithm");
  175. }
  176. for (auto i = 0; i < size; i++) {
  177. fingerprint << std::setfill('0') << std::setw(2) << std::hex
  178. << static_cast<int>(buffer.at(i));
  179. if (i != (size - 1)) {
  180. fingerprint << ":";
  181. }
  182. }
  183. return fingerprint.str();
  184. }
  185. Certificate::Certificate(shared_ptr<mbedtls_x509_crt> crt, shared_ptr<mbedtls_pk_context> pk)
  186. : mCrt(crt), mPk(pk),
  187. mFingerprint(make_fingerprint(crt.get(), CertificateFingerprint::Algorithm::Sha256)) {}
  188. Certificate Certificate::FromString(string crt_pem, string key_pem) {
  189. PLOG_DEBUG << "Importing certificate from PEM string (MbedTLS)";
  190. auto crt = mbedtls::new_x509_crt();
  191. auto pk = mbedtls::new_pk_context();
  192. mbedtls::check(mbedtls_x509_crt_parse(crt.get(),
  193. reinterpret_cast<const unsigned char *>(crt_pem.c_str()),
  194. crt_pem.size() + 1),
  195. "Failed to parse certificate");
  196. mbedtls::check(mbedtls_pk_parse_key(pk.get(),
  197. reinterpret_cast<const unsigned char *>(key_pem.c_str()),
  198. key_pem.size() + 1, NULL, 0, NULL, 0),
  199. "Failed to parse key");
  200. return Certificate(std::move(crt), std::move(pk));
  201. }
  202. Certificate Certificate::FromFile(const string &crt_pem_file, const string &key_pem_file,
  203. const string &pass) {
  204. PLOG_DEBUG << "Importing certificate from PEM file (MbedTLS): " << crt_pem_file;
  205. auto crt = mbedtls::new_x509_crt();
  206. auto pk = mbedtls::new_pk_context();
  207. mbedtls::check(mbedtls_x509_crt_parse_file(crt.get(), crt_pem_file.c_str()),
  208. "Failed to parse certificate");
  209. mbedtls::check(mbedtls_pk_parse_keyfile(pk.get(), key_pem_file.c_str(), pass.c_str(), 0, NULL),
  210. "Failed to parse key");
  211. return Certificate(std::move(crt), std::move(pk));
  212. }
  213. Certificate Certificate::Generate(CertificateType type, const string &commonName) {
  214. PLOG_DEBUG << "Generating certificate (MbedTLS)";
  215. mbedtls_entropy_context entropy;
  216. mbedtls_ctr_drbg_context drbg;
  217. mbedtls_x509write_cert wcrt;
  218. mbedtls_mpi serial;
  219. auto crt = mbedtls::new_x509_crt();
  220. auto pk = mbedtls::new_pk_context();
  221. mbedtls_entropy_init(&entropy);
  222. mbedtls_ctr_drbg_init(&drbg);
  223. mbedtls_ctr_drbg_set_prediction_resistance(&drbg, MBEDTLS_CTR_DRBG_PR_ON);
  224. mbedtls_x509write_crt_init(&wcrt);
  225. mbedtls_mpi_init(&serial);
  226. try {
  227. mbedtls::check(mbedtls_ctr_drbg_seed(
  228. &drbg, mbedtls_entropy_func, &entropy,
  229. reinterpret_cast<const unsigned char *>(commonName.data()), commonName.size()));
  230. switch (type) {
  231. // RFC 8827 WebRTC Security Architecture 6.5. Communications Security
  232. // All implementations MUST support DTLS 1.2 with the
  233. // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 cipher suite and the P-256 curve
  234. // See https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5
  235. case CertificateType::Default:
  236. case CertificateType::Ecdsa: {
  237. mbedtls::check(mbedtls_pk_setup(pk.get(), mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)));
  238. mbedtls::check(mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(*pk.get()),
  239. mbedtls_ctr_drbg_random, &drbg),
  240. "Unable to generate ECDSA P-256 key pair");
  241. break;
  242. }
  243. case CertificateType::Rsa: {
  244. const unsigned int nbits = 2048;
  245. const int exponent = 65537;
  246. mbedtls::check(mbedtls_pk_setup(pk.get(), mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)));
  247. mbedtls::check(mbedtls_rsa_gen_key(mbedtls_pk_rsa(*pk.get()), mbedtls_ctr_drbg_random,
  248. &drbg, nbits, exponent),
  249. "Unable to generate RSA key pair");
  250. break;
  251. }
  252. default:
  253. throw std::invalid_argument("Unknown certificate type");
  254. }
  255. auto now = std::chrono::system_clock::now();
  256. string notBefore = mbedtls::format_time(now - std::chrono::hours(1));
  257. string notAfter = mbedtls::format_time(now + std::chrono::hours(24 * 365));
  258. const size_t serialBufferSize = 16;
  259. unsigned char serialBuffer[serialBufferSize];
  260. mbedtls::check(mbedtls_ctr_drbg_random(&drbg, serialBuffer, serialBufferSize),
  261. "Failed to generate certificate");
  262. mbedtls::check(mbedtls_mpi_read_binary(&serial, serialBuffer, serialBufferSize),
  263. "Failed to generate certificate");
  264. std::string name = std::string("O=" + commonName + ",CN=" + commonName);
  265. mbedtls::check(mbedtls_x509write_crt_set_serial(&wcrt, &serial),
  266. "Failed to generate certificate");
  267. mbedtls::check(mbedtls_x509write_crt_set_subject_name(&wcrt, name.c_str()),
  268. "Failed to generate certificate");
  269. mbedtls::check(mbedtls_x509write_crt_set_issuer_name(&wcrt, name.c_str()),
  270. "Failed to generate certificate");
  271. mbedtls::check(
  272. mbedtls_x509write_crt_set_validity(&wcrt, notBefore.c_str(), notAfter.c_str()),
  273. "Failed to generate certificate");
  274. mbedtls_x509write_crt_set_version(&wcrt, MBEDTLS_X509_CRT_VERSION_3);
  275. mbedtls_x509write_crt_set_subject_key(&wcrt, pk.get());
  276. mbedtls_x509write_crt_set_issuer_key(&wcrt, pk.get());
  277. mbedtls_x509write_crt_set_md_alg(&wcrt, MBEDTLS_MD_SHA256);
  278. const size_t certificateBufferSize = 4096;
  279. unsigned char certificateBuffer[certificateBufferSize];
  280. std::memset(certificateBuffer, 0, certificateBufferSize);
  281. auto certificateLen = mbedtls_x509write_crt_der(
  282. &wcrt, certificateBuffer, certificateBufferSize, mbedtls_ctr_drbg_random, &drbg);
  283. if (certificateLen <= 0) {
  284. throw std::runtime_error("Certificate generation failed");
  285. }
  286. mbedtls::check(mbedtls_x509_crt_parse_der(
  287. crt.get(), (certificateBuffer + certificateBufferSize - certificateLen),
  288. certificateLen),
  289. "Failed to generate certificate");
  290. } catch (...) {
  291. mbedtls_entropy_free(&entropy);
  292. mbedtls_ctr_drbg_free(&drbg);
  293. mbedtls_x509write_crt_free(&wcrt);
  294. mbedtls_mpi_free(&serial);
  295. throw;
  296. }
  297. mbedtls_entropy_free(&entropy);
  298. mbedtls_ctr_drbg_free(&drbg);
  299. mbedtls_x509write_crt_free(&wcrt);
  300. mbedtls_mpi_free(&serial);
  301. return Certificate(std::move(crt), std::move(pk));
  302. }
  303. std::tuple<shared_ptr<mbedtls_x509_crt>, shared_ptr<mbedtls_pk_context>>
  304. Certificate::credentials() const {
  305. return {mCrt, mPk};
  306. }
  307. #else // OPENSSL
  308. #include <openssl/bn.h>
  309. #include <openssl/ec.h>
  310. #include <openssl/rsa.h>
  311. namespace {
  312. // Dummy password callback that copies the password from user data
  313. int dummy_pass_cb(char *buf, int size, int /*rwflag*/, void *u) {
  314. const char *pass = static_cast<char *>(u);
  315. return snprintf(buf, size, "%s", pass);
  316. }
  317. } // namespace
  318. Certificate Certificate::FromString(string crt_pem, string key_pem) {
  319. PLOG_DEBUG << "Importing certificate from PEM string (OpenSSL)";
  320. BIO *bio = BIO_new(BIO_s_mem());
  321. BIO_write(bio, crt_pem.data(), int(crt_pem.size()));
  322. auto x509 = shared_ptr<X509>(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free);
  323. if (!x509) {
  324. BIO_free(bio);
  325. throw std::invalid_argument("Unable to import PEM certificate");
  326. }
  327. std::vector<shared_ptr<X509>> chain;
  328. while (auto extra =
  329. shared_ptr<X509>(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free)) {
  330. chain.push_back(std::move(extra));
  331. }
  332. BIO_free(bio);
  333. bio = BIO_new(BIO_s_mem());
  334. BIO_write(bio, key_pem.data(), int(key_pem.size()));
  335. auto pkey = shared_ptr<EVP_PKEY>(PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr),
  336. EVP_PKEY_free);
  337. BIO_free(bio);
  338. if (!pkey)
  339. throw std::invalid_argument("Unable to import PEM key");
  340. return Certificate(x509, pkey, std::move(chain));
  341. }
  342. Certificate Certificate::FromFile(const string &crt_pem_file, const string &key_pem_file,
  343. const string &pass) {
  344. PLOG_DEBUG << "Importing certificate from PEM file (OpenSSL): " << crt_pem_file;
  345. BIO *bio = openssl::BIO_new_from_file(crt_pem_file);
  346. if (!bio)
  347. throw std::invalid_argument("Unable to open PEM certificate file");
  348. auto x509 = shared_ptr<X509>(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free);
  349. if (!x509) {
  350. BIO_free(bio);
  351. throw std::invalid_argument("Unable to import PEM certificate from file");
  352. }
  353. std::vector<shared_ptr<X509>> chain;
  354. while (auto extra =
  355. shared_ptr<X509>(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free)) {
  356. chain.push_back(std::move(extra));
  357. }
  358. BIO_free(bio);
  359. bio = openssl::BIO_new_from_file(key_pem_file);
  360. if (!bio)
  361. throw std::invalid_argument("Unable to open PEM key file");
  362. auto pkey = shared_ptr<EVP_PKEY>(
  363. PEM_read_bio_PrivateKey(bio, nullptr, dummy_pass_cb, const_cast<char *>(pass.c_str())),
  364. EVP_PKEY_free);
  365. BIO_free(bio);
  366. if (!pkey)
  367. throw std::invalid_argument("Unable to import PEM key from file");
  368. return Certificate(x509, pkey, std::move(chain));
  369. }
  370. Certificate Certificate::Generate(CertificateType type, const string &commonName) {
  371. PLOG_DEBUG << "Generating certificate (OpenSSL)";
  372. shared_ptr<X509> x509(X509_new(), X509_free);
  373. unique_ptr<BIGNUM, decltype(&BN_free)> serial_number(BN_new(), BN_free);
  374. unique_ptr<X509_NAME, decltype(&X509_NAME_free)> name(X509_NAME_new(), X509_NAME_free);
  375. if (!x509 || !serial_number || !name)
  376. throw std::runtime_error("Unable to allocate structures for certificate generation");
  377. shared_ptr<EVP_PKEY> pkey;
  378. switch (type) {
  379. // RFC 8827 WebRTC Security Architecture 6.5. Communications Security
  380. // All implementations MUST support DTLS 1.2 with the TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  381. // cipher suite and the P-256 curve
  382. // See https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5
  383. case CertificateType::Default:
  384. case CertificateType::Ecdsa: {
  385. PLOG_VERBOSE << "Generating ECDSA P-256 key pair";
  386. #if OPENSSL_VERSION_NUMBER >= 0x30000000
  387. pkey = shared_ptr<EVP_PKEY>(EVP_EC_gen("prime256v1"), EVP_PKEY_free);
  388. if (!pkey)
  389. throw std::runtime_error("Unable to generate ECDSA P-256 key pair");
  390. #else
  391. pkey = shared_ptr<EVP_PKEY>(EVP_PKEY_new(), EVP_PKEY_free);
  392. unique_ptr<EC_KEY, decltype(&EC_KEY_free)> ecc(
  393. EC_KEY_new_by_curve_name(NID_X9_62_prime256v1), EC_KEY_free);
  394. if (!pkey || !ecc)
  395. throw std::runtime_error("Unable to allocate structure for ECDSA P-256 key pair");
  396. EC_KEY_set_asn1_flag(ecc.get(), OPENSSL_EC_NAMED_CURVE); // Set ASN1 OID
  397. if (!EC_KEY_generate_key(ecc.get()) || !EVP_PKEY_assign_EC_KEY(pkey.get(), ecc.get()))
  398. throw std::runtime_error("Unable to generate ECDSA P-256 key pair");
  399. ecc.release(); // the key will be freed when pkey is freed
  400. #endif
  401. break;
  402. }
  403. case CertificateType::Rsa: {
  404. PLOG_VERBOSE << "Generating RSA key pair";
  405. const unsigned int bits = 2048;
  406. #if OPENSSL_VERSION_NUMBER >= 0x30000000
  407. pkey = shared_ptr<EVP_PKEY>(EVP_RSA_gen(bits), EVP_PKEY_free);
  408. if (!pkey)
  409. throw std::runtime_error("Unable to generate RSA key pair");
  410. #else
  411. pkey = shared_ptr<EVP_PKEY>(EVP_PKEY_new(), EVP_PKEY_free);
  412. unique_ptr<RSA, decltype(&RSA_free)> rsa(RSA_new(), RSA_free);
  413. unique_ptr<BIGNUM, decltype(&BN_free)> exponent(BN_new(), BN_free);
  414. if (!pkey || !rsa || !exponent)
  415. throw std::runtime_error("Unable to allocate structures for RSA key pair");
  416. const unsigned int e = 65537; // 2^16 + 1
  417. if (!BN_set_word(exponent.get(), e) ||
  418. !RSA_generate_key_ex(rsa.get(), bits, exponent.get(), NULL) ||
  419. !EVP_PKEY_assign_RSA(pkey.get(), rsa.get()))
  420. throw std::runtime_error("Unable to generate RSA key pair");
  421. rsa.release(); // the key will be freed when pkey is freed
  422. #endif
  423. break;
  424. }
  425. default:
  426. throw std::invalid_argument("Unknown certificate type");
  427. }
  428. const size_t serialSize = 16;
  429. auto *commonNameBytes =
  430. reinterpret_cast<unsigned char *>(const_cast<char *>(commonName.c_str()));
  431. if (!X509_set_pubkey(x509.get(), pkey.get()))
  432. throw std::runtime_error("Unable to set certificate public key");
  433. if (!X509_gmtime_adj(X509_getm_notBefore(x509.get()), 3600 * -1) ||
  434. !X509_gmtime_adj(X509_getm_notAfter(x509.get()), 3600 * 24 * 365) ||
  435. !X509_set_version(x509.get(), 1) || !BN_rand(serial_number.get(), serialSize, 0, 0) ||
  436. !BN_to_ASN1_INTEGER(serial_number.get(), X509_get_serialNumber(x509.get())) ||
  437. !X509_NAME_add_entry_by_NID(name.get(), NID_commonName, MBSTRING_UTF8, commonNameBytes, -1,
  438. -1, 0) ||
  439. !X509_set_subject_name(x509.get(), name.get()) ||
  440. !X509_set_issuer_name(x509.get(), name.get()))
  441. throw std::runtime_error("Unable to set certificate properties");
  442. if (!X509_sign(x509.get(), pkey.get(), EVP_sha256()))
  443. throw std::runtime_error("Unable to auto-sign certificate");
  444. return Certificate(x509, pkey);
  445. }
  446. Certificate::Certificate(shared_ptr<X509> x509, shared_ptr<EVP_PKEY> pkey,
  447. std::vector<shared_ptr<X509>> chain)
  448. : mX509(std::move(x509)), mPKey(std::move(pkey)), mChain(std::move(chain)),
  449. mFingerprint(make_fingerprint(mX509.get(), CertificateFingerprint::Algorithm::Sha256)) {}
  450. std::tuple<X509 *, EVP_PKEY *> Certificate::credentials() const {
  451. return {mX509.get(), mPKey.get()};
  452. }
  453. std::vector<X509 *> Certificate::chain() const {
  454. std::vector<X509 *> v;
  455. v.reserve(mChain.size());
  456. std::transform(mChain.begin(), mChain.end(), std::back_inserter(v),
  457. [](const auto &c) { return c.get(); });
  458. return v;
  459. }
  460. string make_fingerprint(X509 *x509, CertificateFingerprint::Algorithm fingerprintAlgorithm) {
  461. size_t size = CertificateFingerprint::AlgorithmSize(fingerprintAlgorithm);
  462. std::vector<unsigned char> buffer(size);
  463. auto len = static_cast<unsigned int>(size);
  464. const EVP_MD *hashFunc;
  465. switch (fingerprintAlgorithm) {
  466. case CertificateFingerprint::Algorithm::Sha1:
  467. hashFunc = EVP_sha1();
  468. break;
  469. case CertificateFingerprint::Algorithm::Sha224:
  470. hashFunc = EVP_sha224();
  471. break;
  472. case CertificateFingerprint::Algorithm::Sha256:
  473. hashFunc = EVP_sha256();
  474. break;
  475. case CertificateFingerprint::Algorithm::Sha384:
  476. hashFunc = EVP_sha384();
  477. break;
  478. case CertificateFingerprint::Algorithm::Sha512:
  479. hashFunc = EVP_sha512();
  480. break;
  481. default:
  482. throw std::invalid_argument("Unknown fingerprint algorithm");
  483. }
  484. if (!X509_digest(x509, hashFunc, buffer.data(), &len))
  485. throw std::runtime_error("X509 fingerprint error");
  486. std::ostringstream oss;
  487. oss << std::hex << std::uppercase << std::setfill('0');
  488. for (size_t i = 0; i < len; ++i) {
  489. if (i)
  490. oss << std::setw(1) << ':';
  491. oss << std::setw(2) << unsigned(buffer.at(i));
  492. }
  493. return oss.str();
  494. }
  495. #endif
  496. // Common for GnuTLS, Mbed TLS, and OpenSSL
  497. future_certificate_ptr make_certificate(CertificateType type) {
  498. return ThreadPool::Instance().enqueue([type, token = Init::Instance().token()]() {
  499. return std::make_shared<Certificate>(Certificate::Generate(type, "libdatachannel"));
  500. });
  501. }
  502. CertificateFingerprint Certificate::fingerprint() const {
  503. return CertificateFingerprint{CertificateFingerprint::Algorithm::Sha256, mFingerprint};
  504. }
  505. } // namespace rtc::impl