• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #if defined(WEBRTC_WIN)
13 // Must be included first before openssl headers.
14 #include "rtc_base/win32.h"  // NOLINT
15 #endif                       // WEBRTC_WIN
16 
17 #include <openssl/err.h>
18 #include <openssl/x509.h>
19 #include <openssl/x509v3.h>
20 #include <stddef.h>
21 
22 #include "rtc_base/arraysize.h"
23 #include "rtc_base/logging.h"
24 #include "rtc_base/numerics/safe_conversions.h"
25 #include "rtc_base/openssl.h"
26 #include "rtc_base/openssl_certificate.h"
27 #ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
28 #include "rtc_base/ssl_roots.h"
29 #endif  // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
30 
31 namespace rtc {
32 namespace openssl {
33 
34 // Holds various helper methods.
35 namespace {
LogCertificates(SSL * ssl,X509 * certificate)36 void LogCertificates(SSL* ssl, X509* certificate) {
37 // Logging certificates is extremely verbose. So it is disabled by default.
38 #ifdef LOG_CERTIFICATES
39   BIO* mem = BIO_new(BIO_s_mem());
40   if (mem == nullptr) {
41     RTC_DLOG(LS_ERROR) << "BIO_new() failed to allocate memory.";
42     return;
43   }
44 
45   RTC_DLOG(LS_INFO) << "Certificate from server:";
46   X509_print_ex(mem, certificate, XN_FLAG_SEP_CPLUS_SPC, X509_FLAG_NO_HEADER);
47   BIO_write(mem, "\0", 1);
48 
49   char* buffer = nullptr;
50   BIO_get_mem_data(mem, &buffer);
51   if (buffer != nullptr) {
52     RTC_DLOG(LS_INFO) << buffer;
53   } else {
54     RTC_DLOG(LS_ERROR) << "BIO_get_mem_data() failed to get buffer.";
55   }
56   BIO_free(mem);
57 
58   const char* cipher_name = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
59   if (cipher_name != nullptr) {
60     RTC_DLOG(LS_INFO) << "Cipher: " << cipher_name;
61   } else {
62     RTC_DLOG(LS_ERROR) << "SSL_CIPHER_DESCRIPTION() failed to get cipher_name.";
63   }
64 #endif
65 }
66 }  // namespace
67 
VerifyPeerCertMatchesHost(SSL * ssl,const std::string & host)68 bool VerifyPeerCertMatchesHost(SSL* ssl, const std::string& host) {
69   if (host.empty()) {
70     RTC_DLOG(LS_ERROR) << "Hostname is empty. Cannot verify peer certificate.";
71     return false;
72   }
73 
74   if (ssl == nullptr) {
75     RTC_DLOG(LS_ERROR) << "SSL is nullptr. Cannot verify peer certificate.";
76     return false;
77   }
78 
79   X509* certificate = SSL_get_peer_certificate(ssl);
80   if (certificate == nullptr) {
81     RTC_DLOG(LS_ERROR)
82         << "SSL_get_peer_certificate failed. This should never happen.";
83     return false;
84   }
85 
86   LogCertificates(ssl, certificate);
87 
88   bool is_valid_cert_name =
89       X509_check_host(certificate, host.c_str(), host.size(), 0, nullptr) == 1;
90   X509_free(certificate);
91   return is_valid_cert_name;
92 }
93 
LogSSLErrors(const std::string & prefix)94 void LogSSLErrors(const std::string& prefix) {
95   char error_buf[200];
96   unsigned long err;  // NOLINT
97 
98   while ((err = ERR_get_error()) != 0) {
99     ERR_error_string_n(err, error_buf, sizeof(error_buf));
100     RTC_LOG(LS_ERROR) << prefix << ": " << error_buf << "\n";
101   }
102 }
103 
104 #ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
LoadBuiltinSSLRootCertificates(SSL_CTX * ctx)105 bool LoadBuiltinSSLRootCertificates(SSL_CTX* ctx) {
106   int count_of_added_certs = 0;
107   for (size_t i = 0; i < arraysize(kSSLCertCertificateList); i++) {
108     const unsigned char* cert_buffer = kSSLCertCertificateList[i];
109     size_t cert_buffer_len = kSSLCertCertificateSizeList[i];
110     X509* cert = d2i_X509(nullptr, &cert_buffer,
111                           checked_cast<long>(cert_buffer_len));  // NOLINT
112     if (cert) {
113       int return_value = X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx), cert);
114       if (return_value == 0) {
115         RTC_LOG(LS_WARNING) << "Unable to add certificate.";
116       } else {
117         count_of_added_certs++;
118       }
119       X509_free(cert);
120     }
121   }
122   return count_of_added_certs > 0;
123 }
124 #endif  // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
125 
126 }  // namespace openssl
127 }  // namespace rtc
128