blob: 9f7c63b06c407978d93113841b2adcb3274be7bb [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "rtc_base/opensslidentity.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000012
jbauch555604a2016-04-26 03:13:22 -070013#include <memory>
14
Mirko Bonadeie0623852018-02-01 11:17:40 +010015#if defined(WEBRTC_WIN)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000016// Must be included first before openssl headers.
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/win32.h" // NOLINT
Mirko Bonadeie0623852018-02-01 11:17:40 +010018#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000019
20#include <openssl/bio.h>
Jian Cui0a8798b2017-11-16 16:58:02 -080021#include <openssl/bn.h>
22#include <openssl/crypto.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000023#include <openssl/err.h>
24#include <openssl/pem.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000025#include <openssl/rsa.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "rtc_base/checks.h"
28#include "rtc_base/helpers.h"
29#include "rtc_base/logging.h"
30#include "rtc_base/openssl.h"
31#include "rtc_base/openssldigest.h"
Jian Cui0a8798b2017-11-16 16:58:02 -080032#include "rtc_base/ptr_util.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000033
34namespace rtc {
35
36// We could have exposed a myriad of parameters for the crypto stuff,
37// but keeping it simple seems best.
38
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000039// Random bits for certificate serial number
40static const int SERIAL_RAND_BITS = 64;
41
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000042// Generate a key pair. Caller is responsible for freeing the returned object.
torbjorng4e572472015-10-08 09:42:49 -070043static EVP_PKEY* MakeKey(const KeyParams& key_params) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010044 RTC_LOG(LS_INFO) << "Making key pair";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000045 EVP_PKEY* pkey = EVP_PKEY_new();
torbjorng4e572472015-10-08 09:42:49 -070046 if (key_params.type() == KT_RSA) {
47 int key_length = key_params.rsa_params().mod_size;
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020048 BIGNUM* exponent = BN_new();
49 RSA* rsa = RSA_new();
50 if (!pkey || !exponent || !rsa ||
torbjorng4e572472015-10-08 09:42:49 -070051 !BN_set_word(exponent, key_params.rsa_params().pub_exp) ||
deadbeef37f5ecf2017-02-27 14:06:41 -080052 !RSA_generate_key_ex(rsa, key_length, exponent, nullptr) ||
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020053 !EVP_PKEY_assign_RSA(pkey, rsa)) {
54 EVP_PKEY_free(pkey);
55 BN_free(exponent);
56 RSA_free(rsa);
Mirko Bonadei675513b2017-11-09 11:09:25 +010057 RTC_LOG(LS_ERROR) << "Failed to make RSA key pair";
deadbeef37f5ecf2017-02-27 14:06:41 -080058 return nullptr;
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020059 }
60 // ownership of rsa struct was assigned, don't free it.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000061 BN_free(exponent);
torbjorng4e572472015-10-08 09:42:49 -070062 } else if (key_params.type() == KT_ECDSA) {
63 if (key_params.ec_curve() == EC_NIST_P256) {
64 EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
ssarohabbfed522016-12-11 18:42:07 -080065
66 // Ensure curve name is included when EC key is serialized.
67 // Without this call, OpenSSL versions before 1.1.0 will create
68 // certificates that don't work for TLS.
69 // This is a no-op for BoringSSL and OpenSSL 1.1.0+
70 EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE);
71
torbjorng4e572472015-10-08 09:42:49 -070072 if (!pkey || !ec_key || !EC_KEY_generate_key(ec_key) ||
73 !EVP_PKEY_assign_EC_KEY(pkey, ec_key)) {
74 EVP_PKEY_free(pkey);
75 EC_KEY_free(ec_key);
Mirko Bonadei675513b2017-11-09 11:09:25 +010076 RTC_LOG(LS_ERROR) << "Failed to make EC key pair";
deadbeef37f5ecf2017-02-27 14:06:41 -080077 return nullptr;
torbjorng4e572472015-10-08 09:42:49 -070078 }
79 // ownership of ec_key struct was assigned, don't free it.
80 } else {
81 // Add generation of any other curves here.
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020082 EVP_PKEY_free(pkey);
Mirko Bonadei675513b2017-11-09 11:09:25 +010083 RTC_LOG(LS_ERROR) << "ECDSA key requested for unknown curve";
deadbeef37f5ecf2017-02-27 14:06:41 -080084 return nullptr;
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020085 }
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020086 } else {
87 EVP_PKEY_free(pkey);
Mirko Bonadei675513b2017-11-09 11:09:25 +010088 RTC_LOG(LS_ERROR) << "Key type requested not understood";
deadbeef37f5ecf2017-02-27 14:06:41 -080089 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000090 }
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020091
Mirko Bonadei675513b2017-11-09 11:09:25 +010092 RTC_LOG(LS_INFO) << "Returning key pair";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000093 return pkey;
94}
95
96// Generate a self-signed certificate, with the public key from the
97// given key pair. Caller is responsible for freeing the returned object.
98static X509* MakeCertificate(EVP_PKEY* pkey, const SSLIdentityParams& params) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010099 RTC_LOG(LS_INFO) << "Making certificate for " << params.common_name;
deadbeef37f5ecf2017-02-27 14:06:41 -0800100 X509* x509 = nullptr;
101 BIGNUM* serial_number = nullptr;
102 X509_NAME* name = nullptr;
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100103 time_t epoch_off = 0; // Time offset since epoch.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000104
deadbeef37f5ecf2017-02-27 14:06:41 -0800105 if ((x509 = X509_new()) == nullptr)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000106 goto error;
107
108 if (!X509_set_pubkey(x509, pkey))
109 goto error;
110
111 // serial number
112 // temporary reference to serial number inside x509 struct
113 ASN1_INTEGER* asn1_serial_number;
deadbeef37f5ecf2017-02-27 14:06:41 -0800114 if ((serial_number = BN_new()) == nullptr ||
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000115 !BN_pseudo_rand(serial_number, SERIAL_RAND_BITS, 0, 0) ||
deadbeef37f5ecf2017-02-27 14:06:41 -0800116 (asn1_serial_number = X509_get_serialNumber(x509)) == nullptr ||
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000117 !BN_to_ASN1_INTEGER(serial_number, asn1_serial_number))
118 goto error;
119
torbjorngf8160352016-03-29 07:57:43 -0700120 if (!X509_set_version(x509, 2L)) // version 3
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000121 goto error;
122
123 // There are a lot of possible components for the name entries. In
124 // our P2P SSL mode however, the certificates are pre-exchanged
125 // (through the secure XMPP channel), and so the certificate
126 // identification is arbitrary. It can't be empty, so we set some
127 // arbitrary common_name. Note that this certificate goes out in
128 // clear during SSL negotiation, so there may be a privacy issue in
129 // putting anything recognizable here.
deadbeef37f5ecf2017-02-27 14:06:41 -0800130 if ((name = X509_NAME_new()) == nullptr ||
131 !X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_UTF8,
132 (unsigned char*)params.common_name.c_str(),
133 -1, -1, 0) ||
134 !X509_set_subject_name(x509, name) || !X509_set_issuer_name(x509, name))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000135 goto error;
136
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100137 if (!X509_time_adj(X509_get_notBefore(x509), params.not_before, &epoch_off) ||
138 !X509_time_adj(X509_get_notAfter(x509), params.not_after, &epoch_off))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000139 goto error;
140
Joachim Bauch1b794d52015-05-12 03:32:11 +0200141 if (!X509_sign(x509, pkey, EVP_sha256()))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000142 goto error;
143
144 BN_free(serial_number);
145 X509_NAME_free(name);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100146 RTC_LOG(LS_INFO) << "Returning certificate";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000147 return x509;
148
Jian Cui0a8798b2017-11-16 16:58:02 -0800149error:
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000150 BN_free(serial_number);
151 X509_NAME_free(name);
152 X509_free(x509);
deadbeef37f5ecf2017-02-27 14:06:41 -0800153 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000154}
155
156// This dumps the SSL error stack to the log.
157static void LogSSLErrors(const std::string& prefix) {
158 char error_buf[200];
159 unsigned long err;
160
161 while ((err = ERR_get_error()) != 0) {
162 ERR_error_string_n(err, error_buf, sizeof(error_buf));
Mirko Bonadei675513b2017-11-09 11:09:25 +0100163 RTC_LOG(LS_ERROR) << prefix << ": " << error_buf << "\n";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000164 }
165}
166
torbjorng4e572472015-10-08 09:42:49 -0700167OpenSSLKeyPair* OpenSSLKeyPair::Generate(const KeyParams& key_params) {
168 EVP_PKEY* pkey = MakeKey(key_params);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000169 if (!pkey) {
170 LogSSLErrors("Generating key pair");
deadbeef37f5ecf2017-02-27 14:06:41 -0800171 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000172 }
173 return new OpenSSLKeyPair(pkey);
174}
175
hbos6b470a92016-04-28 05:14:21 -0700176OpenSSLKeyPair* OpenSSLKeyPair::FromPrivateKeyPEMString(
177 const std::string& pem_string) {
178 BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1);
179 if (!bio) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100180 RTC_LOG(LS_ERROR) << "Failed to create a new BIO buffer.";
hbos6b470a92016-04-28 05:14:21 -0700181 return nullptr;
182 }
183 BIO_set_mem_eof_return(bio, 0);
184 EVP_PKEY* pkey =
185 PEM_read_bio_PrivateKey(bio, nullptr, nullptr, const_cast<char*>("\0"));
186 BIO_free(bio); // Frees the BIO, but not the pointed-to string.
187 if (!pkey) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100188 RTC_LOG(LS_ERROR) << "Failed to create the private key from PEM string.";
hbos6b470a92016-04-28 05:14:21 -0700189 return nullptr;
190 }
191 if (EVP_PKEY_missing_parameters(pkey) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100192 RTC_LOG(LS_ERROR)
193 << "The resulting key pair is missing public key parameters.";
hbos6b470a92016-04-28 05:14:21 -0700194 EVP_PKEY_free(pkey);
195 return nullptr;
196 }
197 return new OpenSSLKeyPair(pkey);
198}
199
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000200OpenSSLKeyPair::~OpenSSLKeyPair() {
201 EVP_PKEY_free(pkey_);
202}
203
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000204OpenSSLKeyPair* OpenSSLKeyPair::GetReference() {
205 AddReference();
206 return new OpenSSLKeyPair(pkey_);
207}
208
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000209void OpenSSLKeyPair::AddReference() {
Jiayang Liu770cc382015-05-28 15:36:29 -0700210 EVP_PKEY_up_ref(pkey_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000211}
212
hbos6b470a92016-04-28 05:14:21 -0700213std::string OpenSSLKeyPair::PrivateKeyToPEMString() const {
214 BIO* temp_memory_bio = BIO_new(BIO_s_mem());
215 if (!temp_memory_bio) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100216 RTC_LOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
hbos6b470a92016-04-28 05:14:21 -0700217 RTC_NOTREACHED();
218 return "";
219 }
Jian Cui0a8798b2017-11-16 16:58:02 -0800220 if (!PEM_write_bio_PrivateKey(temp_memory_bio, pkey_, nullptr, nullptr, 0,
221 nullptr, nullptr)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100222 RTC_LOG_F(LS_ERROR) << "Failed to write private key";
hbos6b470a92016-04-28 05:14:21 -0700223 BIO_free(temp_memory_bio);
224 RTC_NOTREACHED();
225 return "";
226 }
227 BIO_write(temp_memory_bio, "\0", 1);
228 char* buffer;
229 BIO_get_mem_data(temp_memory_bio, &buffer);
230 std::string priv_key_str = buffer;
231 BIO_free(temp_memory_bio);
232 return priv_key_str;
233}
234
235std::string OpenSSLKeyPair::PublicKeyToPEMString() const {
236 BIO* temp_memory_bio = BIO_new(BIO_s_mem());
237 if (!temp_memory_bio) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100238 RTC_LOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
hbos6b470a92016-04-28 05:14:21 -0700239 RTC_NOTREACHED();
240 return "";
241 }
242 if (!PEM_write_bio_PUBKEY(temp_memory_bio, pkey_)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100243 RTC_LOG_F(LS_ERROR) << "Failed to write public key";
hbos6b470a92016-04-28 05:14:21 -0700244 BIO_free(temp_memory_bio);
245 RTC_NOTREACHED();
246 return "";
247 }
248 BIO_write(temp_memory_bio, "\0", 1);
249 char* buffer;
250 BIO_get_mem_data(temp_memory_bio, &buffer);
251 std::string pub_key_str = buffer;
252 BIO_free(temp_memory_bio);
253 return pub_key_str;
254}
255
256bool OpenSSLKeyPair::operator==(const OpenSSLKeyPair& other) const {
257 return EVP_PKEY_cmp(this->pkey_, other.pkey_) == 1;
258}
259
260bool OpenSSLKeyPair::operator!=(const OpenSSLKeyPair& other) const {
261 return !(*this == other);
262}
263
tfarinaa41ab932015-10-30 16:08:48 -0700264#if !defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000265// Print a certificate to the log, for debugging.
266static void PrintCert(X509* x509) {
267 BIO* temp_memory_bio = BIO_new(BIO_s_mem());
268 if (!temp_memory_bio) {
Jonas Olssonaddc3802018-02-01 09:53:06 +0100269 RTC_DLOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000270 return;
271 }
272 X509_print_ex(temp_memory_bio, x509, XN_FLAG_SEP_CPLUS_SPC, 0);
273 BIO_write(temp_memory_bio, "\0", 1);
274 char* buffer;
275 BIO_get_mem_data(temp_memory_bio, &buffer);
Jonas Olssonaddc3802018-02-01 09:53:06 +0100276 RTC_DLOG(LS_VERBOSE) << buffer;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000277 BIO_free(temp_memory_bio);
278}
279#endif
280
Jian Cui0a8798b2017-11-16 16:58:02 -0800281OpenSSLCertificate::OpenSSLCertificate(X509* x509) : x509_(x509) {
282 AddReference();
283}
284
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000285OpenSSLCertificate* OpenSSLCertificate::Generate(
Jian Cui0a8798b2017-11-16 16:58:02 -0800286 OpenSSLKeyPair* key_pair,
287 const SSLIdentityParams& params) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000288 SSLIdentityParams actual_params(params);
289 if (actual_params.common_name.empty()) {
290 // Use a random string, arbitrarily 8chars long.
291 actual_params.common_name = CreateRandomString(8);
292 }
293 X509* x509 = MakeCertificate(key_pair->pkey(), actual_params);
294 if (!x509) {
295 LogSSLErrors("Generating certificate");
deadbeef37f5ecf2017-02-27 14:06:41 -0800296 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000297 }
tfarinaa41ab932015-10-30 16:08:48 -0700298#if !defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000299 PrintCert(x509);
300#endif
301 OpenSSLCertificate* ret = new OpenSSLCertificate(x509);
302 X509_free(x509);
303 return ret;
304}
305
306OpenSSLCertificate* OpenSSLCertificate::FromPEMString(
307 const std::string& pem_string) {
308 BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1);
309 if (!bio)
deadbeef37f5ecf2017-02-27 14:06:41 -0800310 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000311 BIO_set_mem_eof_return(bio, 0);
deadbeef37f5ecf2017-02-27 14:06:41 -0800312 X509* x509 =
313 PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0"));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000314 BIO_free(bio); // Frees the BIO, but not the pointed-to string.
315
316 if (!x509)
deadbeef37f5ecf2017-02-27 14:06:41 -0800317 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000318
319 OpenSSLCertificate* ret = new OpenSSLCertificate(x509);
320 X509_free(x509);
321 return ret;
322}
323
324// NOTE: This implementation only functions correctly after InitializeSSL
325// and before CleanupSSL.
326bool OpenSSLCertificate::GetSignatureDigestAlgorithm(
327 std::string* algorithm) const {
Jiawei Oueb0df082018-02-02 14:51:18 -0800328 int nid = X509_get_signature_nid(x509_);
JiaYang (佳扬) Liu01aeaee2015-04-22 12:18:33 -0700329 switch (nid) {
330 case NID_md5WithRSA:
331 case NID_md5WithRSAEncryption:
332 *algorithm = DIGEST_MD5;
333 break;
334 case NID_ecdsa_with_SHA1:
335 case NID_dsaWithSHA1:
336 case NID_dsaWithSHA1_2:
337 case NID_sha1WithRSA:
338 case NID_sha1WithRSAEncryption:
339 *algorithm = DIGEST_SHA_1;
340 break;
341 case NID_ecdsa_with_SHA224:
342 case NID_sha224WithRSAEncryption:
343 case NID_dsa_with_SHA224:
344 *algorithm = DIGEST_SHA_224;
345 break;
346 case NID_ecdsa_with_SHA256:
347 case NID_sha256WithRSAEncryption:
348 case NID_dsa_with_SHA256:
349 *algorithm = DIGEST_SHA_256;
350 break;
351 case NID_ecdsa_with_SHA384:
352 case NID_sha384WithRSAEncryption:
353 *algorithm = DIGEST_SHA_384;
354 break;
355 case NID_ecdsa_with_SHA512:
356 case NID_sha512WithRSAEncryption:
357 *algorithm = DIGEST_SHA_512;
358 break;
359 default:
360 // Unknown algorithm. There are several unhandled options that are less
361 // common and more complex.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100362 RTC_LOG(LS_ERROR) << "Unknown signature algorithm NID: " << nid;
JiaYang (佳扬) Liu01aeaee2015-04-22 12:18:33 -0700363 algorithm->clear();
364 return false;
365 }
366 return true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000367}
368
369bool OpenSSLCertificate::ComputeDigest(const std::string& algorithm,
370 unsigned char* digest,
371 size_t size,
372 size_t* length) const {
373 return ComputeDigest(x509_, algorithm, digest, size, length);
374}
375
376bool OpenSSLCertificate::ComputeDigest(const X509* x509,
377 const std::string& algorithm,
378 unsigned char* digest,
379 size_t size,
380 size_t* length) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200381 const EVP_MD* md;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000382 unsigned int n;
383
384 if (!OpenSSLDigest::GetDigestEVP(algorithm, &md))
385 return false;
386
387 if (size < static_cast<size_t>(EVP_MD_size(md)))
388 return false;
389
390 X509_digest(x509, md, digest, &n);
391
392 *length = n;
393
394 return true;
395}
396
397OpenSSLCertificate::~OpenSSLCertificate() {
398 X509_free(x509_);
399}
400
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000401OpenSSLCertificate* OpenSSLCertificate::GetReference() const {
402 return new OpenSSLCertificate(x509_);
403}
404
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000405std::string OpenSSLCertificate::ToPEMString() const {
406 BIO* bio = BIO_new(BIO_s_mem());
407 if (!bio) {
andrew@webrtc.orga5b78692014-08-28 16:28:26 +0000408 FATAL() << "unreachable code";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000409 }
410 if (!PEM_write_bio_X509(bio, x509_)) {
411 BIO_free(bio);
andrew@webrtc.orga5b78692014-08-28 16:28:26 +0000412 FATAL() << "unreachable code";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000413 }
414 BIO_write(bio, "\0", 1);
415 char* buffer;
416 BIO_get_mem_data(bio, &buffer);
417 std::string ret(buffer);
418 BIO_free(bio);
419 return ret;
420}
421
422void OpenSSLCertificate::ToDER(Buffer* der_buffer) const {
423 // In case of failure, make sure to leave the buffer empty.
Karl Wiberg94784372015-04-20 14:03:07 +0200424 der_buffer->SetSize(0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000425
426 // Calculates the DER representation of the certificate, from scratch.
427 BIO* bio = BIO_new(BIO_s_mem());
428 if (!bio) {
andrew@webrtc.orga5b78692014-08-28 16:28:26 +0000429 FATAL() << "unreachable code";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000430 }
431 if (!i2d_X509_bio(bio, x509_)) {
432 BIO_free(bio);
andrew@webrtc.orga5b78692014-08-28 16:28:26 +0000433 FATAL() << "unreachable code";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000434 }
435 char* data;
436 size_t length = BIO_get_mem_data(bio, &data);
437 der_buffer->SetData(data, length);
438 BIO_free(bio);
439}
440
441void OpenSSLCertificate::AddReference() const {
deadbeef37f5ecf2017-02-27 14:06:41 -0800442 RTC_DCHECK(x509_ != nullptr);
Jiayang Liu770cc382015-05-28 15:36:29 -0700443 X509_up_ref(x509_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000444}
445
hbos6b470a92016-04-28 05:14:21 -0700446bool OpenSSLCertificate::operator==(const OpenSSLCertificate& other) const {
Jian Cui0a8798b2017-11-16 16:58:02 -0800447 return X509_cmp(x509_, other.x509_) == 0;
hbos6b470a92016-04-28 05:14:21 -0700448}
449
450bool OpenSSLCertificate::operator!=(const OpenSSLCertificate& other) const {
451 return !(*this == other);
452}
453
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100454// Documented in sslidentity.h.
455int64_t OpenSSLCertificate::CertificateExpirationTime() const {
456 ASN1_TIME* expire_time = X509_get_notAfter(x509_);
457 bool long_format;
458
459 if (expire_time->type == V_ASN1_UTCTIME) {
460 long_format = false;
461 } else if (expire_time->type == V_ASN1_GENERALIZEDTIME) {
462 long_format = true;
463 } else {
464 return -1;
465 }
466
467 return ASN1TimeToSec(expire_time->data, expire_time->length, long_format);
468}
469
Jian Cui0a8798b2017-11-16 16:58:02 -0800470OpenSSLIdentity::OpenSSLIdentity(
471 std::unique_ptr<OpenSSLKeyPair> key_pair,
472 std::unique_ptr<OpenSSLCertificate> certificate)
473 : key_pair_(std::move(key_pair)) {
474 RTC_DCHECK(key_pair_ != nullptr);
deadbeef37f5ecf2017-02-27 14:06:41 -0800475 RTC_DCHECK(certificate != nullptr);
Jian Cui0a8798b2017-11-16 16:58:02 -0800476 std::vector<std::unique_ptr<SSLCertificate>> certs;
477 certs.push_back(std::move(certificate));
478 cert_chain_.reset(new SSLCertChain(std::move(certs)));
479}
480
481OpenSSLIdentity::OpenSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,
482 std::unique_ptr<SSLCertChain> cert_chain)
483 : key_pair_(std::move(key_pair)), cert_chain_(std::move(cert_chain)) {
484 RTC_DCHECK(key_pair_ != nullptr);
485 RTC_DCHECK(cert_chain_ != nullptr);
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000486}
487
488OpenSSLIdentity::~OpenSSLIdentity() = default;
489
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000490OpenSSLIdentity* OpenSSLIdentity::GenerateInternal(
491 const SSLIdentityParams& params) {
Jian Cui0a8798b2017-11-16 16:58:02 -0800492 std::unique_ptr<OpenSSLKeyPair> key_pair(
493 OpenSSLKeyPair::Generate(params.key_params));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000494 if (key_pair) {
Jian Cui0a8798b2017-11-16 16:58:02 -0800495 std::unique_ptr<OpenSSLCertificate> certificate(
496 OpenSSLCertificate::Generate(key_pair.get(), params));
497 if (certificate != nullptr)
498 return new OpenSSLIdentity(std::move(key_pair), std::move(certificate));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000499 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100500 RTC_LOG(LS_INFO) << "Identity generation failed";
deadbeef37f5ecf2017-02-27 14:06:41 -0800501 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000502}
503
Torbjorn Granlund1d846b22016-03-31 16:21:04 +0200504OpenSSLIdentity* OpenSSLIdentity::GenerateWithExpiration(
505 const std::string& common_name,
506 const KeyParams& key_params,
507 time_t certificate_lifetime) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000508 SSLIdentityParams params;
torbjorng4e572472015-10-08 09:42:49 -0700509 params.key_params = key_params;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000510 params.common_name = common_name;
deadbeef37f5ecf2017-02-27 14:06:41 -0800511 time_t now = time(nullptr);
Torbjorn Granlund1d846b22016-03-31 16:21:04 +0200512 params.not_before = now + kCertificateWindowInSeconds;
torbjornge8dc0812016-02-15 09:35:54 -0800513 params.not_after = now + certificate_lifetime;
Torbjorn Granlund1d846b22016-03-31 16:21:04 +0200514 if (params.not_before > params.not_after)
515 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000516 return GenerateInternal(params);
517}
518
519OpenSSLIdentity* OpenSSLIdentity::GenerateForTest(
520 const SSLIdentityParams& params) {
521 return GenerateInternal(params);
522}
523
Jian Cui0a8798b2017-11-16 16:58:02 -0800524SSLIdentity* OpenSSLIdentity::FromPEMStrings(const std::string& private_key,
525 const std::string& certificate) {
jbauch555604a2016-04-26 03:13:22 -0700526 std::unique_ptr<OpenSSLCertificate> cert(
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000527 OpenSSLCertificate::FromPEMString(certificate));
528 if (!cert) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100529 RTC_LOG(LS_ERROR) << "Failed to create OpenSSLCertificate from PEM string.";
hbos6b470a92016-04-28 05:14:21 -0700530 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000531 }
532
Jian Cui0a8798b2017-11-16 16:58:02 -0800533 std::unique_ptr<OpenSSLKeyPair> key_pair(
534 OpenSSLKeyPair::FromPrivateKeyPEMString(private_key));
hbos6b470a92016-04-28 05:14:21 -0700535 if (!key_pair) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100536 RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
hbos6b470a92016-04-28 05:14:21 -0700537 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000538 }
539
Jian Cui0a8798b2017-11-16 16:58:02 -0800540 return new OpenSSLIdentity(std::move(key_pair), std::move(cert));
541}
542
543SSLIdentity* OpenSSLIdentity::FromPEMChainStrings(
544 const std::string& private_key,
545 const std::string& certificate_chain) {
546 BIO* bio =
547 BIO_new_mem_buf(certificate_chain.data(), certificate_chain.size());
548 if (!bio)
549 return nullptr;
550 BIO_set_mem_eof_return(bio, 0);
551 std::vector<std::unique_ptr<SSLCertificate>> certs;
552 while (true) {
553 X509* x509 =
554 PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0"));
555 if (x509 == nullptr) {
556 uint32_t err = ERR_peek_error();
557 if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
558 ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
559 break;
560 }
561 RTC_LOG(LS_ERROR) << "Failed to parse certificate from PEM string.";
562 BIO_free(bio);
563 return nullptr;
564 }
565 certs.emplace_back(new OpenSSLCertificate(x509));
566 X509_free(x509);
567 }
568 BIO_free(bio);
569 if (certs.empty()) {
570 RTC_LOG(LS_ERROR) << "Found no certificates in PEM string.";
571 return nullptr;
572 }
573
574 std::unique_ptr<OpenSSLKeyPair> key_pair(
575 OpenSSLKeyPair::FromPrivateKeyPEMString(private_key));
576 if (!key_pair) {
577 RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
578 return nullptr;
579 }
580
581 return new OpenSSLIdentity(std::move(key_pair),
582 MakeUnique<SSLCertChain>(std::move(certs)));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000583}
584
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000585const OpenSSLCertificate& OpenSSLIdentity::certificate() const {
Jian Cui0a8798b2017-11-16 16:58:02 -0800586 return *static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(0));
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000587}
588
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800589const SSLCertChain& OpenSSLIdentity::cert_chain() const {
590 return *cert_chain_.get();
591}
592
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000593OpenSSLIdentity* OpenSSLIdentity::GetReference() const {
Jian Cui0a8798b2017-11-16 16:58:02 -0800594 return new OpenSSLIdentity(WrapUnique(key_pair_->GetReference()),
David Benjaminea84b6b2017-12-01 17:25:45 -0500595 WrapUnique(cert_chain_->Copy()));
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000596}
597
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000598bool OpenSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) {
599 // 1 is the documented success return code.
Jian Cui0a8798b2017-11-16 16:58:02 -0800600 const OpenSSLCertificate* cert = &certificate();
601 if (SSL_CTX_use_certificate(ctx, cert->x509()) != 1 ||
602 SSL_CTX_use_PrivateKey(ctx, key_pair_->pkey()) != 1) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000603 LogSSLErrors("Configuring key and certificate");
604 return false;
605 }
Jian Cui0a8798b2017-11-16 16:58:02 -0800606 // If a chain is available, use it.
607 for (size_t i = 1; i < cert_chain_->GetSize(); ++i) {
608 cert = static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(i));
609 if (SSL_CTX_add1_chain_cert(ctx, cert->x509()) != 1) {
610 LogSSLErrors("Configuring intermediate certificate");
611 return false;
612 }
613 }
614
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000615 return true;
616}
617
hbos6b470a92016-04-28 05:14:21 -0700618std::string OpenSSLIdentity::PrivateKeyToPEMString() const {
619 return key_pair_->PrivateKeyToPEMString();
620}
621
622std::string OpenSSLIdentity::PublicKeyToPEMString() const {
623 return key_pair_->PublicKeyToPEMString();
624}
625
626bool OpenSSLIdentity::operator==(const OpenSSLIdentity& other) const {
627 return *this->key_pair_ == *other.key_pair_ &&
Jian Cui0a8798b2017-11-16 16:58:02 -0800628 this->certificate() == other.certificate();
hbos6b470a92016-04-28 05:14:21 -0700629}
630
631bool OpenSSLIdentity::operator!=(const OpenSSLIdentity& other) const {
632 return !(*this == other);
633}
634
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000635} // namespace rtc