chromium/third_party/webrtc/rtc_base/openssl_stream_adapter.cc

/*
 *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "rtc_base/openssl_stream_adapter.h"

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/stack.h>
#include <openssl/tls1.h>

#include <cstddef>
#include <cstdint>
#include <cstring>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "api/array_view.h"
#include "api/sequence_checker.h"
#include "api/task_queue/pending_task_safety_flag.h"
#include "api/units/time_delta.h"
#include "rtc_base/buffer.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/openssl_adapter.h"
#include "rtc_base/openssl_digest.h"
#include "rtc_base/ssl_identity.h"
#include "rtc_base/ssl_stream_adapter.h"
#include "rtc_base/task_utils/repeating_task.h"
#ifdef OPENSSL_IS_BORINGSSL
#include <openssl/base.h>
#include <openssl/digest.h>
#include <openssl/dtls1.h>
#include <openssl/pool.h>
#include <openssl/ssl.h>

#include "rtc_base/boringssl_certificate.h"
#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/string_encode.h"
#include "rtc_base/thread.h"
#include "rtc_base/time_utils.h"
#include "system_wrappers/include/field_trial.h"

#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
#error "webrtc requires at least OpenSSL version 1.1.0, to support DTLS-SRTP"
#endif

// Defines for the TLS Cipher Suite Map.
#define DEFINE_CIPHER_ENTRY_SSL3(name)
#define DEFINE_CIPHER_ENTRY_TLS1(name)

namespace rtc {
namespace {
SafeTask;
// SRTP cipher suite table. `internal_name` is used to construct a
// colon-separated profile strings which is needed by
// SSL_CTX_set_tlsext_use_srtp().
struct SrtpCipherMapEntry {};

// Cipher name table. Maps internal OpenSSL cipher ids to the RFC name.
struct SslCipherMapEntry {};

// This isn't elegant, but it's better than an external reference
constexpr SrtpCipherMapEntry kSrtpCipherMap[] =;

#ifndef OPENSSL_IS_BORINGSSL
// The "SSL_CIPHER_standard_name" function is only available in OpenSSL when
// compiled with tracing, so we need to define the mapping manually here.
constexpr SslCipherMapEntry kSslCipherMap[] = {
    // TLS v1.0 ciphersuites from RFC2246.
    DEFINE_CIPHER_ENTRY_SSL3(RSA_RC4_128_SHA),
    {SSL3_CK_RSA_DES_192_CBC3_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},

    // AES ciphersuites from RFC3268.
    {TLS1_CK_RSA_WITH_AES_128_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"},
    {TLS1_CK_DHE_RSA_WITH_AES_128_SHA, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"},
    {TLS1_CK_RSA_WITH_AES_256_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA"},
    {TLS1_CK_DHE_RSA_WITH_AES_256_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},

    // ECC ciphersuites from RFC4492.
    DEFINE_CIPHER_ENTRY_TLS1(ECDHE_ECDSA_WITH_RC4_128_SHA),
    {TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA,
     "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"},
    DEFINE_CIPHER_ENTRY_TLS1(ECDHE_ECDSA_WITH_AES_128_CBC_SHA),
    DEFINE_CIPHER_ENTRY_TLS1(ECDHE_ECDSA_WITH_AES_256_CBC_SHA),

    DEFINE_CIPHER_ENTRY_TLS1(ECDHE_RSA_WITH_RC4_128_SHA),
    {TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA,
     "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"},
    DEFINE_CIPHER_ENTRY_TLS1(ECDHE_RSA_WITH_AES_128_CBC_SHA),
    DEFINE_CIPHER_ENTRY_TLS1(ECDHE_RSA_WITH_AES_256_CBC_SHA),

    // TLS v1.2 ciphersuites.
    {TLS1_CK_RSA_WITH_AES_128_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256"},
    {TLS1_CK_RSA_WITH_AES_256_SHA256, "TLS_RSA_WITH_AES_256_CBC_SHA256"},
    {TLS1_CK_DHE_RSA_WITH_AES_128_SHA256,
     "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"},
    {TLS1_CK_DHE_RSA_WITH_AES_256_SHA256,
     "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},

    // TLS v1.2 GCM ciphersuites from RFC5288.
    DEFINE_CIPHER_ENTRY_TLS1(RSA_WITH_AES_128_GCM_SHA256),
    DEFINE_CIPHER_ENTRY_TLS1(RSA_WITH_AES_256_GCM_SHA384),
    DEFINE_CIPHER_ENTRY_TLS1(DHE_RSA_WITH_AES_128_GCM_SHA256),
    DEFINE_CIPHER_ENTRY_TLS1(DHE_RSA_WITH_AES_256_GCM_SHA384),
    DEFINE_CIPHER_ENTRY_TLS1(DH_RSA_WITH_AES_128_GCM_SHA256),
    DEFINE_CIPHER_ENTRY_TLS1(DH_RSA_WITH_AES_256_GCM_SHA384),

    // ECDH HMAC based ciphersuites from RFC5289.
    {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256,
     "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"},
    {TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384,
     "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"},
    {TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256,
     "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"},
    {TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384,
     "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"},

    // ECDH GCM based ciphersuites from RFC5289.
    DEFINE_CIPHER_ENTRY_TLS1(ECDHE_ECDSA_WITH_AES_128_GCM_SHA256),
    DEFINE_CIPHER_ENTRY_TLS1(ECDHE_ECDSA_WITH_AES_256_GCM_SHA384),
    DEFINE_CIPHER_ENTRY_TLS1(ECDHE_RSA_WITH_AES_128_GCM_SHA256),
    DEFINE_CIPHER_ENTRY_TLS1(ECDHE_RSA_WITH_AES_256_GCM_SHA384),

    {0, nullptr}};
#endif  // #ifndef OPENSSL_IS_BORINGSSL

#ifdef OPENSSL_IS_BORINGSSL
// Enabled by EnableTimeCallbackForTesting. Should never be set in production
// code.
bool g_use_time_callback_for_testing =;
// Not used in production code. Actual time should be relative to Jan 1, 1970.
void TimeCallbackForTesting(const SSL* ssl, struct timeval* out_clock) {}
#endif

}  // namespace

//////////////////////////////////////////////////////////////////////
// StreamBIO
//////////////////////////////////////////////////////////////////////

static int stream_write(BIO* h, const char* buf, int num);
static int stream_read(BIO* h, char* buf, int size);
static int stream_puts(BIO* h, const char* str);
static long stream_ctrl(BIO* h, int cmd, long arg1, void* arg2);
static int stream_new(BIO* h);
static int stream_free(BIO* data);

static BIO_METHOD* BIO_stream_method() {}

static BIO* BIO_new_stream(StreamInterface* stream) {}

// bio methods return 1 (or at least non-zero) on success and 0 on failure.

static int stream_new(BIO* b) {}

static int stream_free(BIO* b) {}

static int stream_read(BIO* b, char* out, int outl) {}

static int stream_write(BIO* b, const char* in, int inl) {}

static int stream_puts(BIO* b, const char* str) {}

static long stream_ctrl(BIO* b, int cmd, long num, void* ptr) {}

/////////////////////////////////////////////////////////////////////////////
// OpenSSLStreamAdapter
/////////////////////////////////////////////////////////////////////////////

OpenSSLStreamAdapter::OpenSSLStreamAdapter(
    std::unique_ptr<StreamInterface> stream,
    absl::AnyInvocable<void(SSLHandshakeError)> handshake_error)
    :{}

OpenSSLStreamAdapter::~OpenSSLStreamAdapter() {}

void OpenSSLStreamAdapter::SetIdentity(std::unique_ptr<SSLIdentity> identity) {}

SSLIdentity* OpenSSLStreamAdapter::GetIdentityForTesting() const {}

void OpenSSLStreamAdapter::SetServerRole(SSLRole role) {}

bool OpenSSLStreamAdapter::SetPeerCertificateDigest(
    absl::string_view digest_alg,
    const unsigned char* digest_val,
    size_t digest_len,
    SSLPeerCertificateDigestError* error) {}

std::string OpenSSLStreamAdapter::SslCipherSuiteToName(int cipher_suite) {}

bool OpenSSLStreamAdapter::GetSslCipherSuite(int* cipher_suite) {}

SSLProtocolVersion OpenSSLStreamAdapter::GetSslVersion() const {}

bool OpenSSLStreamAdapter::GetSslVersionBytes(int* version) const {}

// Key Extractor interface
bool OpenSSLStreamAdapter::ExportKeyingMaterial(absl::string_view label,
                                                const uint8_t* context,
                                                size_t context_len,
                                                bool use_context,
                                                uint8_t* result,
                                                size_t result_len) {}

uint16_t OpenSSLStreamAdapter::GetPeerSignatureAlgorithm() const {}

bool OpenSSLStreamAdapter::SetDtlsSrtpCryptoSuites(
    const std::vector<int>& ciphers) {}

bool OpenSSLStreamAdapter::GetDtlsSrtpCryptoSuite(int* crypto_suite) {}

bool OpenSSLStreamAdapter::IsTlsConnected() {}

int OpenSSLStreamAdapter::StartSSL() {}

void OpenSSLStreamAdapter::SetMode(SSLMode mode) {}

void OpenSSLStreamAdapter::SetMaxProtocolVersion(SSLProtocolVersion version) {}

void OpenSSLStreamAdapter::SetInitialRetransmissionTimeout(int timeout_ms) {}

//
// StreamInterface Implementation
//
StreamResult OpenSSLStreamAdapter::Write(rtc::ArrayView<const uint8_t> data,
                                         size_t& written,
                                         int& error) {}

StreamResult OpenSSLStreamAdapter::Read(rtc::ArrayView<uint8_t> data,
                                        size_t& read,
                                        int& error) {}

void OpenSSLStreamAdapter::FlushInput(unsigned int left) {}

void OpenSSLStreamAdapter::Close() {}

StreamState OpenSSLStreamAdapter::GetState() const {}

void OpenSSLStreamAdapter::OnEvent(int events, int err) {}

void OpenSSLStreamAdapter::PostEvent(int events, int err) {}

void OpenSSLStreamAdapter::SetTimeout(int delay_ms) {}

int OpenSSLStreamAdapter::BeginSSL() {}

int OpenSSLStreamAdapter::ContinueSSL() {}

void OpenSSLStreamAdapter::Error(absl::string_view context,
                                 int err,
                                 uint8_t alert,
                                 bool signal) {}

void OpenSSLStreamAdapter::Cleanup(uint8_t alert) {}

SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() {}

bool OpenSSLStreamAdapter::VerifyPeerCertificate() {}

std::unique_ptr<SSLCertChain> OpenSSLStreamAdapter::GetPeerSSLCertChain()
    const {}

#ifdef OPENSSL_IS_BORINGSSL
enum ssl_verify_result_t OpenSSLStreamAdapter::SSLVerifyCallback(
    SSL* ssl,
    uint8_t* out_alert) {}
#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*>(
      X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx()));
  OpenSSLStreamAdapter* stream =
      reinterpret_cast<OpenSSLStreamAdapter*>(SSL_get_app_data(ssl));

  // 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)));

  // 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_DLOG(LS_INFO) << "Waiting to verify certificate until digest is known.";
    return 1;
  }

  if (!stream->VerifyPeerCertificate()) {
    X509_STORE_CTX_set_error(store, X509_V_ERR_CERT_REJECTED);
    return 0;
  }

  return 1;
}
#endif  // !OPENSSL_IS_BORINGSSL

bool OpenSSLStreamAdapter::IsBoringSsl() {}

#define CDEF

struct cipher_list {};

// TODO(torbjorng): Perhaps add more cipher suites to these lists.
static const cipher_list OK_RSA_ciphers[] =;

static const cipher_list OK_ECDSA_ciphers[] =;
#undef CDEF

bool OpenSSLStreamAdapter::IsAcceptableCipher(int cipher, KeyType key_type) {}

bool OpenSSLStreamAdapter::IsAcceptableCipher(absl::string_view cipher,
                                              KeyType key_type) {}

void OpenSSLStreamAdapter::EnableTimeCallbackForTesting() {}

}  // namespace rtc