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