blob: 477a0e61f7ce1c314ba28060866df8a5f18a2740 [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() {
Torbjorn Granlund9adc91d2016-03-24 14:05:06 +0100210#if defined(OPENSSL_IS_BORINGSSL)
Jiayang Liu770cc382015-05-28 15:36:29 -0700211 EVP_PKEY_up_ref(pkey_);
Torbjorn Granlund9adc91d2016-03-24 14:05:06 +0100212#else
213 CRYPTO_add(&pkey_->references, 1, CRYPTO_LOCK_EVP_PKEY);
214#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000215}
216
hbos6b470a92016-04-28 05:14:21 -0700217std::string OpenSSLKeyPair::PrivateKeyToPEMString() const {
218 BIO* temp_memory_bio = BIO_new(BIO_s_mem());
219 if (!temp_memory_bio) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100220 RTC_LOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
hbos6b470a92016-04-28 05:14:21 -0700221 RTC_NOTREACHED();
222 return "";
223 }
Jian Cui0a8798b2017-11-16 16:58:02 -0800224 if (!PEM_write_bio_PrivateKey(temp_memory_bio, pkey_, nullptr, nullptr, 0,
225 nullptr, nullptr)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100226 RTC_LOG_F(LS_ERROR) << "Failed to write private key";
hbos6b470a92016-04-28 05:14:21 -0700227 BIO_free(temp_memory_bio);
228 RTC_NOTREACHED();
229 return "";
230 }
231 BIO_write(temp_memory_bio, "\0", 1);
232 char* buffer;
233 BIO_get_mem_data(temp_memory_bio, &buffer);
234 std::string priv_key_str = buffer;
235 BIO_free(temp_memory_bio);
236 return priv_key_str;
237}
238
239std::string OpenSSLKeyPair::PublicKeyToPEMString() const {
240 BIO* temp_memory_bio = BIO_new(BIO_s_mem());
241 if (!temp_memory_bio) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100242 RTC_LOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
hbos6b470a92016-04-28 05:14:21 -0700243 RTC_NOTREACHED();
244 return "";
245 }
246 if (!PEM_write_bio_PUBKEY(temp_memory_bio, pkey_)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100247 RTC_LOG_F(LS_ERROR) << "Failed to write public key";
hbos6b470a92016-04-28 05:14:21 -0700248 BIO_free(temp_memory_bio);
249 RTC_NOTREACHED();
250 return "";
251 }
252 BIO_write(temp_memory_bio, "\0", 1);
253 char* buffer;
254 BIO_get_mem_data(temp_memory_bio, &buffer);
255 std::string pub_key_str = buffer;
256 BIO_free(temp_memory_bio);
257 return pub_key_str;
258}
259
260bool OpenSSLKeyPair::operator==(const OpenSSLKeyPair& other) const {
261 return EVP_PKEY_cmp(this->pkey_, other.pkey_) == 1;
262}
263
264bool OpenSSLKeyPair::operator!=(const OpenSSLKeyPair& other) const {
265 return !(*this == other);
266}
267
tfarinaa41ab932015-10-30 16:08:48 -0700268#if !defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000269// Print a certificate to the log, for debugging.
270static void PrintCert(X509* x509) {
271 BIO* temp_memory_bio = BIO_new(BIO_s_mem());
272 if (!temp_memory_bio) {
Jonas Olssonaddc3802018-02-01 09:53:06 +0100273 RTC_DLOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000274 return;
275 }
276 X509_print_ex(temp_memory_bio, x509, XN_FLAG_SEP_CPLUS_SPC, 0);
277 BIO_write(temp_memory_bio, "\0", 1);
278 char* buffer;
279 BIO_get_mem_data(temp_memory_bio, &buffer);
Jonas Olssonaddc3802018-02-01 09:53:06 +0100280 RTC_DLOG(LS_VERBOSE) << buffer;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000281 BIO_free(temp_memory_bio);
282}
283#endif
284
Jian Cui0a8798b2017-11-16 16:58:02 -0800285OpenSSLCertificate::OpenSSLCertificate(X509* x509) : x509_(x509) {
286 AddReference();
287}
288
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000289OpenSSLCertificate* OpenSSLCertificate::Generate(
Jian Cui0a8798b2017-11-16 16:58:02 -0800290 OpenSSLKeyPair* key_pair,
291 const SSLIdentityParams& params) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000292 SSLIdentityParams actual_params(params);
293 if (actual_params.common_name.empty()) {
294 // Use a random string, arbitrarily 8chars long.
295 actual_params.common_name = CreateRandomString(8);
296 }
297 X509* x509 = MakeCertificate(key_pair->pkey(), actual_params);
298 if (!x509) {
299 LogSSLErrors("Generating certificate");
deadbeef37f5ecf2017-02-27 14:06:41 -0800300 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000301 }
tfarinaa41ab932015-10-30 16:08:48 -0700302#if !defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000303 PrintCert(x509);
304#endif
305 OpenSSLCertificate* ret = new OpenSSLCertificate(x509);
306 X509_free(x509);
307 return ret;
308}
309
310OpenSSLCertificate* OpenSSLCertificate::FromPEMString(
311 const std::string& pem_string) {
312 BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1);
313 if (!bio)
deadbeef37f5ecf2017-02-27 14:06:41 -0800314 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000315 BIO_set_mem_eof_return(bio, 0);
deadbeef37f5ecf2017-02-27 14:06:41 -0800316 X509* x509 =
317 PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0"));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000318 BIO_free(bio); // Frees the BIO, but not the pointed-to string.
319
320 if (!x509)
deadbeef37f5ecf2017-02-27 14:06:41 -0800321 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000322
323 OpenSSLCertificate* ret = new OpenSSLCertificate(x509);
324 X509_free(x509);
325 return ret;
326}
327
328// NOTE: This implementation only functions correctly after InitializeSSL
329// and before CleanupSSL.
330bool OpenSSLCertificate::GetSignatureDigestAlgorithm(
331 std::string* algorithm) const {
JiaYang (佳扬) Liu01aeaee2015-04-22 12:18:33 -0700332 int nid = OBJ_obj2nid(x509_->sig_alg->algorithm);
333 switch (nid) {
334 case NID_md5WithRSA:
335 case NID_md5WithRSAEncryption:
336 *algorithm = DIGEST_MD5;
337 break;
338 case NID_ecdsa_with_SHA1:
339 case NID_dsaWithSHA1:
340 case NID_dsaWithSHA1_2:
341 case NID_sha1WithRSA:
342 case NID_sha1WithRSAEncryption:
343 *algorithm = DIGEST_SHA_1;
344 break;
345 case NID_ecdsa_with_SHA224:
346 case NID_sha224WithRSAEncryption:
347 case NID_dsa_with_SHA224:
348 *algorithm = DIGEST_SHA_224;
349 break;
350 case NID_ecdsa_with_SHA256:
351 case NID_sha256WithRSAEncryption:
352 case NID_dsa_with_SHA256:
353 *algorithm = DIGEST_SHA_256;
354 break;
355 case NID_ecdsa_with_SHA384:
356 case NID_sha384WithRSAEncryption:
357 *algorithm = DIGEST_SHA_384;
358 break;
359 case NID_ecdsa_with_SHA512:
360 case NID_sha512WithRSAEncryption:
361 *algorithm = DIGEST_SHA_512;
362 break;
363 default:
364 // Unknown algorithm. There are several unhandled options that are less
365 // common and more complex.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100366 RTC_LOG(LS_ERROR) << "Unknown signature algorithm NID: " << nid;
JiaYang (佳扬) Liu01aeaee2015-04-22 12:18:33 -0700367 algorithm->clear();
368 return false;
369 }
370 return true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000371}
372
jbauch555604a2016-04-26 03:13:22 -0700373std::unique_ptr<SSLCertChain> OpenSSLCertificate::GetChain() const {
kwibergf5d47862016-03-15 12:53:24 -0700374 return nullptr;
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000375}
376
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000377bool OpenSSLCertificate::ComputeDigest(const std::string& algorithm,
378 unsigned char* digest,
379 size_t size,
380 size_t* length) const {
381 return ComputeDigest(x509_, algorithm, digest, size, length);
382}
383
384bool OpenSSLCertificate::ComputeDigest(const X509* x509,
385 const std::string& algorithm,
386 unsigned char* digest,
387 size_t size,
388 size_t* length) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200389 const EVP_MD* md;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000390 unsigned int n;
391
392 if (!OpenSSLDigest::GetDigestEVP(algorithm, &md))
393 return false;
394
395 if (size < static_cast<size_t>(EVP_MD_size(md)))
396 return false;
397
398 X509_digest(x509, md, digest, &n);
399
400 *length = n;
401
402 return true;
403}
404
405OpenSSLCertificate::~OpenSSLCertificate() {
406 X509_free(x509_);
407}
408
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000409OpenSSLCertificate* OpenSSLCertificate::GetReference() const {
410 return new OpenSSLCertificate(x509_);
411}
412
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000413std::string OpenSSLCertificate::ToPEMString() const {
414 BIO* bio = BIO_new(BIO_s_mem());
415 if (!bio) {
andrew@webrtc.orga5b78692014-08-28 16:28:26 +0000416 FATAL() << "unreachable code";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000417 }
418 if (!PEM_write_bio_X509(bio, x509_)) {
419 BIO_free(bio);
andrew@webrtc.orga5b78692014-08-28 16:28:26 +0000420 FATAL() << "unreachable code";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000421 }
422 BIO_write(bio, "\0", 1);
423 char* buffer;
424 BIO_get_mem_data(bio, &buffer);
425 std::string ret(buffer);
426 BIO_free(bio);
427 return ret;
428}
429
430void OpenSSLCertificate::ToDER(Buffer* der_buffer) const {
431 // In case of failure, make sure to leave the buffer empty.
Karl Wiberg94784372015-04-20 14:03:07 +0200432 der_buffer->SetSize(0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000433
434 // Calculates the DER representation of the certificate, from scratch.
435 BIO* bio = BIO_new(BIO_s_mem());
436 if (!bio) {
andrew@webrtc.orga5b78692014-08-28 16:28:26 +0000437 FATAL() << "unreachable code";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000438 }
439 if (!i2d_X509_bio(bio, x509_)) {
440 BIO_free(bio);
andrew@webrtc.orga5b78692014-08-28 16:28:26 +0000441 FATAL() << "unreachable code";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000442 }
443 char* data;
444 size_t length = BIO_get_mem_data(bio, &data);
445 der_buffer->SetData(data, length);
446 BIO_free(bio);
447}
448
449void OpenSSLCertificate::AddReference() const {
deadbeef37f5ecf2017-02-27 14:06:41 -0800450 RTC_DCHECK(x509_ != nullptr);
Torbjorn Granlund9adc91d2016-03-24 14:05:06 +0100451#if defined(OPENSSL_IS_BORINGSSL)
Jiayang Liu770cc382015-05-28 15:36:29 -0700452 X509_up_ref(x509_);
Torbjorn Granlund9adc91d2016-03-24 14:05:06 +0100453#else
454 CRYPTO_add(&x509_->references, 1, CRYPTO_LOCK_X509);
455#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000456}
457
hbos6b470a92016-04-28 05:14:21 -0700458bool OpenSSLCertificate::operator==(const OpenSSLCertificate& other) const {
Jian Cui0a8798b2017-11-16 16:58:02 -0800459 return X509_cmp(x509_, other.x509_) == 0;
hbos6b470a92016-04-28 05:14:21 -0700460}
461
462bool OpenSSLCertificate::operator!=(const OpenSSLCertificate& other) const {
463 return !(*this == other);
464}
465
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100466// Documented in sslidentity.h.
467int64_t OpenSSLCertificate::CertificateExpirationTime() const {
468 ASN1_TIME* expire_time = X509_get_notAfter(x509_);
469 bool long_format;
470
471 if (expire_time->type == V_ASN1_UTCTIME) {
472 long_format = false;
473 } else if (expire_time->type == V_ASN1_GENERALIZEDTIME) {
474 long_format = true;
475 } else {
476 return -1;
477 }
478
479 return ASN1TimeToSec(expire_time->data, expire_time->length, long_format);
480}
481
Jian Cui0a8798b2017-11-16 16:58:02 -0800482OpenSSLIdentity::OpenSSLIdentity(
483 std::unique_ptr<OpenSSLKeyPair> key_pair,
484 std::unique_ptr<OpenSSLCertificate> certificate)
485 : key_pair_(std::move(key_pair)) {
486 RTC_DCHECK(key_pair_ != nullptr);
deadbeef37f5ecf2017-02-27 14:06:41 -0800487 RTC_DCHECK(certificate != nullptr);
Jian Cui0a8798b2017-11-16 16:58:02 -0800488 std::vector<std::unique_ptr<SSLCertificate>> certs;
489 certs.push_back(std::move(certificate));
490 cert_chain_.reset(new SSLCertChain(std::move(certs)));
491}
492
493OpenSSLIdentity::OpenSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,
494 std::unique_ptr<SSLCertChain> cert_chain)
495 : key_pair_(std::move(key_pair)), cert_chain_(std::move(cert_chain)) {
496 RTC_DCHECK(key_pair_ != nullptr);
497 RTC_DCHECK(cert_chain_ != nullptr);
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000498}
499
500OpenSSLIdentity::~OpenSSLIdentity() = default;
501
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000502OpenSSLIdentity* OpenSSLIdentity::GenerateInternal(
503 const SSLIdentityParams& params) {
Jian Cui0a8798b2017-11-16 16:58:02 -0800504 std::unique_ptr<OpenSSLKeyPair> key_pair(
505 OpenSSLKeyPair::Generate(params.key_params));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000506 if (key_pair) {
Jian Cui0a8798b2017-11-16 16:58:02 -0800507 std::unique_ptr<OpenSSLCertificate> certificate(
508 OpenSSLCertificate::Generate(key_pair.get(), params));
509 if (certificate != nullptr)
510 return new OpenSSLIdentity(std::move(key_pair), std::move(certificate));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000511 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100512 RTC_LOG(LS_INFO) << "Identity generation failed";
deadbeef37f5ecf2017-02-27 14:06:41 -0800513 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000514}
515
Torbjorn Granlund1d846b22016-03-31 16:21:04 +0200516OpenSSLIdentity* OpenSSLIdentity::GenerateWithExpiration(
517 const std::string& common_name,
518 const KeyParams& key_params,
519 time_t certificate_lifetime) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000520 SSLIdentityParams params;
torbjorng4e572472015-10-08 09:42:49 -0700521 params.key_params = key_params;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000522 params.common_name = common_name;
deadbeef37f5ecf2017-02-27 14:06:41 -0800523 time_t now = time(nullptr);
Torbjorn Granlund1d846b22016-03-31 16:21:04 +0200524 params.not_before = now + kCertificateWindowInSeconds;
torbjornge8dc0812016-02-15 09:35:54 -0800525 params.not_after = now + certificate_lifetime;
Torbjorn Granlund1d846b22016-03-31 16:21:04 +0200526 if (params.not_before > params.not_after)
527 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000528 return GenerateInternal(params);
529}
530
531OpenSSLIdentity* OpenSSLIdentity::GenerateForTest(
532 const SSLIdentityParams& params) {
533 return GenerateInternal(params);
534}
535
Jian Cui0a8798b2017-11-16 16:58:02 -0800536SSLIdentity* OpenSSLIdentity::FromPEMStrings(const std::string& private_key,
537 const std::string& certificate) {
jbauch555604a2016-04-26 03:13:22 -0700538 std::unique_ptr<OpenSSLCertificate> cert(
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000539 OpenSSLCertificate::FromPEMString(certificate));
540 if (!cert) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100541 RTC_LOG(LS_ERROR) << "Failed to create OpenSSLCertificate from PEM string.";
hbos6b470a92016-04-28 05:14:21 -0700542 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000543 }
544
Jian Cui0a8798b2017-11-16 16:58:02 -0800545 std::unique_ptr<OpenSSLKeyPair> key_pair(
546 OpenSSLKeyPair::FromPrivateKeyPEMString(private_key));
hbos6b470a92016-04-28 05:14:21 -0700547 if (!key_pair) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100548 RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
hbos6b470a92016-04-28 05:14:21 -0700549 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000550 }
551
Jian Cui0a8798b2017-11-16 16:58:02 -0800552 return new OpenSSLIdentity(std::move(key_pair), std::move(cert));
553}
554
555SSLIdentity* OpenSSLIdentity::FromPEMChainStrings(
556 const std::string& private_key,
557 const std::string& certificate_chain) {
558 BIO* bio =
559 BIO_new_mem_buf(certificate_chain.data(), certificate_chain.size());
560 if (!bio)
561 return nullptr;
562 BIO_set_mem_eof_return(bio, 0);
563 std::vector<std::unique_ptr<SSLCertificate>> certs;
564 while (true) {
565 X509* x509 =
566 PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0"));
567 if (x509 == nullptr) {
568 uint32_t err = ERR_peek_error();
569 if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
570 ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
571 break;
572 }
573 RTC_LOG(LS_ERROR) << "Failed to parse certificate from PEM string.";
574 BIO_free(bio);
575 return nullptr;
576 }
577 certs.emplace_back(new OpenSSLCertificate(x509));
578 X509_free(x509);
579 }
580 BIO_free(bio);
581 if (certs.empty()) {
582 RTC_LOG(LS_ERROR) << "Found no certificates in PEM string.";
583 return nullptr;
584 }
585
586 std::unique_ptr<OpenSSLKeyPair> key_pair(
587 OpenSSLKeyPair::FromPrivateKeyPEMString(private_key));
588 if (!key_pair) {
589 RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
590 return nullptr;
591 }
592
593 return new OpenSSLIdentity(std::move(key_pair),
594 MakeUnique<SSLCertChain>(std::move(certs)));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000595}
596
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000597const OpenSSLCertificate& OpenSSLIdentity::certificate() const {
Jian Cui0a8798b2017-11-16 16:58:02 -0800598 return *static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(0));
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000599}
600
601OpenSSLIdentity* OpenSSLIdentity::GetReference() const {
Jian Cui0a8798b2017-11-16 16:58:02 -0800602 return new OpenSSLIdentity(WrapUnique(key_pair_->GetReference()),
David Benjaminea84b6b2017-12-01 17:25:45 -0500603 WrapUnique(cert_chain_->Copy()));
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000604}
605
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000606bool OpenSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) {
607 // 1 is the documented success return code.
Jian Cui0a8798b2017-11-16 16:58:02 -0800608 const OpenSSLCertificate* cert = &certificate();
609 if (SSL_CTX_use_certificate(ctx, cert->x509()) != 1 ||
610 SSL_CTX_use_PrivateKey(ctx, key_pair_->pkey()) != 1) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000611 LogSSLErrors("Configuring key and certificate");
612 return false;
613 }
Jian Cui0a8798b2017-11-16 16:58:02 -0800614 // If a chain is available, use it.
615 for (size_t i = 1; i < cert_chain_->GetSize(); ++i) {
616 cert = static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(i));
617 if (SSL_CTX_add1_chain_cert(ctx, cert->x509()) != 1) {
618 LogSSLErrors("Configuring intermediate certificate");
619 return false;
620 }
621 }
622
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000623 return true;
624}
625
hbos6b470a92016-04-28 05:14:21 -0700626std::string OpenSSLIdentity::PrivateKeyToPEMString() const {
627 return key_pair_->PrivateKeyToPEMString();
628}
629
630std::string OpenSSLIdentity::PublicKeyToPEMString() const {
631 return key_pair_->PublicKeyToPEMString();
632}
633
634bool OpenSSLIdentity::operator==(const OpenSSLIdentity& other) const {
635 return *this->key_pair_ == *other.key_pair_ &&
Jian Cui0a8798b2017-11-16 16:58:02 -0800636 this->certificate() == other.certificate();
hbos6b470a92016-04-28 05:14:21 -0700637}
638
639bool OpenSSLIdentity::operator!=(const OpenSSLIdentity& other) const {
640 return !(*this == other);
641}
642
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000643} // namespace rtc