blob: bb14036a3e0482c3d7e1bd2e28f22260353e4e02 [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_certificate.h"
12
13#if defined(WEBRTC_WIN)
14// Must be included first before openssl headers.
15#include "rtc_base/win32.h" // NOLINT
16#endif // WEBRTC_WIN
17
18#include <openssl/asn1.h>
19#include <openssl/bytestring.h>
20#include <openssl/digest.h>
21#include <openssl/evp.h>
22#include <openssl/mem.h>
23#include <openssl/pool.h>
24#include <openssl/rand.h>
25#include <time.h>
26
27#include <cstring>
28#include <memory>
29#include <utility>
30#include <vector>
31
32#include "rtc_base/checks.h"
33#include "rtc_base/helpers.h"
34#include "rtc_base/logging.h"
35#include "rtc_base/message_digest.h"
36#include "rtc_base/openssl_digest.h"
37#include "rtc_base/openssl_key_pair.h"
38#include "rtc_base/openssl_utility.h"
39
40namespace rtc {
41namespace {
42
43// List of OIDs of signature algorithms accepted by WebRTC.
44// Taken from openssl/nid.h.
45static const uint8_t kMD5WithRSA[] = {0x2b, 0x0e, 0x03, 0x02, 0x03};
46static const uint8_t kMD5WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
47 0x0d, 0x01, 0x01, 0x04};
48static const uint8_t kECDSAWithSHA1[] = {0x2a, 0x86, 0x48, 0xce,
49 0x3d, 0x04, 0x01};
50static const uint8_t kDSAWithSHA1[] = {0x2a, 0x86, 0x48, 0xce,
51 0x38, 0x04, 0x03};
52static const uint8_t kDSAWithSHA1_2[] = {0x2b, 0x0e, 0x03, 0x02, 0x1b};
53static const uint8_t kSHA1WithRSA[] = {0x2b, 0x0e, 0x03, 0x02, 0x1d};
54static const uint8_t kSHA1WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
55 0x0d, 0x01, 0x01, 0x05};
56static const uint8_t kECDSAWithSHA224[] = {0x2a, 0x86, 0x48, 0xce,
57 0x3d, 0x04, 0x03, 0x01};
58static const uint8_t kSHA224WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
59 0x0d, 0x01, 0x01, 0x0e};
60static const uint8_t kDSAWithSHA224[] = {0x60, 0x86, 0x48, 0x01, 0x65,
61 0x03, 0x04, 0x03, 0x01};
62static const uint8_t kECDSAWithSHA256[] = {0x2a, 0x86, 0x48, 0xce,
63 0x3d, 0x04, 0x03, 0x02};
64static const uint8_t kSHA256WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
65 0x0d, 0x01, 0x01, 0x0b};
66static const uint8_t kDSAWithSHA256[] = {0x60, 0x86, 0x48, 0x01, 0x65,
Taylor Brandstetter221ece52020-12-14 14:18:11 -080067 0x03, 0x04, 0x03, 0x02};
Taylor Brandstetter165c6182020-12-10 16:23:03 -080068static const uint8_t kECDSAWithSHA384[] = {0x2a, 0x86, 0x48, 0xce,
69 0x3d, 0x04, 0x03, 0x03};
70static const uint8_t kSHA384WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
71 0x0d, 0x01, 0x01, 0x0c};
72static const uint8_t kECDSAWithSHA512[] = {0x2a, 0x86, 0x48, 0xce,
73 0x3d, 0x04, 0x03, 0x04};
74static const uint8_t kSHA512WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
75 0x0d, 0x01, 0x01, 0x0d};
76
77#if !defined(NDEBUG)
78// Print a certificate to the log, for debugging.
79static void PrintCert(BoringSSLCertificate* cert) {
80 // Since we're using CRYPTO_BUFFER, we can't use X509_print_ex, so we'll just
81 // print the PEM string.
82 RTC_DLOG(LS_VERBOSE) << "PEM representation of certificate:\n"
83 << cert->ToPEMString();
84}
85#endif
86
87bool AddSHA256SignatureAlgorithm(CBB* cbb, KeyType key_type) {
88 // An AlgorithmIdentifier is described in RFC 5280, 4.1.1.2.
89 CBB sequence, oid, params;
90 if (!CBB_add_asn1(cbb, &sequence, CBS_ASN1_SEQUENCE) ||
91 !CBB_add_asn1(&sequence, &oid, CBS_ASN1_OBJECT)) {
92 return false;
93 }
94
95 switch (key_type) {
96 case KT_RSA:
97 if (!CBB_add_bytes(&oid, kSHA256WithRSAEncryption,
98 sizeof(kSHA256WithRSAEncryption)) ||
99 !CBB_add_asn1(&sequence, &params, CBS_ASN1_NULL)) {
100 return false;
101 }
102 break;
103 case KT_ECDSA:
104 if (!CBB_add_bytes(&oid, kECDSAWithSHA256, sizeof(kECDSAWithSHA256))) {
105 return false;
106 }
107 break;
108 default:
109 RTC_NOTREACHED();
110 return false;
111 }
112 if (!CBB_flush(cbb)) {
113 return false;
114 }
115 return true;
116}
117
118// Adds an X.509 Common Name to |cbb|.
119bool AddCommonName(CBB* cbb, const std::string& common_name) {
120 // See RFC 4519.
121 static const uint8_t kCommonName[] = {0x55, 0x04, 0x03};
122
123 if (common_name.empty()) {
124 RTC_LOG(LS_ERROR) << "Common name cannot be empty.";
125 return false;
126 }
127
128 // See RFC 5280, section 4.1.2.4.
129 CBB rdns;
130 if (!CBB_add_asn1(cbb, &rdns, CBS_ASN1_SEQUENCE)) {
131 return false;
132 }
133
134 CBB rdn, attr, type, value;
135 if (!CBB_add_asn1(&rdns, &rdn, CBS_ASN1_SET) ||
136 !CBB_add_asn1(&rdn, &attr, CBS_ASN1_SEQUENCE) ||
137 !CBB_add_asn1(&attr, &type, CBS_ASN1_OBJECT) ||
138 !CBB_add_bytes(&type, kCommonName, sizeof(kCommonName)) ||
139 !CBB_add_asn1(&attr, &value, CBS_ASN1_UTF8STRING) ||
140 !CBB_add_bytes(&value,
141 reinterpret_cast<const uint8_t*>(common_name.c_str()),
142 common_name.size()) ||
143 !CBB_flush(cbb)) {
144 return false;
145 }
146
147 return true;
148}
149
150bool AddTime(CBB* cbb, time_t time) {
151 bssl::UniquePtr<ASN1_TIME> asn1_time(ASN1_TIME_new());
152 if (!asn1_time) {
153 return false;
154 }
155
156 if (!ASN1_TIME_set(asn1_time.get(), time)) {
157 return false;
158 }
159
160 unsigned tag;
161 switch (asn1_time->type) {
162 case V_ASN1_UTCTIME:
163 tag = CBS_ASN1_UTCTIME;
164 break;
165 case V_ASN1_GENERALIZEDTIME:
166 tag = CBS_ASN1_GENERALIZEDTIME;
167 break;
168 default:
169 return false;
170 }
171
172 CBB child;
173 if (!CBB_add_asn1(cbb, &child, tag) ||
174 !CBB_add_bytes(&child, asn1_time->data, asn1_time->length) ||
175 !CBB_flush(cbb)) {
176 return false;
177 }
178
179 return true;
180}
181
182// Generate a self-signed certificate, with the public key from the
183// given key pair. Caller is responsible for freeing the returned object.
184static bssl::UniquePtr<CRYPTO_BUFFER> MakeCertificate(
185 EVP_PKEY* pkey,
186 const SSLIdentityParams& params) {
187 RTC_LOG(LS_INFO) << "Making certificate for " << params.common_name;
188
189 // See RFC 5280, section 4.1. First, construct the TBSCertificate.
190 bssl::ScopedCBB cbb;
191 CBB tbs_cert, version, validity;
192 uint8_t* tbs_cert_bytes;
193 size_t tbs_cert_len;
194 uint64_t serial_number;
195 if (!CBB_init(cbb.get(), 64) ||
196 !CBB_add_asn1(cbb.get(), &tbs_cert, CBS_ASN1_SEQUENCE) ||
197 !CBB_add_asn1(&tbs_cert, &version,
198 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
199 !CBB_add_asn1_uint64(&version, 2) ||
200 !RAND_bytes(reinterpret_cast<uint8_t*>(&serial_number),
201 sizeof(serial_number)) ||
202 !CBB_add_asn1_uint64(&tbs_cert, serial_number) ||
203 !AddSHA256SignatureAlgorithm(&tbs_cert, params.key_params.type()) ||
204 !AddCommonName(&tbs_cert, params.common_name) || // issuer
205 !CBB_add_asn1(&tbs_cert, &validity, CBS_ASN1_SEQUENCE) ||
206 !AddTime(&validity, params.not_before) ||
207 !AddTime(&validity, params.not_after) ||
208 !AddCommonName(&tbs_cert, params.common_name) || // subject
209 !EVP_marshal_public_key(&tbs_cert, pkey) || // subjectPublicKeyInfo
210 !CBB_finish(cbb.get(), &tbs_cert_bytes, &tbs_cert_len)) {
211 return nullptr;
212 }
213
214 bssl::UniquePtr<uint8_t> delete_tbs_cert_bytes(tbs_cert_bytes);
215
216 // Sign the TBSCertificate and write the entire certificate.
217 CBB cert, signature;
218 bssl::ScopedEVP_MD_CTX ctx;
219 uint8_t* sig_out;
220 size_t sig_len;
221 uint8_t* cert_bytes;
222 size_t cert_len;
223 if (!CBB_init(cbb.get(), tbs_cert_len) ||
224 !CBB_add_asn1(cbb.get(), &cert, CBS_ASN1_SEQUENCE) ||
225 !CBB_add_bytes(&cert, tbs_cert_bytes, tbs_cert_len) ||
226 !AddSHA256SignatureAlgorithm(&cert, params.key_params.type()) ||
227 !CBB_add_asn1(&cert, &signature, CBS_ASN1_BITSTRING) ||
228 !CBB_add_u8(&signature, 0 /* no unused bits */) ||
229 !EVP_DigestSignInit(ctx.get(), nullptr, EVP_sha256(), nullptr, pkey) ||
230 // Compute the maximum signature length.
231 !EVP_DigestSign(ctx.get(), nullptr, &sig_len, tbs_cert_bytes,
232 tbs_cert_len) ||
233 !CBB_reserve(&signature, &sig_out, sig_len) ||
234 // Actually sign the TBSCertificate.
235 !EVP_DigestSign(ctx.get(), sig_out, &sig_len, tbs_cert_bytes,
236 tbs_cert_len) ||
237 !CBB_did_write(&signature, sig_len) ||
238 !CBB_finish(cbb.get(), &cert_bytes, &cert_len)) {
239 return nullptr;
240 }
241 bssl::UniquePtr<uint8_t> delete_cert_bytes(cert_bytes);
242
243 RTC_LOG(LS_INFO) << "Returning certificate";
244 return bssl::UniquePtr<CRYPTO_BUFFER>(
245 CRYPTO_BUFFER_new(cert_bytes, cert_len, openssl::GetBufferPool()));
246}
247
248} // namespace
249
250BoringSSLCertificate::BoringSSLCertificate(
251 bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer)
252 : cert_buffer_(std::move(cert_buffer)) {
253 RTC_DCHECK(cert_buffer_ != nullptr);
254}
255
256std::unique_ptr<BoringSSLCertificate> BoringSSLCertificate::Generate(
257 OpenSSLKeyPair* key_pair,
258 const SSLIdentityParams& params) {
259 SSLIdentityParams actual_params(params);
260 if (actual_params.common_name.empty()) {
261 // Use a random string, arbitrarily 8 chars long.
262 actual_params.common_name = CreateRandomString(8);
263 }
264 bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer =
265 MakeCertificate(key_pair->pkey(), actual_params);
266 if (!cert_buffer) {
267 openssl::LogSSLErrors("Generating certificate");
268 return nullptr;
269 }
270 auto ret = std::make_unique<BoringSSLCertificate>(std::move(cert_buffer));
271#if !defined(NDEBUG)
272 PrintCert(ret.get());
273#endif
274 return ret;
275}
276
277std::unique_ptr<BoringSSLCertificate> BoringSSLCertificate::FromPEMString(
278 const std::string& pem_string) {
279 std::string der;
280 if (!SSLIdentity::PemToDer(kPemTypeCertificate, pem_string, &der)) {
281 return nullptr;
282 }
283 bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer(
284 CRYPTO_BUFFER_new(reinterpret_cast<const uint8_t*>(der.c_str()),
285 der.length(), openssl::GetBufferPool()));
286 if (!cert_buffer) {
287 return nullptr;
288 }
289 return std::make_unique<BoringSSLCertificate>(std::move(cert_buffer));
290}
291
292#define OID_MATCHES(oid, oid_other) \
293 (CBS_len(&oid) == sizeof(oid_other) && \
Taylor Brandstetterd0acbd82021-01-25 13:44:55 -0800294 0 == memcmp(CBS_data(&oid), oid_other, sizeof(oid_other)))
Taylor Brandstetter165c6182020-12-10 16:23:03 -0800295
296bool BoringSSLCertificate::GetSignatureDigestAlgorithm(
297 std::string* algorithm) const {
298 CBS oid;
299 if (!openssl::ParseCertificate(cert_buffer_.get(), &oid, nullptr)) {
300 RTC_LOG(LS_ERROR) << "Failed to parse certificate.";
301 return false;
302 }
303 if (OID_MATCHES(oid, kMD5WithRSA) ||
304 OID_MATCHES(oid, kMD5WithRSAEncryption)) {
305 *algorithm = DIGEST_MD5;
306 return true;
307 }
308 if (OID_MATCHES(oid, kECDSAWithSHA1) || OID_MATCHES(oid, kDSAWithSHA1) ||
309 OID_MATCHES(oid, kDSAWithSHA1_2) || OID_MATCHES(oid, kSHA1WithRSA) ||
310 OID_MATCHES(oid, kSHA1WithRSAEncryption)) {
311 *algorithm = DIGEST_SHA_1;
312 return true;
313 }
314 if (OID_MATCHES(oid, kECDSAWithSHA224) ||
315 OID_MATCHES(oid, kSHA224WithRSAEncryption) ||
316 OID_MATCHES(oid, kDSAWithSHA224)) {
317 *algorithm = DIGEST_SHA_224;
318 return true;
319 }
320 if (OID_MATCHES(oid, kECDSAWithSHA256) ||
321 OID_MATCHES(oid, kSHA256WithRSAEncryption) ||
322 OID_MATCHES(oid, kDSAWithSHA256)) {
323 *algorithm = DIGEST_SHA_256;
324 return true;
325 }
326 if (OID_MATCHES(oid, kECDSAWithSHA384) ||
327 OID_MATCHES(oid, kSHA384WithRSAEncryption)) {
328 *algorithm = DIGEST_SHA_384;
329 return true;
330 }
331 if (OID_MATCHES(oid, kECDSAWithSHA512) ||
332 OID_MATCHES(oid, kSHA512WithRSAEncryption)) {
333 *algorithm = DIGEST_SHA_512;
334 return true;
335 }
336 // Unknown algorithm. There are several unhandled options that are less
337 // common and more complex.
338 RTC_LOG(LS_ERROR) << "Unknown signature algorithm.";
339 algorithm->clear();
340 return false;
341}
342
343bool BoringSSLCertificate::ComputeDigest(const std::string& algorithm,
344 unsigned char* digest,
345 size_t size,
346 size_t* length) const {
347 return ComputeDigest(cert_buffer_.get(), algorithm, digest, size, length);
348}
349
350bool BoringSSLCertificate::ComputeDigest(const CRYPTO_BUFFER* cert_buffer,
351 const std::string& algorithm,
352 unsigned char* digest,
353 size_t size,
354 size_t* length) {
355 const EVP_MD* md = nullptr;
356 unsigned int n = 0;
357 if (!OpenSSLDigest::GetDigestEVP(algorithm, &md)) {
358 return false;
359 }
360 if (size < static_cast<size_t>(EVP_MD_size(md))) {
361 return false;
362 }
363 if (!EVP_Digest(CRYPTO_BUFFER_data(cert_buffer),
364 CRYPTO_BUFFER_len(cert_buffer), digest, &n, md, nullptr)) {
365 return false;
366 }
367 *length = n;
368 return true;
369}
370
371BoringSSLCertificate::~BoringSSLCertificate() {}
372
373std::unique_ptr<SSLCertificate> BoringSSLCertificate::Clone() const {
374 return std::make_unique<BoringSSLCertificate>(
375 bssl::UpRef(cert_buffer_.get()));
376}
377
378std::string BoringSSLCertificate::ToPEMString() const {
379 return SSLIdentity::DerToPem(kPemTypeCertificate,
380 CRYPTO_BUFFER_data(cert_buffer_.get()),
381 CRYPTO_BUFFER_len(cert_buffer_.get()));
382}
383
384void BoringSSLCertificate::ToDER(Buffer* der_buffer) const {
385 der_buffer->SetData(CRYPTO_BUFFER_data(cert_buffer_.get()),
386 CRYPTO_BUFFER_len(cert_buffer_.get()));
387}
388
389bool BoringSSLCertificate::operator==(const BoringSSLCertificate& other) const {
390 return CRYPTO_BUFFER_len(cert_buffer_.get()) ==
391 CRYPTO_BUFFER_len(other.cert_buffer_.get()) &&
392 0 == memcmp(CRYPTO_BUFFER_data(cert_buffer_.get()),
393 CRYPTO_BUFFER_data(other.cert_buffer_.get()),
394 CRYPTO_BUFFER_len(cert_buffer_.get()));
395}
396
397bool BoringSSLCertificate::operator!=(const BoringSSLCertificate& other) const {
398 return !(*this == other);
399}
400
401int64_t BoringSSLCertificate::CertificateExpirationTime() const {
402 int64_t ret;
403 if (!openssl::ParseCertificate(cert_buffer_.get(), nullptr, &ret)) {
404 RTC_LOG(LS_ERROR) << "Failed to parse certificate.";
405 return -1;
406 }
407 return ret;
408}
409
410} // namespace rtc