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