blob: eba3788a948bd0c18c0669901cf6eec98dc2de1b [file] [log] [blame]
Benjamin Wright9201d1a2018-04-05 12:12:26 -07001/*
2 * Copyright 2018 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_utility.h"
Ali Tofigh7fa90572022-03-17 15:47:49 +010012
13#include "absl/strings/string_view.h"
Benjamin Wright9201d1a2018-04-05 12:12:26 -070014#if defined(WEBRTC_WIN)
15// Must be included first before openssl headers.
16#include "rtc_base/win32.h" // NOLINT
17#endif // WEBRTC_WIN
18
Taylor Brandstetter165c6182020-12-10 16:23:03 -080019#ifdef OPENSSL_IS_BORINGSSL
20#include <openssl/pool.h>
21#endif
Jiawei Oue635e982018-07-26 11:31:28 -070022#include <openssl/err.h>
Benjamin Wright9201d1a2018-04-05 12:12:26 -070023#include <openssl/x509.h>
24#include <openssl/x509v3.h>
Yves Gerey988cc082018-10-23 12:03:01 +020025#include <stddef.h>
Benjamin Wright9201d1a2018-04-05 12:12:26 -070026
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070027#include "rtc_base/arraysize.h"
Benjamin Wright9201d1a2018-04-05 12:12:26 -070028#include "rtc_base/logging.h"
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070029#include "rtc_base/numerics/safe_conversions.h"
Jonas Olssona4d87372019-07-05 19:08:33 +020030#include "rtc_base/openssl.h"
Taylor Brandstetter165c6182020-12-10 16:23:03 -080031#include "rtc_base/ssl_identity.h"
Mirko Bonadeib889a202018-08-15 11:41:27 +020032#ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
Steve Anton10542f22019-01-11 09:11:00 -080033#include "rtc_base/ssl_roots.h"
Mirko Bonadeib889a202018-08-15 11:41:27 +020034#endif // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
Benjamin Wright9201d1a2018-04-05 12:12:26 -070035
36namespace rtc {
37namespace openssl {
38
39// Holds various helper methods.
40namespace {
Taylor Brandstetter165c6182020-12-10 16:23:03 -080041
42// TODO(crbug.com/webrtc/11710): When OS certificate verification is available,
43// and we don't need VerifyPeerCertMatchesHost, don't compile this in order to
44// avoid a dependency on OpenSSL X509 objects (see crbug.com/webrtc/11410).
Benjamin Wright9201d1a2018-04-05 12:12:26 -070045void LogCertificates(SSL* ssl, X509* certificate) {
46// Logging certificates is extremely verbose. So it is disabled by default.
47#ifdef LOG_CERTIFICATES
48 BIO* mem = BIO_new(BIO_s_mem());
49 if (mem == nullptr) {
50 RTC_DLOG(LS_ERROR) << "BIO_new() failed to allocate memory.";
51 return;
52 }
53
54 RTC_DLOG(LS_INFO) << "Certificate from server:";
55 X509_print_ex(mem, certificate, XN_FLAG_SEP_CPLUS_SPC, X509_FLAG_NO_HEADER);
56 BIO_write(mem, "\0", 1);
57
58 char* buffer = nullptr;
59 BIO_get_mem_data(mem, &buffer);
60 if (buffer != nullptr) {
61 RTC_DLOG(LS_INFO) << buffer;
62 } else {
63 RTC_DLOG(LS_ERROR) << "BIO_get_mem_data() failed to get buffer.";
64 }
65 BIO_free(mem);
66
67 const char* cipher_name = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
68 if (cipher_name != nullptr) {
69 RTC_DLOG(LS_INFO) << "Cipher: " << cipher_name;
70 } else {
71 RTC_DLOG(LS_ERROR) << "SSL_CIPHER_DESCRIPTION() failed to get cipher_name.";
72 }
73#endif
74}
75} // namespace
76
Taylor Brandstetter165c6182020-12-10 16:23:03 -080077#ifdef OPENSSL_IS_BORINGSSL
78bool ParseCertificate(CRYPTO_BUFFER* cert_buffer,
79 CBS* signature_algorithm_oid,
80 int64_t* expiration_time) {
81 CBS cbs;
82 CRYPTO_BUFFER_init_CBS(cert_buffer, &cbs);
83
84 // Certificate ::= SEQUENCE {
85 CBS certificate;
86 if (!CBS_get_asn1(&cbs, &certificate, CBS_ASN1_SEQUENCE)) {
87 return false;
88 }
89 // tbsCertificate TBSCertificate,
90 CBS tbs_certificate;
91 if (!CBS_get_asn1(&certificate, &tbs_certificate, CBS_ASN1_SEQUENCE)) {
92 return false;
93 }
94 // signatureAlgorithm AlgorithmIdentifier,
95 CBS signature_algorithm;
96 if (!CBS_get_asn1(&certificate, &signature_algorithm, CBS_ASN1_SEQUENCE)) {
97 return false;
98 }
99 if (!CBS_get_asn1(&signature_algorithm, signature_algorithm_oid,
100 CBS_ASN1_OBJECT)) {
101 return false;
102 }
103 // signatureValue BIT STRING }
104 if (!CBS_get_asn1(&certificate, nullptr, CBS_ASN1_BITSTRING)) {
105 return false;
106 }
107 if (CBS_len(&certificate)) {
108 return false;
109 }
110
111 // Now parse the inner TBSCertificate.
112 // version [0] EXPLICIT Version DEFAULT v1,
113 if (!CBS_get_optional_asn1(
114 &tbs_certificate, nullptr, nullptr,
115 CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC)) {
116 return false;
117 }
118 // serialNumber CertificateSerialNumber,
119 if (!CBS_get_asn1(&tbs_certificate, nullptr, CBS_ASN1_INTEGER)) {
120 return false;
121 }
122 // signature AlgorithmIdentifier
123 if (!CBS_get_asn1(&tbs_certificate, nullptr, CBS_ASN1_SEQUENCE)) {
124 return false;
125 }
126 // issuer Name,
127 if (!CBS_get_asn1(&tbs_certificate, nullptr, CBS_ASN1_SEQUENCE)) {
128 return false;
129 }
130 // validity Validity,
131 CBS validity;
132 if (!CBS_get_asn1(&tbs_certificate, &validity, CBS_ASN1_SEQUENCE)) {
133 return false;
134 }
135 // Skip over notBefore.
136 if (!CBS_get_any_asn1_element(&validity, nullptr, nullptr, nullptr)) {
137 return false;
138 }
139 // Parse notAfter.
140 CBS not_after;
141 unsigned not_after_tag;
142 if (!CBS_get_any_asn1(&validity, &not_after, &not_after_tag)) {
143 return false;
144 }
145 bool long_format;
146 if (not_after_tag == CBS_ASN1_UTCTIME) {
147 long_format = false;
148 } else if (not_after_tag == CBS_ASN1_GENERALIZEDTIME) {
149 long_format = true;
150 } else {
151 return false;
152 }
153 if (expiration_time) {
154 *expiration_time =
155 ASN1TimeToSec(CBS_data(&not_after), CBS_len(&not_after), long_format);
156 }
157 // subject Name,
158 if (!CBS_get_asn1_element(&tbs_certificate, nullptr, CBS_ASN1_SEQUENCE)) {
159 return false;
160 }
161 // subjectPublicKeyInfo SubjectPublicKeyInfo,
162 if (!CBS_get_asn1(&tbs_certificate, nullptr, CBS_ASN1_SEQUENCE)) {
163 return false;
164 }
165 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL
166 if (!CBS_get_optional_asn1(&tbs_certificate, nullptr, nullptr,
167 0x01 | CBS_ASN1_CONTEXT_SPECIFIC)) {
168 return false;
169 }
170 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL
171 if (!CBS_get_optional_asn1(&tbs_certificate, nullptr, nullptr,
172 0x02 | CBS_ASN1_CONTEXT_SPECIFIC)) {
173 return false;
174 }
175 // extensions [3] EXPLICIT Extensions OPTIONAL
176 if (!CBS_get_optional_asn1(
177 &tbs_certificate, nullptr, nullptr,
178 0x03 | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC)) {
179 return false;
180 }
181 if (CBS_len(&tbs_certificate)) {
182 return false;
183 }
184
185 return true;
186}
187#endif // OPENSSL_IS_BORINGSSL
188
Ali Tofigh7fa90572022-03-17 15:47:49 +0100189bool VerifyPeerCertMatchesHost(SSL* ssl, absl::string_view host) {
Benjamin Wright9201d1a2018-04-05 12:12:26 -0700190 if (host.empty()) {
191 RTC_DLOG(LS_ERROR) << "Hostname is empty. Cannot verify peer certificate.";
192 return false;
193 }
194
195 if (ssl == nullptr) {
196 RTC_DLOG(LS_ERROR) << "SSL is nullptr. Cannot verify peer certificate.";
197 return false;
198 }
199
Taylor Brandstetter165c6182020-12-10 16:23:03 -0800200#ifdef OPENSSL_IS_BORINGSSL
201 // We can't grab a X509 object directly, as the SSL context may have been
202 // initialized with TLS_with_buffers_method.
203 const STACK_OF(CRYPTO_BUFFER)* chain = SSL_get0_peer_certificates(ssl);
204 if (chain == nullptr || sk_CRYPTO_BUFFER_num(chain) == 0) {
205 RTC_LOG(LS_ERROR)
206 << "SSL_get0_peer_certificates failed. This should never happen.";
207 return false;
208 }
209 CRYPTO_BUFFER* leaf = sk_CRYPTO_BUFFER_value(chain, 0);
210 bssl::UniquePtr<X509> x509(X509_parse_from_buffer(leaf));
211 if (!x509) {
212 RTC_LOG(LS_ERROR) << "Failed to parse certificate to X509 object.";
213 return false;
214 }
215 LogCertificates(ssl, x509.get());
Ali Tofigh7fa90572022-03-17 15:47:49 +0100216 return X509_check_host(x509.get(), host.data(), host.size(), 0, nullptr) == 1;
Taylor Brandstetter165c6182020-12-10 16:23:03 -0800217#else // OPENSSL_IS_BORINGSSL
Benjamin Wright9201d1a2018-04-05 12:12:26 -0700218 X509* certificate = SSL_get_peer_certificate(ssl);
219 if (certificate == nullptr) {
Taylor Brandstetter165c6182020-12-10 16:23:03 -0800220 RTC_LOG(LS_ERROR)
Benjamin Wright9201d1a2018-04-05 12:12:26 -0700221 << "SSL_get_peer_certificate failed. This should never happen.";
222 return false;
223 }
224
225 LogCertificates(ssl, certificate);
226
227 bool is_valid_cert_name =
Ali Tofigh7fa90572022-03-17 15:47:49 +0100228 X509_check_host(certificate, host.data(), host.size(), 0, nullptr) == 1;
Benjamin Wright9201d1a2018-04-05 12:12:26 -0700229 X509_free(certificate);
230 return is_valid_cert_name;
Taylor Brandstetter165c6182020-12-10 16:23:03 -0800231#endif // !defined(OPENSSL_IS_BORINGSSL)
Benjamin Wright9201d1a2018-04-05 12:12:26 -0700232}
233
Ali Tofigh7fa90572022-03-17 15:47:49 +0100234void LogSSLErrors(absl::string_view prefix) {
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700235 char error_buf[200];
236 unsigned long err; // NOLINT
237
238 while ((err = ERR_get_error()) != 0) {
239 ERR_error_string_n(err, error_buf, sizeof(error_buf));
240 RTC_LOG(LS_ERROR) << prefix << ": " << error_buf << "\n";
241 }
242}
243
Mirko Bonadeib889a202018-08-15 11:41:27 +0200244#ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700245bool LoadBuiltinSSLRootCertificates(SSL_CTX* ctx) {
246 int count_of_added_certs = 0;
247 for (size_t i = 0; i < arraysize(kSSLCertCertificateList); i++) {
248 const unsigned char* cert_buffer = kSSLCertCertificateList[i];
249 size_t cert_buffer_len = kSSLCertCertificateSizeList[i];
250 X509* cert = d2i_X509(nullptr, &cert_buffer,
251 checked_cast<long>(cert_buffer_len)); // NOLINT
252 if (cert) {
253 int return_value = X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx), cert);
254 if (return_value == 0) {
255 RTC_LOG(LS_WARNING) << "Unable to add certificate.";
256 } else {
257 count_of_added_certs++;
258 }
259 X509_free(cert);
260 }
261 }
262 return count_of_added_certs > 0;
263}
Mirko Bonadeib889a202018-08-15 11:41:27 +0200264#endif // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700265
Taylor Brandstetter165c6182020-12-10 16:23:03 -0800266#ifdef OPENSSL_IS_BORINGSSL
267CRYPTO_BUFFER_POOL* GetBufferPool() {
268 static CRYPTO_BUFFER_POOL* instance = CRYPTO_BUFFER_POOL_new();
269 return instance;
270}
271#endif
272
Benjamin Wright9201d1a2018-04-05 12:12:26 -0700273} // namespace openssl
274} // namespace rtc