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