blob: a4b8591d91776051da57729d8475183644bf769c [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:261/*
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 17:11:0011#include "rtc_base/openssl_identity.h"
henrike@webrtc.orgf0488722014-05-13 18:00:2612
jbauch555604a2016-04-26 10:13:2213#include <memory>
Benjamin Wrightd6f86e82018-05-08 20:12:2514#include <utility>
15#include <vector>
jbauch555604a2016-04-26 10:13:2216
Mirko Bonadeie0623852018-02-01 10:17:4017#if defined(WEBRTC_WIN)
henrike@webrtc.orgf0488722014-05-13 18:00:2618// Must be included first before openssl headers.
Mirko Bonadei92ea95e2017-09-15 04:47:3119#include "rtc_base/win32.h" // NOLINT
Yves Gerey665174f2018-06-19 13:03:0520#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:2621
22#include <openssl/bio.h>
23#include <openssl/err.h>
24#include <openssl/pem.h>
Yves Gerey988cc082018-10-23 10:03:0125#include <stdint.h>
26
Karl Wiberg918f50c2018-07-05 09:40:3327#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3128#include "rtc_base/checks.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3129#include "rtc_base/logging.h"
Mirko Bonadeia041f922018-05-23 08:22:3630#include "rtc_base/numerics/safe_conversions.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3131#include "rtc_base/openssl.h"
Steve Anton10542f22019-01-11 17:11:0032#include "rtc_base/openssl_utility.h"
henrike@webrtc.orgf0488722014-05-13 18:00:2633
34namespace rtc {
35
Jian Cui0a8798b2017-11-17 00:58:0236OpenSSLIdentity::OpenSSLIdentity(
37 std::unique_ptr<OpenSSLKeyPair> key_pair,
38 std::unique_ptr<OpenSSLCertificate> certificate)
39 : key_pair_(std::move(key_pair)) {
40 RTC_DCHECK(key_pair_ != nullptr);
deadbeef37f5ecf2017-02-27 22:06:4141 RTC_DCHECK(certificate != nullptr);
Jian Cui0a8798b2017-11-17 00:58:0242 std::vector<std::unique_ptr<SSLCertificate>> certs;
43 certs.push_back(std::move(certificate));
44 cert_chain_.reset(new SSLCertChain(std::move(certs)));
45}
46
47OpenSSLIdentity::OpenSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,
48 std::unique_ptr<SSLCertChain> cert_chain)
49 : key_pair_(std::move(key_pair)), cert_chain_(std::move(cert_chain)) {
50 RTC_DCHECK(key_pair_ != nullptr);
51 RTC_DCHECK(cert_chain_ != nullptr);
kwiberg@webrtc.org67186fe2015-03-09 22:21:5352}
53
54OpenSSLIdentity::~OpenSSLIdentity() = default;
55
Harald Alvestrand8515d5a2020-03-20 21:51:3256std::unique_ptr<OpenSSLIdentity> OpenSSLIdentity::CreateInternal(
henrike@webrtc.orgf0488722014-05-13 18:00:2657 const SSLIdentityParams& params) {
Taylor Brandstetter165c6182020-12-11 00:23:0358 auto key_pair = OpenSSLKeyPair::Generate(params.key_params);
henrike@webrtc.orgf0488722014-05-13 18:00:2659 if (key_pair) {
Jian Cui0a8798b2017-11-17 00:58:0260 std::unique_ptr<OpenSSLCertificate> certificate(
61 OpenSSLCertificate::Generate(key_pair.get(), params));
Harald Alvestrand8515d5a2020-03-20 21:51:3262 if (certificate != nullptr) {
63 return absl::WrapUnique(
64 new OpenSSLIdentity(std::move(key_pair), std::move(certificate)));
65 }
henrike@webrtc.orgf0488722014-05-13 18:00:2666 }
Taylor Brandstetter165c6182020-12-11 00:23:0367 RTC_LOG(LS_ERROR) << "Identity generation failed";
deadbeef37f5ecf2017-02-27 22:06:4168 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:2669}
70
Harald Alvestrand8515d5a2020-03-20 21:51:3271// static
72std::unique_ptr<OpenSSLIdentity> OpenSSLIdentity::CreateWithExpiration(
Ali Tofigh58d861c2022-03-24 23:51:2073 absl::string_view common_name,
Torbjorn Granlund1d846b22016-03-31 14:21:0474 const KeyParams& key_params,
75 time_t certificate_lifetime) {
henrike@webrtc.orgf0488722014-05-13 18:00:2676 SSLIdentityParams params;
torbjorng4e572472015-10-08 16:42:4977 params.key_params = key_params;
Ali Tofigh58d861c2022-03-24 23:51:2078 params.common_name = std::string(common_name);
deadbeef37f5ecf2017-02-27 22:06:4179 time_t now = time(nullptr);
Torbjorn Granlund1d846b22016-03-31 14:21:0480 params.not_before = now + kCertificateWindowInSeconds;
torbjornge8dc0812016-02-15 17:35:5481 params.not_after = now + certificate_lifetime;
Philipp Hanckecfd83742024-08-09 18:56:3382 if (params.not_before > params.not_after) {
83 RTC_LOG(LS_ERROR)
84 << "Іdentity generated failed, not_before is after not_after.";
Torbjorn Granlund1d846b22016-03-31 14:21:0485 return nullptr;
Philipp Hanckecfd83742024-08-09 18:56:3386 }
Harald Alvestrand8515d5a2020-03-20 21:51:3287 return CreateInternal(params);
88}
89
Harald Alvestrand8515d5a2020-03-20 21:51:3290std::unique_ptr<OpenSSLIdentity> OpenSSLIdentity::CreateForTest(
91 const SSLIdentityParams& params) {
92 return CreateInternal(params);
henrike@webrtc.orgf0488722014-05-13 18:00:2693}
94
Harald Alvestrand8515d5a2020-03-20 21:51:3295std::unique_ptr<SSLIdentity> OpenSSLIdentity::CreateFromPEMStrings(
Ali Tofigh58d861c2022-03-24 23:51:2096 absl::string_view private_key,
97 absl::string_view certificate) {
jbauch555604a2016-04-26 10:13:2298 std::unique_ptr<OpenSSLCertificate> cert(
henrike@webrtc.orgf0488722014-05-13 18:00:2699 OpenSSLCertificate::FromPEMString(certificate));
100 if (!cert) {
Mirko Bonadei675513b2017-11-09 10:09:25101 RTC_LOG(LS_ERROR) << "Failed to create OpenSSLCertificate from PEM string.";
hbos6b470a92016-04-28 12:14:21102 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26103 }
104
Taylor Brandstetter165c6182020-12-11 00:23:03105 auto key_pair = OpenSSLKeyPair::FromPrivateKeyPEMString(private_key);
hbos6b470a92016-04-28 12:14:21106 if (!key_pair) {
Mirko Bonadei675513b2017-11-09 10:09:25107 RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
hbos6b470a92016-04-28 12:14:21108 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26109 }
110
Harald Alvestrand8515d5a2020-03-20 21:51:32111 return absl::WrapUnique(
112 new OpenSSLIdentity(std::move(key_pair), std::move(cert)));
Jian Cui0a8798b2017-11-17 00:58:02113}
114
Harald Alvestrand8515d5a2020-03-20 21:51:32115std::unique_ptr<SSLIdentity> OpenSSLIdentity::CreateFromPEMChainStrings(
Ali Tofigh58d861c2022-03-24 23:51:20116 absl::string_view private_key,
117 absl::string_view certificate_chain) {
Yves Gerey665174f2018-06-19 13:03:05118 BIO* bio = BIO_new_mem_buf(certificate_chain.data(),
119 rtc::dchecked_cast<int>(certificate_chain.size()));
Jian Cui0a8798b2017-11-17 00:58:02120 if (!bio)
121 return nullptr;
122 BIO_set_mem_eof_return(bio, 0);
123 std::vector<std::unique_ptr<SSLCertificate>> certs;
124 while (true) {
125 X509* x509 =
126 PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0"));
127 if (x509 == nullptr) {
128 uint32_t err = ERR_peek_error();
129 if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
130 ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
Philipp Hancked79a1852024-09-09 20:39:05131 err = ERR_get_error();
Jian Cui0a8798b2017-11-17 00:58:02132 break;
133 }
Philipp Hanckecfd83742024-08-09 18:56:33134 RTC_LOG(LS_ERROR) << "Failed to parse certificate from PEM string: "
135 << ERR_reason_error_string(err);
Jian Cui0a8798b2017-11-17 00:58:02136 BIO_free(bio);
137 return nullptr;
138 }
139 certs.emplace_back(new OpenSSLCertificate(x509));
140 X509_free(x509);
141 }
142 BIO_free(bio);
143 if (certs.empty()) {
144 RTC_LOG(LS_ERROR) << "Found no certificates in PEM string.";
145 return nullptr;
146 }
147
Taylor Brandstetter165c6182020-12-11 00:23:03148 auto key_pair = OpenSSLKeyPair::FromPrivateKeyPEMString(private_key);
Jian Cui0a8798b2017-11-17 00:58:02149 if (!key_pair) {
150 RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
151 return nullptr;
152 }
153
Harald Alvestrand8515d5a2020-03-20 21:51:32154 return absl::WrapUnique(new OpenSSLIdentity(
155 std::move(key_pair), std::make_unique<SSLCertChain>(std::move(certs))));
156}
157
kwiberg@webrtc.org67186fe2015-03-09 22:21:53158const OpenSSLCertificate& OpenSSLIdentity::certificate() const {
Jian Cui0a8798b2017-11-17 00:58:02159 return *static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(0));
kwiberg@webrtc.org67186fe2015-03-09 22:21:53160}
161
Taylor Brandstetterc3928662018-02-23 21:04:51162const SSLCertChain& OpenSSLIdentity::cert_chain() const {
163 return *cert_chain_.get();
164}
165
Harald Alvestrand8515d5a2020-03-20 21:51:32166std::unique_ptr<SSLIdentity> OpenSSLIdentity::CloneInternal() const {
167 // We cannot use std::make_unique here because the referenced OpenSSLIdentity
168 // constructor is private.
Taylor Brandstetter165c6182020-12-11 00:23:03169 return absl::WrapUnique(
170 new OpenSSLIdentity(key_pair_->Clone(), cert_chain_->Clone()));
kwiberg@webrtc.org67186fe2015-03-09 22:21:53171}
172
henrike@webrtc.orgf0488722014-05-13 18:00:26173bool OpenSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) {
174 // 1 is the documented success return code.
Jian Cui0a8798b2017-11-17 00:58:02175 const OpenSSLCertificate* cert = &certificate();
176 if (SSL_CTX_use_certificate(ctx, cert->x509()) != 1 ||
177 SSL_CTX_use_PrivateKey(ctx, key_pair_->pkey()) != 1) {
Benjamin Wrightd6f86e82018-05-08 20:12:25178 openssl::LogSSLErrors("Configuring key and certificate");
henrike@webrtc.orgf0488722014-05-13 18:00:26179 return false;
180 }
Jian Cui0a8798b2017-11-17 00:58:02181 // If a chain is available, use it.
182 for (size_t i = 1; i < cert_chain_->GetSize(); ++i) {
183 cert = static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(i));
184 if (SSL_CTX_add1_chain_cert(ctx, cert->x509()) != 1) {
Benjamin Wrightd6f86e82018-05-08 20:12:25185 openssl::LogSSLErrors("Configuring intermediate certificate");
Jian Cui0a8798b2017-11-17 00:58:02186 return false;
187 }
188 }
189
henrike@webrtc.orgf0488722014-05-13 18:00:26190 return true;
191}
192
hbos6b470a92016-04-28 12:14:21193std::string OpenSSLIdentity::PrivateKeyToPEMString() const {
194 return key_pair_->PrivateKeyToPEMString();
195}
196
197std::string OpenSSLIdentity::PublicKeyToPEMString() const {
198 return key_pair_->PublicKeyToPEMString();
199}
200
201bool OpenSSLIdentity::operator==(const OpenSSLIdentity& other) const {
202 return *this->key_pair_ == *other.key_pair_ &&
Jian Cui0a8798b2017-11-17 00:58:02203 this->certificate() == other.certificate();
hbos6b470a92016-04-28 12:14:21204}
205
206bool OpenSSLIdentity::operator!=(const OpenSSLIdentity& other) const {
207 return !(*this == other);
208}
209
henrike@webrtc.orgf0488722014-05-13 18:00:26210} // namespace rtc