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
@ -32,7 +32,12 @@
|
||||
#include "rtc_base/openssl.h"
|
||||
#include "rtc_base/openssl_adapter.h"
|
||||
#include "rtc_base/openssl_digest.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/ssl_certificate.h"
|
||||
#include "rtc_base/stream.h"
|
||||
#include "rtc_base/task_utils/to_queued_task.h"
|
||||
@ -304,10 +309,14 @@ OpenSSLStreamAdapter::~OpenSSLStreamAdapter() {
|
||||
|
||||
void OpenSSLStreamAdapter::SetIdentity(std::unique_ptr<SSLIdentity> identity) {
|
||||
RTC_DCHECK(!identity_);
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
identity_.reset(static_cast<BoringSSLIdentity*>(identity.release()));
|
||||
#else
|
||||
identity_.reset(static_cast<OpenSSLIdentity*>(identity.release()));
|
||||
#endif
|
||||
}
|
||||
|
||||
OpenSSLIdentity* OpenSSLStreamAdapter::GetIdentityForTesting() const {
|
||||
SSLIdentity* OpenSSLStreamAdapter::GetIdentityForTesting() const {
|
||||
return identity_.get();
|
||||
}
|
||||
|
||||
@ -994,8 +1003,16 @@ void OpenSSLStreamAdapter::Cleanup(uint8_t alert) {
|
||||
}
|
||||
|
||||
SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() {
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
// If X509 objects aren't used, we can use these methods to avoid
|
||||
// linking the sizable crypto/x509 code, using CRYPTO_BUFFER instead.
|
||||
SSL_CTX* ctx =
|
||||
SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ? DTLS_with_buffers_method()
|
||||
: TLS_with_buffers_method());
|
||||
#else
|
||||
SSL_CTX* ctx =
|
||||
SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ? DTLS_method() : TLS_method());
|
||||
#endif
|
||||
if (ctx == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -1033,6 +1050,7 @@ SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() {
|
||||
if (g_use_time_callback_for_testing) {
|
||||
SSL_CTX_set_current_time_cb(ctx, &TimeCallbackForTesting);
|
||||
}
|
||||
SSL_CTX_set0_buffer_pool(ctx, openssl::GetBufferPool());
|
||||
#endif
|
||||
|
||||
if (identity_ && !identity_->ConfigureIdentity(ctx)) {
|
||||
@ -1053,11 +1071,16 @@ SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() {
|
||||
}
|
||||
|
||||
// Configure a custom certificate verification callback to check the peer
|
||||
// certificate digest. Note the second argument to SSL_CTX_set_verify is to
|
||||
// override individual errors in the default verification logic, which is not
|
||||
// what we want here.
|
||||
// certificate digest.
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
// Use CRYPTO_BUFFER version of the callback if building with BoringSSL.
|
||||
SSL_CTX_set_custom_verify(ctx, mode, SSLVerifyCallback);
|
||||
#else
|
||||
// Note the second argument to SSL_CTX_set_verify is to override individual
|
||||
// errors in the default verification logic, which is not what we want here.
|
||||
SSL_CTX_set_verify(ctx, mode, nullptr);
|
||||
SSL_CTX_set_cert_verify_callback(ctx, SSLVerifyCallback, nullptr);
|
||||
#endif
|
||||
|
||||
// Select list of available ciphers. Note that !SHA256 and !SHA384 only
|
||||
// remove HMAC-SHA256 and HMAC-SHA384 cipher suites, not GCM cipher suites
|
||||
@ -1082,14 +1105,12 @@ bool OpenSSLStreamAdapter::VerifyPeerCertificate() {
|
||||
RTC_LOG(LS_WARNING) << "Missing digest or peer certificate.";
|
||||
return false;
|
||||
}
|
||||
const OpenSSLCertificate* leaf_cert =
|
||||
static_cast<const OpenSSLCertificate*>(&peer_cert_chain_->Get(0));
|
||||
|
||||
unsigned char digest[EVP_MAX_MD_SIZE];
|
||||
size_t digest_length;
|
||||
if (!OpenSSLCertificate::ComputeDigest(
|
||||
leaf_cert->x509(), peer_certificate_digest_algorithm_, digest,
|
||||
sizeof(digest), &digest_length)) {
|
||||
if (!peer_cert_chain_->Get(0).ComputeDigest(
|
||||
peer_certificate_digest_algorithm_, digest, sizeof(digest),
|
||||
&digest_length)) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to compute peer cert digest.";
|
||||
return false;
|
||||
}
|
||||
@ -1113,6 +1134,36 @@ std::unique_ptr<SSLCertChain> OpenSSLStreamAdapter::GetPeerSSLCertChain()
|
||||
return peer_cert_chain_ ? peer_cert_chain_->Clone() : nullptr;
|
||||
}
|
||||
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
enum ssl_verify_result_t OpenSSLStreamAdapter::SSLVerifyCallback(
|
||||
SSL* ssl,
|
||||
uint8_t* out_alert) {
|
||||
// Get our OpenSSLStreamAdapter from the context.
|
||||
OpenSSLStreamAdapter* stream =
|
||||
reinterpret_cast<OpenSSLStreamAdapter*>(SSL_get_app_data(ssl));
|
||||
const STACK_OF(CRYPTO_BUFFER)* chain = SSL_get0_peer_certificates(ssl);
|
||||
// Creates certificate chain.
|
||||
std::vector<std::unique_ptr<SSLCertificate>> cert_chain;
|
||||
for (CRYPTO_BUFFER* cert : chain) {
|
||||
cert_chain.emplace_back(new BoringSSLCertificate(bssl::UpRef(cert)));
|
||||
}
|
||||
stream->peer_cert_chain_.reset(new SSLCertChain(std::move(cert_chain)));
|
||||
|
||||
// If the peer certificate digest isn't known yet, we'll wait to verify
|
||||
// until it's known, and for now just return a success status.
|
||||
if (stream->peer_certificate_digest_algorithm_.empty()) {
|
||||
RTC_LOG(LS_INFO) << "Waiting to verify certificate until digest is known.";
|
||||
// TODO(deadbeef): Use ssl_verify_retry?
|
||||
return ssl_verify_ok;
|
||||
}
|
||||
|
||||
if (!stream->VerifyPeerCertificate()) {
|
||||
return ssl_verify_invalid;
|
||||
}
|
||||
|
||||
return ssl_verify_ok;
|
||||
}
|
||||
#else // OPENSSL_IS_BORINGSSL
|
||||
int OpenSSLStreamAdapter::SSLVerifyCallback(X509_STORE_CTX* store, void* arg) {
|
||||
// Get our SSL structure and OpenSSLStreamAdapter from the store.
|
||||
SSL* ssl = reinterpret_cast<SSL*>(
|
||||
@ -1120,20 +1171,10 @@ int OpenSSLStreamAdapter::SSLVerifyCallback(X509_STORE_CTX* store, void* arg) {
|
||||
OpenSSLStreamAdapter* stream =
|
||||
reinterpret_cast<OpenSSLStreamAdapter*>(SSL_get_app_data(ssl));
|
||||
|
||||
#if defined(OPENSSL_IS_BORINGSSL)
|
||||
STACK_OF(X509)* chain = SSL_get_peer_full_cert_chain(ssl);
|
||||
// Creates certificate chain.
|
||||
std::vector<std::unique_ptr<SSLCertificate>> cert_chain;
|
||||
for (X509* cert : chain) {
|
||||
cert_chain.emplace_back(new OpenSSLCertificate(cert));
|
||||
}
|
||||
stream->peer_cert_chain_.reset(new SSLCertChain(std::move(cert_chain)));
|
||||
#else
|
||||
// Record the peer's certificate.
|
||||
X509* cert = X509_STORE_CTX_get0_cert(store);
|
||||
stream->peer_cert_chain_.reset(
|
||||
new SSLCertChain(std::make_unique<OpenSSLCertificate>(cert)));
|
||||
#endif
|
||||
|
||||
// If the peer certificate digest isn't known yet, we'll wait to verify
|
||||
// until it's known, and for now just return a success status.
|
||||
@ -1149,6 +1190,7 @@ int OpenSSLStreamAdapter::SSLVerifyCallback(X509_STORE_CTX* store, void* arg) {
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif // !OPENSSL_IS_BORINGSSL
|
||||
|
||||
bool OpenSSLStreamAdapter::IsBoringSsl() {
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
|
||||
Reference in New Issue
Block a user