Reland: Use CRYPTO_BUFFER APIs instead of X509 when building with BoringSSL.
Using CRYPTO_BUFFERs instead of legacy X509 objects offers memory and security gains, and will provide binary size improvements as well once the default list of built-in certificates can be removed; the code dealing with them still depends on the X509 API. Implemented by splitting openssl_identity and openssl_certificate into BoringSSL and vanilla OpenSSL implementations. No-Try: True Bug: webrtc:11410 Change-Id: I86ddb361b94ad85b15ebb8743490de83632ca53f Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/196941 Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Cr-Commit-Position: refs/heads/master@{#32818}
This commit is contained in:
committed by
Commit Bot
parent
c1ad1ff178
commit
165c618bb9
@ -13,6 +13,9 @@
|
||||
#include <errno.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
#include <openssl/pool.h>
|
||||
#endif
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <string.h>
|
||||
@ -20,13 +23,24 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
// Use CRYPTO_BUFFER APIs if available and we have no dependency on X509
|
||||
// objects.
|
||||
#if defined(OPENSSL_IS_BORINGSSL) && \
|
||||
defined(WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS)
|
||||
#define WEBRTC_USE_CRYPTO_BUFFER_CALLBACK
|
||||
#endif
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/location.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
#include "rtc_base/openssl.h"
|
||||
#include "rtc_base/openssl_certificate.h"
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
#include "rtc_base/boringssl_identity.h"
|
||||
#else
|
||||
#include "rtc_base/openssl_identity.h"
|
||||
#endif
|
||||
#include "rtc_base/openssl_utility.h"
|
||||
#include "rtc_base/string_encode.h"
|
||||
#include "rtc_base/thread.h"
|
||||
@ -223,8 +237,13 @@ void OpenSSLAdapter::SetCertVerifier(
|
||||
|
||||
void OpenSSLAdapter::SetIdentity(std::unique_ptr<SSLIdentity> identity) {
|
||||
RTC_DCHECK(!identity_);
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
identity_ =
|
||||
absl::WrapUnique(static_cast<BoringSSLIdentity*>(identity.release()));
|
||||
#else
|
||||
identity_ =
|
||||
absl::WrapUnique(static_cast<OpenSSLIdentity*>(identity.release()));
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenSSLAdapter::SetRole(SSLRole role) {
|
||||
@ -797,7 +816,70 @@ void OpenSSLAdapter::SSLInfoCallback(const SSL* s, int where, int ret) {
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WEBRTC_USE_CRYPTO_BUFFER_CALLBACK
|
||||
// static
|
||||
enum ssl_verify_result_t OpenSSLAdapter::SSLVerifyCallback(SSL* ssl,
|
||||
uint8_t* out_alert) {
|
||||
// Get our stream pointer from the SSL context.
|
||||
OpenSSLAdapter* stream =
|
||||
reinterpret_cast<OpenSSLAdapter*>(SSL_get_app_data(ssl));
|
||||
|
||||
ssl_verify_result_t ret = stream->SSLVerifyInternal(ssl, out_alert);
|
||||
|
||||
// Should only be used for debugging and development.
|
||||
if (ret != ssl_verify_ok && stream->ignore_bad_cert_) {
|
||||
RTC_DLOG(LS_WARNING) << "Ignoring cert error while verifying cert chain";
|
||||
return ssl_verify_ok;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum ssl_verify_result_t OpenSSLAdapter::SSLVerifyInternal(SSL* ssl,
|
||||
uint8_t* out_alert) {
|
||||
if (ssl_cert_verifier_ == nullptr) {
|
||||
RTC_LOG(LS_WARNING) << "Built-in trusted root certificates disabled but no "
|
||||
"SSL verify callback provided.";
|
||||
return ssl_verify_invalid;
|
||||
}
|
||||
|
||||
RTC_LOG(LS_INFO) << "Invoking SSL Verify Callback.";
|
||||
const STACK_OF(CRYPTO_BUFFER)* chain = SSL_get0_peer_certificates(ssl);
|
||||
if (sk_CRYPTO_BUFFER_num(chain) == 0) {
|
||||
RTC_LOG(LS_ERROR) << "Peer certificate chain empty?";
|
||||
return ssl_verify_invalid;
|
||||
}
|
||||
|
||||
BoringSSLCertificate cert(bssl::UpRef(sk_CRYPTO_BUFFER_value(chain, 0)));
|
||||
if (!ssl_cert_verifier_->Verify(cert)) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to verify certificate using custom callback";
|
||||
return ssl_verify_invalid;
|
||||
}
|
||||
|
||||
custom_cert_verifier_status_ = true;
|
||||
RTC_LOG(LS_INFO) << "Validated certificate using custom callback";
|
||||
return ssl_verify_ok;
|
||||
}
|
||||
#else // WEBRTC_USE_CRYPTO_BUFFER_CALLBACK
|
||||
int OpenSSLAdapter::SSLVerifyCallback(int ok, X509_STORE_CTX* store) {
|
||||
// Get our stream pointer from the store
|
||||
SSL* ssl = reinterpret_cast<SSL*>(
|
||||
X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx()));
|
||||
|
||||
OpenSSLAdapter* stream =
|
||||
reinterpret_cast<OpenSSLAdapter*>(SSL_get_app_data(ssl));
|
||||
ok = stream->SSLVerifyInternal(ok, ssl, store);
|
||||
|
||||
// Should only be used for debugging and development.
|
||||
if (!ok && stream->ignore_bad_cert_) {
|
||||
RTC_DLOG(LS_WARNING) << "Ignoring cert error while verifying cert chain";
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
int OpenSSLAdapter::SSLVerifyInternal(int ok, SSL* ssl, X509_STORE_CTX* store) {
|
||||
#if !defined(NDEBUG)
|
||||
if (!ok) {
|
||||
char data[256];
|
||||
@ -814,33 +896,40 @@ int OpenSSLAdapter::SSLVerifyCallback(int ok, X509_STORE_CTX* store) {
|
||||
<< X509_verify_cert_error_string(err);
|
||||
}
|
||||
#endif
|
||||
// Get our stream pointer from the store
|
||||
SSL* ssl = reinterpret_cast<SSL*>(
|
||||
X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx()));
|
||||
|
||||
OpenSSLAdapter* stream =
|
||||
reinterpret_cast<OpenSSLAdapter*>(SSL_get_app_data(ssl));
|
||||
|
||||
if (!ok && stream->ssl_cert_verifier_ != nullptr) {
|
||||
RTC_LOG(LS_INFO) << "Invoking SSL Verify Callback.";
|
||||
const OpenSSLCertificate cert(X509_STORE_CTX_get_current_cert(store));
|
||||
if (stream->ssl_cert_verifier_->Verify(cert)) {
|
||||
stream->custom_cert_verifier_status_ = true;
|
||||
RTC_LOG(LS_INFO) << "Validated certificate using custom callback";
|
||||
ok = true;
|
||||
} else {
|
||||
RTC_LOG(LS_INFO) << "Failed to verify certificate using custom callback";
|
||||
}
|
||||
if (ssl_cert_verifier_ == nullptr) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Should only be used for debugging and development.
|
||||
if (!ok && stream->ignore_bad_cert_) {
|
||||
RTC_DLOG(LS_WARNING) << "Ignoring cert error while verifying cert chain";
|
||||
ok = 1;
|
||||
RTC_LOG(LS_INFO) << "Invoking SSL Verify Callback.";
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
// Convert X509 to CRYPTO_BUFFER.
|
||||
uint8_t* data = nullptr;
|
||||
int length = i2d_X509(X509_STORE_CTX_get_current_cert(store), &data);
|
||||
if (length < 0) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to encode X509.";
|
||||
return ok;
|
||||
}
|
||||
bssl::UniquePtr<uint8_t> owned_data(data);
|
||||
bssl::UniquePtr<CRYPTO_BUFFER> crypto_buffer(
|
||||
CRYPTO_BUFFER_new(data, length, openssl::GetBufferPool()));
|
||||
if (!crypto_buffer) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to allocate CRYPTO_BUFFER.";
|
||||
return ok;
|
||||
}
|
||||
const BoringSSLCertificate cert(std::move(crypto_buffer));
|
||||
#else
|
||||
const OpenSSLCertificate cert(X509_STORE_CTX_get_current_cert(store));
|
||||
#endif
|
||||
if (!ssl_cert_verifier_->Verify(cert)) {
|
||||
RTC_LOG(LS_INFO) << "Failed to verify certificate using custom callback";
|
||||
return ok;
|
||||
}
|
||||
|
||||
return ok;
|
||||
custom_cert_verifier_status_ = true;
|
||||
RTC_LOG(LS_INFO) << "Validated certificate using custom callback";
|
||||
return 1;
|
||||
}
|
||||
#endif // !defined(WEBRTC_USE_CRYPTO_BUFFER_CALLBACK)
|
||||
|
||||
int OpenSSLAdapter::NewSSLSessionCallback(SSL* ssl, SSL_SESSION* session) {
|
||||
OpenSSLAdapter* stream =
|
||||
@ -852,8 +941,15 @@ int OpenSSLAdapter::NewSSLSessionCallback(SSL* ssl, SSL_SESSION* session) {
|
||||
}
|
||||
|
||||
SSL_CTX* OpenSSLAdapter::CreateContext(SSLMode mode, bool enable_cache) {
|
||||
#ifdef WEBRTC_USE_CRYPTO_BUFFER_CALLBACK
|
||||
// If X509 objects aren't used, we can use these methods to avoid
|
||||
// linking the sizable crypto/x509 code.
|
||||
SSL_CTX* ctx = SSL_CTX_new(mode == SSL_MODE_DTLS ? DTLS_with_buffers_method()
|
||||
: TLS_with_buffers_method());
|
||||
#else
|
||||
SSL_CTX* ctx =
|
||||
SSL_CTX_new(mode == SSL_MODE_DTLS ? DTLS_method() : TLS_method());
|
||||
#endif
|
||||
if (ctx == nullptr) {
|
||||
unsigned long error = ERR_get_error(); // NOLINT: type used by OpenSSL.
|
||||
RTC_LOG(LS_WARNING) << "SSL_CTX creation failed: " << '"'
|
||||
@ -877,8 +973,16 @@ SSL_CTX* OpenSSLAdapter::CreateContext(SSLMode mode, bool enable_cache) {
|
||||
SSL_CTX_set_info_callback(ctx, SSLInfoCallback);
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
SSL_CTX_set0_buffer_pool(ctx, openssl::GetBufferPool());
|
||||
#endif
|
||||
|
||||
#ifdef WEBRTC_USE_CRYPTO_BUFFER_CALLBACK
|
||||
SSL_CTX_set_custom_verify(ctx, SSL_VERIFY_PEER, SSLVerifyCallback);
|
||||
#else
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, SSLVerifyCallback);
|
||||
SSL_CTX_set_verify_depth(ctx, 4);
|
||||
#endif
|
||||
// Use defaults, but disable HMAC-SHA256 and HMAC-SHA384 ciphers
|
||||
// (note that SHA256 and SHA384 only select legacy CBC ciphers).
|
||||
// Additionally disable HMAC-SHA1 ciphers in ECDSA. These are the remaining
|
||||
|
||||
Reference in New Issue
Block a user