xref: /aosp_15_r20/external/webrtc/rtc_base/openssl_utility.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
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 
11 #include "rtc_base/openssl_utility.h"
12 
13 #include "absl/strings/string_view.h"
14 #if defined(WEBRTC_WIN)
15 // Must be included first before openssl headers.
16 #include "rtc_base/win32.h"  // NOLINT
17 #endif                       // WEBRTC_WIN
18 
19 #ifdef OPENSSL_IS_BORINGSSL
20 #include <openssl/pool.h>
21 #endif
22 #include <openssl/err.h>
23 #include <openssl/x509.h>
24 #include <openssl/x509v3.h>
25 #include <stddef.h>
26 
27 #include "rtc_base/arraysize.h"
28 #include "rtc_base/logging.h"
29 #include "rtc_base/numerics/safe_conversions.h"
30 #include "rtc_base/openssl.h"
31 #include "rtc_base/ssl_identity.h"
32 #ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
33 #include "rtc_base/ssl_roots.h"
34 #endif  // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
35 
36 namespace rtc {
37 namespace openssl {
38 
39 // Holds various helper methods.
40 namespace {
41 
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).
LogCertificates(SSL * ssl,X509 * certificate)45 void 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 
77 #ifdef OPENSSL_IS_BORINGSSL
ParseCertificate(CRYPTO_BUFFER * cert_buffer,CBS * signature_algorithm_oid,int64_t * expiration_time)78 bool 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 
VerifyPeerCertMatchesHost(SSL * ssl,absl::string_view host)189 bool VerifyPeerCertMatchesHost(SSL* ssl, absl::string_view host) {
190   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 
200 #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());
216   return X509_check_host(x509.get(), host.data(), host.size(), 0, nullptr) == 1;
217 #else   // OPENSSL_IS_BORINGSSL
218   X509* certificate = SSL_get_peer_certificate(ssl);
219   if (certificate == nullptr) {
220     RTC_LOG(LS_ERROR)
221         << "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 =
228       X509_check_host(certificate, host.data(), host.size(), 0, nullptr) == 1;
229   X509_free(certificate);
230   return is_valid_cert_name;
231 #endif  // !defined(OPENSSL_IS_BORINGSSL)
232 }
233 
LogSSLErrors(absl::string_view prefix)234 void LogSSLErrors(absl::string_view prefix) {
235   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 
244 #ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
LoadBuiltinSSLRootCertificates(SSL_CTX * ctx)245 bool 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 }
264 #endif  // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
265 
266 #ifdef OPENSSL_IS_BORINGSSL
GetBufferPool()267 CRYPTO_BUFFER_POOL* GetBufferPool() {
268   static CRYPTO_BUFFER_POOL* instance = CRYPTO_BUFFER_POOL_new();
269   return instance;
270 }
271 #endif
272 
273 }  // namespace openssl
274 }  // namespace rtc
275