blob: d22c8ce529b9acceb322e858735172a3c80c4be0 [file] [log] [blame]
Taylor Brandstetter165c6182020-12-10 16:23:03 -08001/*
2 * Copyright 2020 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
11#include "rtc_base/boringssl_identity.h"
12
13#include <openssl/bio.h>
14#include <openssl/err.h>
15#include <openssl/pem.h>
16#include <openssl/pool.h>
17#include <stdint.h>
18#include <string.h>
19
20#include <memory>
21#include <utility>
22#include <vector>
23
24#include "absl/memory/memory.h"
25#include "rtc_base/checks.h"
26#include "rtc_base/logging.h"
27#include "rtc_base/numerics/safe_conversions.h"
28#include "rtc_base/openssl.h"
29#include "rtc_base/openssl_utility.h"
30
31namespace rtc {
32
33BoringSSLIdentity::BoringSSLIdentity(
34 std::unique_ptr<OpenSSLKeyPair> key_pair,
35 std::unique_ptr<BoringSSLCertificate> certificate)
36 : key_pair_(std::move(key_pair)) {
37 RTC_DCHECK(key_pair_ != nullptr);
38 RTC_DCHECK(certificate != nullptr);
39 std::vector<std::unique_ptr<SSLCertificate>> certs;
40 certs.push_back(std::move(certificate));
41 cert_chain_.reset(new SSLCertChain(std::move(certs)));
42}
43
44BoringSSLIdentity::BoringSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,
45 std::unique_ptr<SSLCertChain> cert_chain)
46 : key_pair_(std::move(key_pair)), cert_chain_(std::move(cert_chain)) {
47 RTC_DCHECK(key_pair_ != nullptr);
48 RTC_DCHECK(cert_chain_ != nullptr);
49}
50
51BoringSSLIdentity::~BoringSSLIdentity() = default;
52
53std::unique_ptr<BoringSSLIdentity> BoringSSLIdentity::CreateInternal(
54 const SSLIdentityParams& params) {
55 auto key_pair = OpenSSLKeyPair::Generate(params.key_params);
56 if (key_pair) {
57 std::unique_ptr<BoringSSLCertificate> certificate(
58 BoringSSLCertificate::Generate(key_pair.get(), params));
59 if (certificate != nullptr) {
60 return absl::WrapUnique(
61 new BoringSSLIdentity(std::move(key_pair), std::move(certificate)));
62 }
63 }
64 RTC_LOG(LS_ERROR) << "Identity generation failed.";
65 return nullptr;
66}
67
68// static
69std::unique_ptr<BoringSSLIdentity> BoringSSLIdentity::CreateWithExpiration(
70 const std::string& common_name,
71 const KeyParams& key_params,
72 time_t certificate_lifetime) {
73 SSLIdentityParams params;
74 params.key_params = key_params;
75 params.common_name = common_name;
76 time_t now = time(nullptr);
77 params.not_before = now + kCertificateWindowInSeconds;
78 params.not_after = now + certificate_lifetime;
79 if (params.not_before > params.not_after)
80 return nullptr;
81 return CreateInternal(params);
82}
83
84std::unique_ptr<BoringSSLIdentity> BoringSSLIdentity::CreateForTest(
85 const SSLIdentityParams& params) {
86 return CreateInternal(params);
87}
88
89std::unique_ptr<SSLIdentity> BoringSSLIdentity::CreateFromPEMStrings(
90 const std::string& private_key,
91 const std::string& certificate) {
92 std::unique_ptr<BoringSSLCertificate> cert(
93 BoringSSLCertificate::FromPEMString(certificate));
94 if (!cert) {
95 RTC_LOG(LS_ERROR)
96 << "Failed to create BoringSSLCertificate from PEM string.";
97 return nullptr;
98 }
99
100 auto key_pair = OpenSSLKeyPair::FromPrivateKeyPEMString(private_key);
101 if (!key_pair) {
102 RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
103 return nullptr;
104 }
105
106 return absl::WrapUnique(
107 new BoringSSLIdentity(std::move(key_pair), std::move(cert)));
108}
109
110std::unique_ptr<SSLIdentity> BoringSSLIdentity::CreateFromPEMChainStrings(
111 const std::string& private_key,
112 const std::string& certificate_chain) {
113 bssl::UniquePtr<BIO> bio(
114 BIO_new_mem_buf(certificate_chain.data(),
115 rtc::dchecked_cast<int>(certificate_chain.size())));
116 if (!bio) {
117 return nullptr;
118 }
119 BIO_set_mem_eof_return(bio.get(), 0);
120 std::vector<std::unique_ptr<SSLCertificate>> certs;
121 while (true) {
122 char* name;
123 char* header;
124 unsigned char* data;
125 long len; // NOLINT
126 int ret = PEM_read_bio(bio.get(), &name, &header, &data, &len);
127 if (ret == 0) {
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) {
131 break;
132 }
133 RTC_LOG(LS_ERROR) << "Failed to parse certificate from PEM string.";
134 return nullptr;
135 }
136 bssl::UniquePtr<char> owned_name(name);
137 bssl::UniquePtr<char> owned_header(header);
138 bssl::UniquePtr<unsigned char> owned_data(data);
139 if (strcmp(owned_name.get(), PEM_STRING_X509) != 0) {
140 RTC_LOG(LS_ERROR)
141 << "Non-certificate found while parsing certificate chain: "
142 << owned_name.get();
143 return nullptr;
144 }
145 bssl::UniquePtr<CRYPTO_BUFFER> crypto_buffer(
146 CRYPTO_BUFFER_new(data, len, openssl::GetBufferPool()));
147 if (!crypto_buffer) {
148 return nullptr;
149 }
150 certs.emplace_back(new BoringSSLCertificate(std::move(crypto_buffer)));
151 }
152 if (certs.empty()) {
153 RTC_LOG(LS_ERROR) << "Found no certificates in PEM string.";
154 return nullptr;
155 }
156
157 auto key_pair = OpenSSLKeyPair::FromPrivateKeyPEMString(private_key);
158 if (!key_pair) {
159 RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
160 return nullptr;
161 }
162
163 return absl::WrapUnique(new BoringSSLIdentity(
164 std::move(key_pair), std::make_unique<SSLCertChain>(std::move(certs))));
165}
166
167const BoringSSLCertificate& BoringSSLIdentity::certificate() const {
168 return *static_cast<const BoringSSLCertificate*>(&cert_chain_->Get(0));
169}
170
171const SSLCertChain& BoringSSLIdentity::cert_chain() const {
172 return *cert_chain_.get();
173}
174
175std::unique_ptr<SSLIdentity> BoringSSLIdentity::CloneInternal() const {
176 // We cannot use std::make_unique here because the referenced
177 // BoringSSLIdentity constructor is private.
178 return absl::WrapUnique(
179 new BoringSSLIdentity(key_pair_->Clone(), cert_chain_->Clone()));
180}
181
182bool BoringSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) {
183 std::vector<CRYPTO_BUFFER*> cert_buffers;
184 for (size_t i = 0; i < cert_chain_->GetSize(); ++i) {
185 cert_buffers.push_back(
186 static_cast<const BoringSSLCertificate*>(&cert_chain_->Get(i))
187 ->cert_buffer());
188 }
189 // 1 is the documented success return code.
190 if (1 != SSL_CTX_set_chain_and_key(ctx, &cert_buffers[0], cert_buffers.size(),
191 key_pair_->pkey(), nullptr)) {
192 openssl::LogSSLErrors("Configuring key and certificate");
193 return false;
194 }
195 return true;
196}
197
198std::string BoringSSLIdentity::PrivateKeyToPEMString() const {
199 return key_pair_->PrivateKeyToPEMString();
200}
201
202std::string BoringSSLIdentity::PublicKeyToPEMString() const {
203 return key_pair_->PublicKeyToPEMString();
204}
205
206bool BoringSSLIdentity::operator==(const BoringSSLIdentity& other) const {
207 return *this->key_pair_ == *other.key_pair_ &&
208 this->certificate() == other.certificate();
209}
210
211bool BoringSSLIdentity::operator!=(const BoringSSLIdentity& other) const {
212 return !(*this == other);
213}
214
215} // namespace rtc