blob: d6e1e1eb34c248978eb9142554cc2af2a7cdb620 [file] [log] [blame]
Benjamin Wright9201d1a2018-04-05 19:12:261/*
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 17:11:0011#include "rtc_base/openssl_utility.h"
Ali Tofigh7fa90572022-03-17 14:47:4912
13#include "absl/strings/string_view.h"
Benjamin Wright9201d1a2018-04-05 19:12:2614#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-11 00:23:0319#ifdef OPENSSL_IS_BORINGSSL
20#include <openssl/pool.h>
21#endif
Jiawei Oue635e982018-07-26 18:31:2822#include <openssl/err.h>
Benjamin Wright9201d1a2018-04-05 19:12:2623#include <openssl/x509.h>
24#include <openssl/x509v3.h>
Yves Gerey988cc082018-10-23 10:03:0125#include <stddef.h>
Benjamin Wright9201d1a2018-04-05 19:12:2626
Benjamin Wrightd6f86e82018-05-08 20:12:2527#include "rtc_base/arraysize.h"
Benjamin Wright9201d1a2018-04-05 19:12:2628#include "rtc_base/logging.h"
Benjamin Wrightd6f86e82018-05-08 20:12:2529#include "rtc_base/numerics/safe_conversions.h"
Jonas Olssona4d87372019-07-05 17:08:3330#include "rtc_base/openssl.h"
Taylor Brandstetter165c6182020-12-11 00:23:0331#include "rtc_base/ssl_identity.h"
Mirko Bonadeib889a202018-08-15 09:41:2732#ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
Steve Anton10542f22019-01-11 17:11:0033#include "rtc_base/ssl_roots.h"
Mirko Bonadeib889a202018-08-15 09:41:2734#endif // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
Benjamin Wright9201d1a2018-04-05 19:12:2635
36namespace rtc {
37namespace openssl {
38
39// Holds various helper methods.
40namespace {
Taylor Brandstetter165c6182020-12-11 00:23:0341
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).
Dor Heneca11ca2024-10-02 19:31:5245void LogCertificates([[maybe_unused]] SSL* ssl,
46 [[maybe_unused]] X509* certificate) {
Benjamin Wright9201d1a2018-04-05 19:12:2647// Logging certificates is extremely verbose. So it is disabled by default.
48#ifdef LOG_CERTIFICATES
49 BIO* mem = BIO_new(BIO_s_mem());
50 if (mem == nullptr) {
51 RTC_DLOG(LS_ERROR) << "BIO_new() failed to allocate memory.";
52 return;
53 }
54
55 RTC_DLOG(LS_INFO) << "Certificate from server:";
56 X509_print_ex(mem, certificate, XN_FLAG_SEP_CPLUS_SPC, X509_FLAG_NO_HEADER);
57 BIO_write(mem, "\0", 1);
58
59 char* buffer = nullptr;
60 BIO_get_mem_data(mem, &buffer);
61 if (buffer != nullptr) {
62 RTC_DLOG(LS_INFO) << buffer;
63 } else {
64 RTC_DLOG(LS_ERROR) << "BIO_get_mem_data() failed to get buffer.";
65 }
66 BIO_free(mem);
67
68 const char* cipher_name = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
69 if (cipher_name != nullptr) {
70 RTC_DLOG(LS_INFO) << "Cipher: " << cipher_name;
71 } else {
72 RTC_DLOG(LS_ERROR) << "SSL_CIPHER_DESCRIPTION() failed to get cipher_name.";
73 }
74#endif
75}
76} // namespace
77
Taylor Brandstetter165c6182020-12-11 00:23:0378#ifdef OPENSSL_IS_BORINGSSL
79bool ParseCertificate(CRYPTO_BUFFER* cert_buffer,
80 CBS* signature_algorithm_oid,
81 int64_t* expiration_time) {
82 CBS cbs;
83 CRYPTO_BUFFER_init_CBS(cert_buffer, &cbs);
84
85 // Certificate ::= SEQUENCE {
86 CBS certificate;
87 if (!CBS_get_asn1(&cbs, &certificate, CBS_ASN1_SEQUENCE)) {
88 return false;
89 }
90 // tbsCertificate TBSCertificate,
91 CBS tbs_certificate;
92 if (!CBS_get_asn1(&certificate, &tbs_certificate, CBS_ASN1_SEQUENCE)) {
93 return false;
94 }
95 // signatureAlgorithm AlgorithmIdentifier,
96 CBS signature_algorithm;
97 if (!CBS_get_asn1(&certificate, &signature_algorithm, CBS_ASN1_SEQUENCE)) {
98 return false;
99 }
100 if (!CBS_get_asn1(&signature_algorithm, signature_algorithm_oid,
101 CBS_ASN1_OBJECT)) {
102 return false;
103 }
104 // signatureValue BIT STRING }
105 if (!CBS_get_asn1(&certificate, nullptr, CBS_ASN1_BITSTRING)) {
106 return false;
107 }
108 if (CBS_len(&certificate)) {
109 return false;
110 }
111
112 // Now parse the inner TBSCertificate.
113 // version [0] EXPLICIT Version DEFAULT v1,
114 if (!CBS_get_optional_asn1(
115 &tbs_certificate, nullptr, nullptr,
116 CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC)) {
117 return false;
118 }
119 // serialNumber CertificateSerialNumber,
120 if (!CBS_get_asn1(&tbs_certificate, nullptr, CBS_ASN1_INTEGER)) {
121 return false;
122 }
123 // signature AlgorithmIdentifier
124 if (!CBS_get_asn1(&tbs_certificate, nullptr, CBS_ASN1_SEQUENCE)) {
125 return false;
126 }
127 // issuer Name,
128 if (!CBS_get_asn1(&tbs_certificate, nullptr, CBS_ASN1_SEQUENCE)) {
129 return false;
130 }
131 // validity Validity,
132 CBS validity;
133 if (!CBS_get_asn1(&tbs_certificate, &validity, CBS_ASN1_SEQUENCE)) {
134 return false;
135 }
136 // Skip over notBefore.
137 if (!CBS_get_any_asn1_element(&validity, nullptr, nullptr, nullptr)) {
138 return false;
139 }
140 // Parse notAfter.
141 CBS not_after;
142 unsigned not_after_tag;
143 if (!CBS_get_any_asn1(&validity, &not_after, &not_after_tag)) {
144 return false;
145 }
146 bool long_format;
147 if (not_after_tag == CBS_ASN1_UTCTIME) {
148 long_format = false;
149 } else if (not_after_tag == CBS_ASN1_GENERALIZEDTIME) {
150 long_format = true;
151 } else {
152 return false;
153 }
154 if (expiration_time) {
155 *expiration_time =
156 ASN1TimeToSec(CBS_data(&not_after), CBS_len(&not_after), long_format);
157 }
158 // subject Name,
159 if (!CBS_get_asn1_element(&tbs_certificate, nullptr, CBS_ASN1_SEQUENCE)) {
160 return false;
161 }
162 // subjectPublicKeyInfo SubjectPublicKeyInfo,
163 if (!CBS_get_asn1(&tbs_certificate, nullptr, CBS_ASN1_SEQUENCE)) {
164 return false;
165 }
166 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL
167 if (!CBS_get_optional_asn1(&tbs_certificate, nullptr, nullptr,
168 0x01 | CBS_ASN1_CONTEXT_SPECIFIC)) {
169 return false;
170 }
171 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL
172 if (!CBS_get_optional_asn1(&tbs_certificate, nullptr, nullptr,
173 0x02 | CBS_ASN1_CONTEXT_SPECIFIC)) {
174 return false;
175 }
176 // extensions [3] EXPLICIT Extensions OPTIONAL
177 if (!CBS_get_optional_asn1(
178 &tbs_certificate, nullptr, nullptr,
179 0x03 | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC)) {
180 return false;
181 }
182 if (CBS_len(&tbs_certificate)) {
183 return false;
184 }
185
186 return true;
187}
188#endif // OPENSSL_IS_BORINGSSL
189
Ali Tofigh7fa90572022-03-17 14:47:49190bool VerifyPeerCertMatchesHost(SSL* ssl, absl::string_view host) {
Benjamin Wright9201d1a2018-04-05 19:12:26191 if (host.empty()) {
192 RTC_DLOG(LS_ERROR) << "Hostname is empty. Cannot verify peer certificate.";
193 return false;
194 }
195
196 if (ssl == nullptr) {
197 RTC_DLOG(LS_ERROR) << "SSL is nullptr. Cannot verify peer certificate.";
198 return false;
199 }
200
Taylor Brandstetter165c6182020-12-11 00:23:03201#ifdef OPENSSL_IS_BORINGSSL
202 // We can't grab a X509 object directly, as the SSL context may have been
203 // initialized with TLS_with_buffers_method.
204 const STACK_OF(CRYPTO_BUFFER)* chain = SSL_get0_peer_certificates(ssl);
205 if (chain == nullptr || sk_CRYPTO_BUFFER_num(chain) == 0) {
206 RTC_LOG(LS_ERROR)
207 << "SSL_get0_peer_certificates failed. This should never happen.";
208 return false;
209 }
210 CRYPTO_BUFFER* leaf = sk_CRYPTO_BUFFER_value(chain, 0);
211 bssl::UniquePtr<X509> x509(X509_parse_from_buffer(leaf));
212 if (!x509) {
213 RTC_LOG(LS_ERROR) << "Failed to parse certificate to X509 object.";
214 return false;
215 }
216 LogCertificates(ssl, x509.get());
Ali Tofigh7fa90572022-03-17 14:47:49217 return X509_check_host(x509.get(), host.data(), host.size(), 0, nullptr) == 1;
Taylor Brandstetter165c6182020-12-11 00:23:03218#else // OPENSSL_IS_BORINGSSL
Benjamin Wright9201d1a2018-04-05 19:12:26219 X509* certificate = SSL_get_peer_certificate(ssl);
220 if (certificate == nullptr) {
Taylor Brandstetter165c6182020-12-11 00:23:03221 RTC_LOG(LS_ERROR)
Benjamin Wright9201d1a2018-04-05 19:12:26222 << "SSL_get_peer_certificate failed. This should never happen.";
223 return false;
224 }
225
226 LogCertificates(ssl, certificate);
227
228 bool is_valid_cert_name =
Ali Tofigh7fa90572022-03-17 14:47:49229 X509_check_host(certificate, host.data(), host.size(), 0, nullptr) == 1;
Benjamin Wright9201d1a2018-04-05 19:12:26230 X509_free(certificate);
231 return is_valid_cert_name;
Taylor Brandstetter165c6182020-12-11 00:23:03232#endif // !defined(OPENSSL_IS_BORINGSSL)
Benjamin Wright9201d1a2018-04-05 19:12:26233}
234
Ali Tofigh7fa90572022-03-17 14:47:49235void LogSSLErrors(absl::string_view prefix) {
Benjamin Wrightd6f86e82018-05-08 20:12:25236 char error_buf[200];
237 unsigned long err; // NOLINT
238
239 while ((err = ERR_get_error()) != 0) {
240 ERR_error_string_n(err, error_buf, sizeof(error_buf));
241 RTC_LOG(LS_ERROR) << prefix << ": " << error_buf << "\n";
242 }
243}
244
Mirko Bonadeib889a202018-08-15 09:41:27245#ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
Benjamin Wrightd6f86e82018-05-08 20:12:25246bool LoadBuiltinSSLRootCertificates(SSL_CTX* ctx) {
247 int count_of_added_certs = 0;
248 for (size_t i = 0; i < arraysize(kSSLCertCertificateList); i++) {
249 const unsigned char* cert_buffer = kSSLCertCertificateList[i];
250 size_t cert_buffer_len = kSSLCertCertificateSizeList[i];
251 X509* cert = d2i_X509(nullptr, &cert_buffer,
252 checked_cast<long>(cert_buffer_len)); // NOLINT
253 if (cert) {
254 int return_value = X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx), cert);
255 if (return_value == 0) {
256 RTC_LOG(LS_WARNING) << "Unable to add certificate.";
257 } else {
258 count_of_added_certs++;
259 }
260 X509_free(cert);
261 }
262 }
263 return count_of_added_certs > 0;
264}
Mirko Bonadeib889a202018-08-15 09:41:27265#endif // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
Benjamin Wrightd6f86e82018-05-08 20:12:25266
Taylor Brandstetter165c6182020-12-11 00:23:03267#ifdef OPENSSL_IS_BORINGSSL
268CRYPTO_BUFFER_POOL* GetBufferPool() {
269 static CRYPTO_BUFFER_POOL* instance = CRYPTO_BUFFER_POOL_new();
270 return instance;
271}
272#endif
273
Benjamin Wright9201d1a2018-04-05 19:12:26274} // namespace openssl
275} // namespace rtc