blob: a3f33478ebc7b05100b73cb304281a0246b9256b [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"
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
Jiawei Oue635e982018-07-26 11:31:28 -070017#include <openssl/err.h>
Benjamin Wright9201d1a2018-04-05 12:12:26 -070018#include <openssl/x509.h>
19#include <openssl/x509v3.h>
Yves Gerey988cc082018-10-23 12:03:01 +020020#include "rtc_base/openssl.h"
21
22#include <stddef.h>
Benjamin Wright9201d1a2018-04-05 12:12:26 -070023
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070024#include "rtc_base/arraysize.h"
Benjamin Wright9201d1a2018-04-05 12:12:26 -070025#include "rtc_base/logging.h"
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070026#include "rtc_base/numerics/safe_conversions.h"
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070027#include "rtc_base/opensslcertificate.h"
Mirko Bonadeib889a202018-08-15 11:41:27 +020028#ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070029#include "rtc_base/sslroots.h"
Mirko Bonadeib889a202018-08-15 11:41:27 +020030#endif // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
Benjamin Wright9201d1a2018-04-05 12:12:26 -070031
32namespace rtc {
33namespace openssl {
34
35// Holds various helper methods.
36namespace {
37void LogCertificates(SSL* ssl, X509* certificate) {
38// Logging certificates is extremely verbose. So it is disabled by default.
39#ifdef LOG_CERTIFICATES
40 BIO* mem = BIO_new(BIO_s_mem());
41 if (mem == nullptr) {
42 RTC_DLOG(LS_ERROR) << "BIO_new() failed to allocate memory.";
43 return;
44 }
45
46 RTC_DLOG(LS_INFO) << "Certificate from server:";
47 X509_print_ex(mem, certificate, XN_FLAG_SEP_CPLUS_SPC, X509_FLAG_NO_HEADER);
48 BIO_write(mem, "\0", 1);
49
50 char* buffer = nullptr;
51 BIO_get_mem_data(mem, &buffer);
52 if (buffer != nullptr) {
53 RTC_DLOG(LS_INFO) << buffer;
54 } else {
55 RTC_DLOG(LS_ERROR) << "BIO_get_mem_data() failed to get buffer.";
56 }
57 BIO_free(mem);
58
59 const char* cipher_name = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
60 if (cipher_name != nullptr) {
61 RTC_DLOG(LS_INFO) << "Cipher: " << cipher_name;
62 } else {
63 RTC_DLOG(LS_ERROR) << "SSL_CIPHER_DESCRIPTION() failed to get cipher_name.";
64 }
65#endif
66}
67} // namespace
68
69bool VerifyPeerCertMatchesHost(SSL* ssl, const std::string& host) {
70 if (host.empty()) {
71 RTC_DLOG(LS_ERROR) << "Hostname is empty. Cannot verify peer certificate.";
72 return false;
73 }
74
75 if (ssl == nullptr) {
76 RTC_DLOG(LS_ERROR) << "SSL is nullptr. Cannot verify peer certificate.";
77 return false;
78 }
79
80 X509* certificate = SSL_get_peer_certificate(ssl);
81 if (certificate == nullptr) {
82 RTC_DLOG(LS_ERROR)
83 << "SSL_get_peer_certificate failed. This should never happen.";
84 return false;
85 }
86
87 LogCertificates(ssl, certificate);
88
89 bool is_valid_cert_name =
90 X509_check_host(certificate, host.c_str(), host.size(), 0, nullptr) == 1;
91 X509_free(certificate);
92 return is_valid_cert_name;
93}
94
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070095void LogSSLErrors(const std::string& prefix) {
96 char error_buf[200];
97 unsigned long err; // NOLINT
98
99 while ((err = ERR_get_error()) != 0) {
100 ERR_error_string_n(err, error_buf, sizeof(error_buf));
101 RTC_LOG(LS_ERROR) << prefix << ": " << error_buf << "\n";
102 }
103}
104
Mirko Bonadeib889a202018-08-15 11:41:27 +0200105#ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700106bool LoadBuiltinSSLRootCertificates(SSL_CTX* ctx) {
107 int count_of_added_certs = 0;
108 for (size_t i = 0; i < arraysize(kSSLCertCertificateList); i++) {
109 const unsigned char* cert_buffer = kSSLCertCertificateList[i];
110 size_t cert_buffer_len = kSSLCertCertificateSizeList[i];
111 X509* cert = d2i_X509(nullptr, &cert_buffer,
112 checked_cast<long>(cert_buffer_len)); // NOLINT
113 if (cert) {
114 int return_value = X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx), cert);
115 if (return_value == 0) {
116 RTC_LOG(LS_WARNING) << "Unable to add certificate.";
117 } else {
118 count_of_added_certs++;
119 }
120 X509_free(cert);
121 }
122 }
123 return count_of_added_certs > 0;
124}
Mirko Bonadeib889a202018-08-15 11:41:27 +0200125#endif // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700126
Benjamin Wright9201d1a2018-04-05 12:12:26 -0700127} // namespace openssl
128} // namespace rtc