blob: 531c971816a6b3410e72bf8da0cc1a4c8ab4f956 [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
Steve Anton10542f22019-01-11 09:11:00 -080011#include "rtc_base/openssl_identity.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000012
jbauch555604a2016-04-26 03:13:22 -070013#include <memory>
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070014#include <utility>
15#include <vector>
jbauch555604a2016-04-26 03:13:22 -070016
Mirko Bonadeie0623852018-02-01 11:17:40 +010017#if defined(WEBRTC_WIN)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000018// Must be included first before openssl headers.
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/win32.h" // NOLINT
Yves Gerey665174f2018-06-19 15:03:05 +020020#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000021
22#include <openssl/bio.h>
Jian Cui0a8798b2017-11-16 16:58:02 -080023#include <openssl/bn.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000024#include <openssl/err.h>
25#include <openssl/pem.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026#include <openssl/rsa.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000027
Yves Gerey988cc082018-10-23 12:03:01 +020028#include <stdint.h>
29
Karl Wiberg918f50c2018-07-05 11:40:33 +020030#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "rtc_base/checks.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "rtc_base/logging.h"
Mirko Bonadeia041f922018-05-23 10:22:36 +020033#include "rtc_base/numerics/safe_conversions.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020034#include "rtc_base/openssl.h"
Steve Anton10542f22019-01-11 09:11:00 -080035#include "rtc_base/openssl_utility.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000036
37namespace rtc {
38
39// We could have exposed a myriad of parameters for the crypto stuff,
40// but keeping it simple seems best.
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
torbjorng4e572472015-10-08 09:42:49 -070096OpenSSLKeyPair* OpenSSLKeyPair::Generate(const KeyParams& key_params) {
97 EVP_PKEY* pkey = MakeKey(key_params);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000098 if (!pkey) {
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070099 openssl::LogSSLErrors("Generating key pair");
deadbeef37f5ecf2017-02-27 14:06:41 -0800100 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000101 }
102 return new OpenSSLKeyPair(pkey);
103}
104
hbos6b470a92016-04-28 05:14:21 -0700105OpenSSLKeyPair* OpenSSLKeyPair::FromPrivateKeyPEMString(
106 const std::string& pem_string) {
107 BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1);
108 if (!bio) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100109 RTC_LOG(LS_ERROR) << "Failed to create a new BIO buffer.";
hbos6b470a92016-04-28 05:14:21 -0700110 return nullptr;
111 }
112 BIO_set_mem_eof_return(bio, 0);
113 EVP_PKEY* pkey =
114 PEM_read_bio_PrivateKey(bio, nullptr, nullptr, const_cast<char*>("\0"));
115 BIO_free(bio); // Frees the BIO, but not the pointed-to string.
116 if (!pkey) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100117 RTC_LOG(LS_ERROR) << "Failed to create the private key from PEM string.";
hbos6b470a92016-04-28 05:14:21 -0700118 return nullptr;
119 }
120 if (EVP_PKEY_missing_parameters(pkey) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100121 RTC_LOG(LS_ERROR)
122 << "The resulting key pair is missing public key parameters.";
hbos6b470a92016-04-28 05:14:21 -0700123 EVP_PKEY_free(pkey);
124 return nullptr;
125 }
126 return new OpenSSLKeyPair(pkey);
127}
128
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000129OpenSSLKeyPair::~OpenSSLKeyPair() {
130 EVP_PKEY_free(pkey_);
131}
132
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000133OpenSSLKeyPair* OpenSSLKeyPair::GetReference() {
134 AddReference();
135 return new OpenSSLKeyPair(pkey_);
136}
137
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000138void OpenSSLKeyPair::AddReference() {
Jiayang Liu770cc382015-05-28 15:36:29 -0700139 EVP_PKEY_up_ref(pkey_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000140}
141
hbos6b470a92016-04-28 05:14:21 -0700142std::string OpenSSLKeyPair::PrivateKeyToPEMString() const {
143 BIO* temp_memory_bio = BIO_new(BIO_s_mem());
144 if (!temp_memory_bio) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100145 RTC_LOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
hbos6b470a92016-04-28 05:14:21 -0700146 RTC_NOTREACHED();
147 return "";
148 }
Jian Cui0a8798b2017-11-16 16:58:02 -0800149 if (!PEM_write_bio_PrivateKey(temp_memory_bio, pkey_, nullptr, nullptr, 0,
150 nullptr, nullptr)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100151 RTC_LOG_F(LS_ERROR) << "Failed to write private key";
hbos6b470a92016-04-28 05:14:21 -0700152 BIO_free(temp_memory_bio);
153 RTC_NOTREACHED();
154 return "";
155 }
156 BIO_write(temp_memory_bio, "\0", 1);
157 char* buffer;
158 BIO_get_mem_data(temp_memory_bio, &buffer);
159 std::string priv_key_str = buffer;
160 BIO_free(temp_memory_bio);
161 return priv_key_str;
162}
163
164std::string OpenSSLKeyPair::PublicKeyToPEMString() const {
165 BIO* temp_memory_bio = BIO_new(BIO_s_mem());
166 if (!temp_memory_bio) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100167 RTC_LOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
hbos6b470a92016-04-28 05:14:21 -0700168 RTC_NOTREACHED();
169 return "";
170 }
171 if (!PEM_write_bio_PUBKEY(temp_memory_bio, pkey_)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100172 RTC_LOG_F(LS_ERROR) << "Failed to write public key";
hbos6b470a92016-04-28 05:14:21 -0700173 BIO_free(temp_memory_bio);
174 RTC_NOTREACHED();
175 return "";
176 }
177 BIO_write(temp_memory_bio, "\0", 1);
178 char* buffer;
179 BIO_get_mem_data(temp_memory_bio, &buffer);
180 std::string pub_key_str = buffer;
181 BIO_free(temp_memory_bio);
182 return pub_key_str;
183}
184
185bool OpenSSLKeyPair::operator==(const OpenSSLKeyPair& other) const {
186 return EVP_PKEY_cmp(this->pkey_, other.pkey_) == 1;
187}
188
189bool OpenSSLKeyPair::operator!=(const OpenSSLKeyPair& other) const {
190 return !(*this == other);
191}
192
Jian Cui0a8798b2017-11-16 16:58:02 -0800193OpenSSLIdentity::OpenSSLIdentity(
194 std::unique_ptr<OpenSSLKeyPair> key_pair,
195 std::unique_ptr<OpenSSLCertificate> certificate)
196 : key_pair_(std::move(key_pair)) {
197 RTC_DCHECK(key_pair_ != nullptr);
deadbeef37f5ecf2017-02-27 14:06:41 -0800198 RTC_DCHECK(certificate != nullptr);
Jian Cui0a8798b2017-11-16 16:58:02 -0800199 std::vector<std::unique_ptr<SSLCertificate>> certs;
200 certs.push_back(std::move(certificate));
201 cert_chain_.reset(new SSLCertChain(std::move(certs)));
202}
203
204OpenSSLIdentity::OpenSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,
205 std::unique_ptr<SSLCertChain> cert_chain)
206 : key_pair_(std::move(key_pair)), cert_chain_(std::move(cert_chain)) {
207 RTC_DCHECK(key_pair_ != nullptr);
208 RTC_DCHECK(cert_chain_ != nullptr);
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000209}
210
211OpenSSLIdentity::~OpenSSLIdentity() = default;
212
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000213OpenSSLIdentity* OpenSSLIdentity::GenerateInternal(
214 const SSLIdentityParams& params) {
Jian Cui0a8798b2017-11-16 16:58:02 -0800215 std::unique_ptr<OpenSSLKeyPair> key_pair(
216 OpenSSLKeyPair::Generate(params.key_params));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000217 if (key_pair) {
Jian Cui0a8798b2017-11-16 16:58:02 -0800218 std::unique_ptr<OpenSSLCertificate> certificate(
219 OpenSSLCertificate::Generate(key_pair.get(), params));
220 if (certificate != nullptr)
221 return new OpenSSLIdentity(std::move(key_pair), std::move(certificate));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000222 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100223 RTC_LOG(LS_INFO) << "Identity generation failed";
deadbeef37f5ecf2017-02-27 14:06:41 -0800224 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000225}
226
Torbjorn Granlund1d846b22016-03-31 16:21:04 +0200227OpenSSLIdentity* OpenSSLIdentity::GenerateWithExpiration(
228 const std::string& common_name,
229 const KeyParams& key_params,
230 time_t certificate_lifetime) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000231 SSLIdentityParams params;
torbjorng4e572472015-10-08 09:42:49 -0700232 params.key_params = key_params;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000233 params.common_name = common_name;
deadbeef37f5ecf2017-02-27 14:06:41 -0800234 time_t now = time(nullptr);
Torbjorn Granlund1d846b22016-03-31 16:21:04 +0200235 params.not_before = now + kCertificateWindowInSeconds;
torbjornge8dc0812016-02-15 09:35:54 -0800236 params.not_after = now + certificate_lifetime;
Torbjorn Granlund1d846b22016-03-31 16:21:04 +0200237 if (params.not_before > params.not_after)
238 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000239 return GenerateInternal(params);
240}
241
242OpenSSLIdentity* OpenSSLIdentity::GenerateForTest(
243 const SSLIdentityParams& params) {
244 return GenerateInternal(params);
245}
246
Jian Cui0a8798b2017-11-16 16:58:02 -0800247SSLIdentity* OpenSSLIdentity::FromPEMStrings(const std::string& private_key,
248 const std::string& certificate) {
jbauch555604a2016-04-26 03:13:22 -0700249 std::unique_ptr<OpenSSLCertificate> cert(
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000250 OpenSSLCertificate::FromPEMString(certificate));
251 if (!cert) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100252 RTC_LOG(LS_ERROR) << "Failed to create OpenSSLCertificate from PEM string.";
hbos6b470a92016-04-28 05:14:21 -0700253 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000254 }
255
Jian Cui0a8798b2017-11-16 16:58:02 -0800256 std::unique_ptr<OpenSSLKeyPair> key_pair(
257 OpenSSLKeyPair::FromPrivateKeyPEMString(private_key));
hbos6b470a92016-04-28 05:14:21 -0700258 if (!key_pair) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100259 RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
hbos6b470a92016-04-28 05:14:21 -0700260 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000261 }
262
Jian Cui0a8798b2017-11-16 16:58:02 -0800263 return new OpenSSLIdentity(std::move(key_pair), std::move(cert));
264}
265
266SSLIdentity* OpenSSLIdentity::FromPEMChainStrings(
267 const std::string& private_key,
268 const std::string& certificate_chain) {
Yves Gerey665174f2018-06-19 15:03:05 +0200269 BIO* bio = BIO_new_mem_buf(certificate_chain.data(),
270 rtc::dchecked_cast<int>(certificate_chain.size()));
Jian Cui0a8798b2017-11-16 16:58:02 -0800271 if (!bio)
272 return nullptr;
273 BIO_set_mem_eof_return(bio, 0);
274 std::vector<std::unique_ptr<SSLCertificate>> certs;
275 while (true) {
276 X509* x509 =
277 PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0"));
278 if (x509 == nullptr) {
279 uint32_t err = ERR_peek_error();
280 if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
281 ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
282 break;
283 }
284 RTC_LOG(LS_ERROR) << "Failed to parse certificate from PEM string.";
285 BIO_free(bio);
286 return nullptr;
287 }
288 certs.emplace_back(new OpenSSLCertificate(x509));
289 X509_free(x509);
290 }
291 BIO_free(bio);
292 if (certs.empty()) {
293 RTC_LOG(LS_ERROR) << "Found no certificates in PEM string.";
294 return nullptr;
295 }
296
297 std::unique_ptr<OpenSSLKeyPair> key_pair(
298 OpenSSLKeyPair::FromPrivateKeyPEMString(private_key));
299 if (!key_pair) {
300 RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
301 return nullptr;
302 }
303
304 return new OpenSSLIdentity(std::move(key_pair),
Karl Wiberg918f50c2018-07-05 11:40:33 +0200305 absl::make_unique<SSLCertChain>(std::move(certs)));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000306}
307
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000308const OpenSSLCertificate& OpenSSLIdentity::certificate() const {
Jian Cui0a8798b2017-11-16 16:58:02 -0800309 return *static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(0));
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000310}
311
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800312const SSLCertChain& OpenSSLIdentity::cert_chain() const {
313 return *cert_chain_.get();
314}
315
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000316OpenSSLIdentity* OpenSSLIdentity::GetReference() const {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200317 return new OpenSSLIdentity(absl::WrapUnique(key_pair_->GetReference()),
Steve Antonf25303e2018-10-16 15:23:31 -0700318 cert_chain_->Clone());
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000319}
320
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000321bool OpenSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) {
322 // 1 is the documented success return code.
Jian Cui0a8798b2017-11-16 16:58:02 -0800323 const OpenSSLCertificate* cert = &certificate();
324 if (SSL_CTX_use_certificate(ctx, cert->x509()) != 1 ||
325 SSL_CTX_use_PrivateKey(ctx, key_pair_->pkey()) != 1) {
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700326 openssl::LogSSLErrors("Configuring key and certificate");
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000327 return false;
328 }
Jian Cui0a8798b2017-11-16 16:58:02 -0800329 // If a chain is available, use it.
330 for (size_t i = 1; i < cert_chain_->GetSize(); ++i) {
331 cert = static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(i));
332 if (SSL_CTX_add1_chain_cert(ctx, cert->x509()) != 1) {
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700333 openssl::LogSSLErrors("Configuring intermediate certificate");
Jian Cui0a8798b2017-11-16 16:58:02 -0800334 return false;
335 }
336 }
337
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000338 return true;
339}
340
hbos6b470a92016-04-28 05:14:21 -0700341std::string OpenSSLIdentity::PrivateKeyToPEMString() const {
342 return key_pair_->PrivateKeyToPEMString();
343}
344
345std::string OpenSSLIdentity::PublicKeyToPEMString() const {
346 return key_pair_->PublicKeyToPEMString();
347}
348
349bool OpenSSLIdentity::operator==(const OpenSSLIdentity& other) const {
350 return *this->key_pair_ == *other.key_pair_ &&
Jian Cui0a8798b2017-11-16 16:58:02 -0800351 this->certificate() == other.certificate();
hbos6b470a92016-04-28 05:14:21 -0700352}
353
354bool OpenSSLIdentity::operator!=(const OpenSSLIdentity& other) const {
355 return !(*this == other);
356}
357
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000358} // namespace rtc