|  | /* | 
|  | *  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 <optional> | 
|  | #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/field_trials_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/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" | 
|  | #include "rtc_base/openssl.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" | 
|  |  | 
|  | #if (OPENSSL_VERSION_NUMBER < 0x10100000L) | 
|  | #error "webrtc requires at least OpenSSL version 1.1.0, to support DTLS-SRTP" | 
|  | #endif | 
|  |  | 
|  | namespace { | 
|  | // Value specified in RFC 5764. | 
|  | static constexpr absl::string_view kDtlsSrtpExporterLabel = | 
|  | "EXTRACTOR-dtls_srtp"; | 
|  | }  // namespace | 
|  |  | 
|  | namespace webrtc { | 
|  | namespace { | 
|  | using ::webrtc::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 { | 
|  | const char* internal_name; | 
|  | const int id; | 
|  | }; | 
|  |  | 
|  | // This isn't elegant, but it's better than an external reference | 
|  | constexpr SrtpCipherMapEntry kSrtpCipherMap[] = { | 
|  | {"SRTP_AES128_CM_SHA1_80", webrtc::kSrtpAes128CmSha1_80}, | 
|  | {"SRTP_AES128_CM_SHA1_32", webrtc::kSrtpAes128CmSha1_32}, | 
|  | {"SRTP_AEAD_AES_128_GCM", webrtc::kSrtpAeadAes128Gcm}, | 
|  | {"SRTP_AEAD_AES_256_GCM", webrtc::kSrtpAeadAes256Gcm}}; | 
|  |  | 
|  | #ifdef OPENSSL_IS_BORINGSSL | 
|  | // Enabled by EnableTimeCallbackForTesting. Should never be set in production | 
|  | // code. | 
|  | bool g_use_time_callback_for_testing = false; | 
|  | // Not used in production code. Actual time should be relative to Jan 1, 1970. | 
|  | void TimeCallbackForTesting(const SSL* ssl, struct timeval* out_clock) { | 
|  | int64_t time = webrtc::TimeNanos(); | 
|  | out_clock->tv_sec = time / webrtc::kNumNanosecsPerSec; | 
|  | out_clock->tv_usec = | 
|  | (time % webrtc::kNumNanosecsPerSec) / webrtc::kNumNanosecsPerMicrosec; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | uint16_t GetMaxVersion(SSLMode ssl_mode, SSLProtocolVersion version) { | 
|  | switch (ssl_mode) { | 
|  | case webrtc::SSL_MODE_TLS: | 
|  | switch (version) { | 
|  | default: | 
|  | case webrtc::SSL_PROTOCOL_NOT_GIVEN: | 
|  | case webrtc::SSL_PROTOCOL_TLS_10: | 
|  | case webrtc::SSL_PROTOCOL_TLS_11: | 
|  | case webrtc::SSL_PROTOCOL_TLS_12: | 
|  | return TLS1_2_VERSION; | 
|  | case webrtc::SSL_PROTOCOL_TLS_13: | 
|  | #ifdef TLS1_3_VERSION | 
|  | return TLS1_3_VERSION; | 
|  | #else | 
|  | return TLS1_2_VERSION; | 
|  | #endif | 
|  | } | 
|  | case webrtc::SSL_MODE_DTLS: | 
|  | switch (version) { | 
|  | default: | 
|  | case webrtc::SSL_PROTOCOL_NOT_GIVEN: | 
|  | case webrtc::SSL_PROTOCOL_DTLS_10: | 
|  | case webrtc::SSL_PROTOCOL_DTLS_12: | 
|  | return DTLS1_2_VERSION; | 
|  | case webrtc::SSL_PROTOCOL_DTLS_13: | 
|  | #ifdef DTLS1_3_VERSION | 
|  | return DTLS1_3_VERSION; | 
|  | #else | 
|  | return DTLS1_2_VERSION; | 
|  | #endif | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | constexpr int kForceDtls13Off = 0; | 
|  | #ifdef DTLS1_3_VERSION | 
|  | constexpr int kForceDtls13Enabled = 1; | 
|  | constexpr int kForceDtls13Only = 2; | 
|  | #endif | 
|  |  | 
|  | int GetForceDtls13(const FieldTrialsView* field_trials) { | 
|  | if (field_trials == nullptr) { | 
|  | return kForceDtls13Off; | 
|  | } | 
|  | #ifdef DTLS1_3_VERSION | 
|  | auto mode = field_trials->Lookup("WebRTC-ForceDtls13"); | 
|  | RTC_LOG(LS_WARNING) << "WebRTC-ForceDtls13: " << mode; | 
|  | if (mode == "Enabled") { | 
|  | return kForceDtls13Enabled; | 
|  | } else if (mode == "Only") { | 
|  | return kForceDtls13Only; | 
|  | } | 
|  | #endif | 
|  | return kForceDtls13Off; | 
|  | } | 
|  |  | 
|  | }  // 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_METHOD* method = [] { | 
|  | BIO_METHOD* method = BIO_meth_new(BIO_TYPE_BIO, "stream"); | 
|  | BIO_meth_set_write(method, stream_write); | 
|  | BIO_meth_set_read(method, stream_read); | 
|  | BIO_meth_set_puts(method, stream_puts); | 
|  | BIO_meth_set_ctrl(method, stream_ctrl); | 
|  | BIO_meth_set_create(method, stream_new); | 
|  | BIO_meth_set_destroy(method, stream_free); | 
|  | return method; | 
|  | }(); | 
|  | return method; | 
|  | } | 
|  |  | 
|  | static BIO* BIO_new_stream(StreamInterface* stream) { | 
|  | BIO* ret = BIO_new(BIO_stream_method()); | 
|  | if (ret == nullptr) { | 
|  | return nullptr; | 
|  | } | 
|  | BIO_set_data(ret, stream); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | // bio methods return 1 (or at least non-zero) on success and 0 on failure. | 
|  |  | 
|  | static int stream_new(BIO* b) { | 
|  | BIO_set_shutdown(b, 0); | 
|  | BIO_set_init(b, 1); | 
|  | BIO_set_data(b, 0); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int stream_free(BIO* b) { | 
|  | if (b == nullptr) { | 
|  | return 0; | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int stream_read(BIO* b, char* out, int outl) { | 
|  | if (!out) { | 
|  | return -1; | 
|  | } | 
|  | StreamInterface* stream = static_cast<StreamInterface*>(BIO_get_data(b)); | 
|  | BIO_clear_retry_flags(b); | 
|  | size_t read; | 
|  | int error; | 
|  | StreamResult result = stream->Read( | 
|  | MakeArrayView(reinterpret_cast<uint8_t*>(out), outl), read, error); | 
|  | if (result == webrtc::SR_SUCCESS) { | 
|  | return webrtc::checked_cast<int>(read); | 
|  | } else if (result == webrtc::SR_BLOCK) { | 
|  | BIO_set_retry_read(b); | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | static int stream_write(BIO* b, const char* in, int inl) { | 
|  | if (!in) { | 
|  | return -1; | 
|  | } | 
|  | StreamInterface* stream = static_cast<StreamInterface*>(BIO_get_data(b)); | 
|  | BIO_clear_retry_flags(b); | 
|  | size_t written; | 
|  | int error; | 
|  | StreamResult result = stream->Write( | 
|  | MakeArrayView(reinterpret_cast<const uint8_t*>(in), inl), written, error); | 
|  | if (result == webrtc::SR_SUCCESS) { | 
|  | return webrtc::checked_cast<int>(written); | 
|  | } else if (result == webrtc::SR_BLOCK) { | 
|  | BIO_set_retry_write(b); | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | static int stream_puts(BIO* b, const char* str) { | 
|  | return stream_write(b, str, webrtc::checked_cast<int>(strlen(str))); | 
|  | } | 
|  |  | 
|  | static long stream_ctrl(BIO* b, int cmd, long num, void* ptr) { | 
|  | switch (cmd) { | 
|  | case BIO_CTRL_RESET: | 
|  | return 0; | 
|  | case BIO_CTRL_EOF: { | 
|  | StreamInterface* stream = static_cast<StreamInterface*>(ptr); | 
|  | // 1 means end-of-stream. | 
|  | return (stream->GetState() == webrtc::SS_CLOSED) ? 1 : 0; | 
|  | } | 
|  | case BIO_CTRL_WPENDING: | 
|  | case BIO_CTRL_PENDING: | 
|  | return 0; | 
|  | case BIO_CTRL_FLUSH: { | 
|  | StreamInterface* stream = static_cast<StreamInterface*>(BIO_get_data(b)); | 
|  | RTC_DCHECK(stream); | 
|  | if (stream->Flush()) { | 
|  | RTC_LOG(LS_WARNING) << "Failed to flush stream"; | 
|  | return 0; | 
|  | } | 
|  | return 1; | 
|  | } | 
|  | case BIO_CTRL_DGRAM_QUERY_MTU: | 
|  | // openssl defaults to mtu=256 unless we return something here. | 
|  | // The handshake doesn't actually need to send packets above 1k, | 
|  | // so this seems like a sensible value that should work in most cases. | 
|  | // Webrtc uses the same value for video packets. | 
|  | RTC_DCHECK_NOTREACHED() | 
|  | << "We should be using SSL_set_mtu instead of this!"; | 
|  | return 1200; | 
|  | default: | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | ///////////////////////////////////////////////////////////////////////////// | 
|  | // OpenSSLStreamAdapter | 
|  | ///////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | OpenSSLStreamAdapter::OpenSSLStreamAdapter( | 
|  | std::unique_ptr<StreamInterface> stream, | 
|  | absl::AnyInvocable<void(SSLHandshakeError)> handshake_error, | 
|  | const FieldTrialsView* field_trials) | 
|  | : stream_(std::move(stream)), | 
|  | handshake_error_(std::move(handshake_error)), | 
|  | owner_(Thread::Current()), | 
|  | state_(SSL_NONE), | 
|  | role_(webrtc::SSL_CLIENT), | 
|  | ssl_read_needs_write_(false), | 
|  | ssl_write_needs_read_(false), | 
|  | ssl_(nullptr), | 
|  | ssl_ctx_(nullptr), | 
|  | ssl_mode_(webrtc::SSL_MODE_DTLS), | 
|  | ssl_max_version_(webrtc::SSL_PROTOCOL_DTLS_12), | 
|  | force_dtls_13_(GetForceDtls13(field_trials)), | 
|  | enable_dtls_pqc_(field_trials && | 
|  | field_trials->IsEnabled("WebRTC-EnableDtlsPqc")) { | 
|  | stream_->SetEventCallback( | 
|  | [this](int events, int err) { OnEvent(events, err); }); | 
|  | } | 
|  |  | 
|  | OpenSSLStreamAdapter::~OpenSSLStreamAdapter() { | 
|  | timeout_task_.Stop(); | 
|  | Cleanup(0); | 
|  | } | 
|  |  | 
|  | 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<webrtc::OpenSSLIdentity*>(identity.release())); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | SSLIdentity* OpenSSLStreamAdapter::GetIdentityForTesting() const { | 
|  | return identity_.get(); | 
|  | } | 
|  |  | 
|  | void OpenSSLStreamAdapter::SetServerRole(SSLRole role) { | 
|  | role_ = role; | 
|  | } | 
|  |  | 
|  | SSLPeerCertificateDigestError OpenSSLStreamAdapter::SetPeerCertificateDigest( | 
|  | absl::string_view digest_alg, | 
|  | ArrayView<const uint8_t> digest_val) { | 
|  | RTC_DCHECK(!peer_certificate_verified_); | 
|  | RTC_DCHECK(!HasPeerCertificateDigest()); | 
|  | size_t expected_len; | 
|  |  | 
|  | if (!OpenSSLDigest::GetDigestSize(digest_alg, &expected_len)) { | 
|  | RTC_LOG(LS_WARNING) << "Unknown digest algorithm: " << digest_alg; | 
|  | return SSLPeerCertificateDigestError::UNKNOWN_ALGORITHM; | 
|  | } | 
|  | if (expected_len != digest_val.size()) { | 
|  | return SSLPeerCertificateDigestError::INVALID_LENGTH; | 
|  | } | 
|  |  | 
|  | peer_certificate_digest_value_.SetData(digest_val); | 
|  | peer_certificate_digest_algorithm_ = std::string(digest_alg); | 
|  |  | 
|  | if (!peer_cert_chain_) { | 
|  | // Normal case, where the digest is set before we obtain the certificate | 
|  | // from the handshake. | 
|  | return SSLPeerCertificateDigestError::NONE; | 
|  | } | 
|  |  | 
|  | if (!VerifyPeerCertificate()) { | 
|  | Error("SetPeerCertificateDigest", -1, SSL_AD_BAD_CERTIFICATE, false); | 
|  | return SSLPeerCertificateDigestError::VERIFICATION_FAILED; | 
|  | } | 
|  |  | 
|  | if (state_ == SSL_CONNECTED) { | 
|  | // Post the event asynchronously to unwind the stack. The caller | 
|  | // of ContinueSSL may be the same object listening for these | 
|  | // events and may not be prepared for reentrancy. | 
|  | PostEvent(webrtc::SE_OPEN | webrtc::SE_READ | webrtc::SE_WRITE, 0); | 
|  | } | 
|  | return SSLPeerCertificateDigestError::NONE; | 
|  | } | 
|  |  | 
|  | std::optional<absl::string_view> OpenSSLStreamAdapter::GetTlsCipherSuiteName() | 
|  | const { | 
|  | if (state_ != SSL_CONNECTED) { | 
|  | return std::nullopt; | 
|  | } | 
|  |  | 
|  | const SSL_CIPHER* current_cipher = SSL_get_current_cipher(ssl_); | 
|  | return SSL_CIPHER_standard_name(current_cipher); | 
|  | } | 
|  |  | 
|  | bool OpenSSLStreamAdapter::GetSslCipherSuite(int* cipher_suite) const { | 
|  | if (state_ != SSL_CONNECTED) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const SSL_CIPHER* current_cipher = SSL_get_current_cipher(ssl_); | 
|  | if (current_cipher == nullptr) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | *cipher_suite = static_cast<uint16_t>(SSL_CIPHER_get_id(current_cipher)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | SSLProtocolVersion OpenSSLStreamAdapter::GetSslVersion() const { | 
|  | if (state_ != SSL_CONNECTED) { | 
|  | return webrtc::SSL_PROTOCOL_NOT_GIVEN; | 
|  | } | 
|  |  | 
|  | int ssl_version = SSL_version(ssl_); | 
|  | if (ssl_mode_ == webrtc::SSL_MODE_DTLS) { | 
|  | if (ssl_version == DTLS1_VERSION) { | 
|  | return webrtc::SSL_PROTOCOL_DTLS_10; | 
|  | } else if (ssl_version == DTLS1_2_VERSION) { | 
|  | return webrtc::SSL_PROTOCOL_DTLS_12; | 
|  | } | 
|  | #ifdef DTLS1_3_VERSION | 
|  | if (ssl_version == DTLS1_3_VERSION) { | 
|  | return webrtc::SSL_PROTOCOL_DTLS_13; | 
|  | } | 
|  | #endif | 
|  | } else { | 
|  | if (ssl_version == TLS1_VERSION) { | 
|  | return webrtc::SSL_PROTOCOL_TLS_10; | 
|  | } else if (ssl_version == TLS1_1_VERSION) { | 
|  | return webrtc::SSL_PROTOCOL_TLS_11; | 
|  | } else if (ssl_version == TLS1_2_VERSION) { | 
|  | return webrtc::SSL_PROTOCOL_TLS_12; | 
|  | } | 
|  | #ifdef TLS1_3_VERSION | 
|  | if (ssl_version == TLS1_3_VERSION) { | 
|  | return webrtc::SSL_PROTOCOL_TLS_13; | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | return webrtc::SSL_PROTOCOL_NOT_GIVEN; | 
|  | } | 
|  |  | 
|  | bool OpenSSLStreamAdapter::GetSslVersionBytes(int* version) const { | 
|  | if (state_ != SSL_CONNECTED) { | 
|  | return false; | 
|  | } | 
|  | *version = SSL_version(ssl_); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | uint16_t OpenSSLStreamAdapter::GetSslGroupIdForTesting() const { | 
|  | if (state_ != SSL_CONNECTED) { | 
|  | return 0; | 
|  | } | 
|  | #ifdef OPENSSL_IS_BORINGSSL | 
|  | return SSL_get_group_id(ssl_); | 
|  | #else | 
|  | return 0; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | bool OpenSSLStreamAdapter::ExportSrtpKeyingMaterial( | 
|  | ZeroOnFreeBuffer<uint8_t>& keying_material) { | 
|  | // Arguments are: | 
|  | // keying material/len -- a buffer to hold the keying material. | 
|  | // label               -- the exporter label. | 
|  | //                        part of the RFC defining each exporter | 
|  | //                        usage. We only use RFC 5764 for DTLS-SRTP. | 
|  | // context/context_len -- a context to bind to for this connection; | 
|  | // use_context            optional, can be null, 0 (IN). Not used by WebRTC. | 
|  | if (SSL_export_keying_material( | 
|  | ssl_, keying_material.data(), keying_material.size(), | 
|  | kDtlsSrtpExporterLabel.data(), kDtlsSrtpExporterLabel.size(), nullptr, | 
|  | 0, false) != 1) { | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | uint16_t OpenSSLStreamAdapter::GetPeerSignatureAlgorithm() const { | 
|  | if (state_ != SSL_CONNECTED) { | 
|  | return 0; | 
|  | } | 
|  | #ifdef OPENSSL_IS_BORINGSSL | 
|  | return SSL_get_peer_signature_algorithm(ssl_); | 
|  | #else | 
|  | return kSslSignatureAlgorithmUnknown; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | bool OpenSSLStreamAdapter::SetDtlsSrtpCryptoSuites( | 
|  | const std::vector<int>& ciphers) { | 
|  | if (state_ != SSL_NONE) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | std::string internal_ciphers; | 
|  | for (const int cipher : ciphers) { | 
|  | bool found = false; | 
|  | for (const auto& entry : kSrtpCipherMap) { | 
|  | if (cipher == entry.id) { | 
|  | found = true; | 
|  | if (!internal_ciphers.empty()) { | 
|  | internal_ciphers += ":"; | 
|  | } | 
|  | internal_ciphers += entry.internal_name; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!found) { | 
|  | RTC_LOG(LS_ERROR) << "Could not find cipher: " << cipher; | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (internal_ciphers.empty()) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | srtp_ciphers_ = internal_ciphers; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OpenSSLStreamAdapter::GetDtlsSrtpCryptoSuite(int* crypto_suite) const { | 
|  | RTC_DCHECK(state_ == SSL_CONNECTED); | 
|  | if (state_ != SSL_CONNECTED) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const SRTP_PROTECTION_PROFILE* srtp_profile = | 
|  | SSL_get_selected_srtp_profile(ssl_); | 
|  |  | 
|  | if (!srtp_profile) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | *crypto_suite = srtp_profile->id; | 
|  | RTC_DCHECK(!webrtc::SrtpCryptoSuiteToName(*crypto_suite).empty()); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OpenSSLStreamAdapter::IsTlsConnected() { | 
|  | return state_ == SSL_CONNECTED; | 
|  | } | 
|  |  | 
|  | int OpenSSLStreamAdapter::StartSSL() { | 
|  | // Don't allow StartSSL to be called twice. | 
|  | if (state_ != SSL_NONE) { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (stream_->GetState() != webrtc::SS_OPEN) { | 
|  | state_ = SSL_WAIT; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | state_ = SSL_CONNECTING; | 
|  | if (int err = BeginSSL()) { | 
|  | Error("BeginSSL", err, 0, false); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void OpenSSLStreamAdapter::SetMode(SSLMode mode) { | 
|  | RTC_DCHECK(state_ == SSL_NONE); | 
|  | ssl_mode_ = mode; | 
|  | } | 
|  |  | 
|  | void OpenSSLStreamAdapter::SetMaxProtocolVersion(SSLProtocolVersion version) { | 
|  | RTC_DCHECK(ssl_ctx_ == nullptr); | 
|  | ssl_max_version_ = version; | 
|  | } | 
|  |  | 
|  | void OpenSSLStreamAdapter::SetInitialRetransmissionTimeout(int timeout_ms) { | 
|  | dtls_handshake_timeout_ms_ = timeout_ms; | 
|  | #ifdef OPENSSL_IS_BORINGSSL | 
|  | if (ssl_ctx_ != nullptr && ssl_mode_ == webrtc::SSL_MODE_DTLS) { | 
|  | // TODO (jonaso, webrtc:367395350): Switch to upcoming | 
|  | // DTLSv1_set_timeout_duration. | 
|  | DTLSv1_set_initial_timeout_duration(ssl_, dtls_handshake_timeout_ms_); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | void OpenSSLStreamAdapter::SetMTU(int mtu) { | 
|  | dtls_mtu_ = mtu; | 
|  | if (ssl_) { | 
|  | RTC_CHECK(SSL_set_mtu(ssl_, dtls_mtu_)) << "Call to SSL_set_mtu failed."; | 
|  | } | 
|  | } | 
|  |  | 
|  | // | 
|  | // StreamInterface Implementation | 
|  | // | 
|  | StreamResult OpenSSLStreamAdapter::Write(ArrayView<const uint8_t> data, | 
|  | size_t& written, | 
|  | int& error) { | 
|  | RTC_DLOG(LS_VERBOSE) << "OpenSSLStreamAdapter::Write(" << data.size() << ")"; | 
|  |  | 
|  | switch (state_) { | 
|  | case SSL_NONE: | 
|  | // pass-through in clear text | 
|  | return stream_->Write(data, written, error); | 
|  | case SSL_WAIT: | 
|  | case SSL_CONNECTING: | 
|  | return webrtc::SR_BLOCK; | 
|  | case SSL_CONNECTED: | 
|  | if (WaitingToVerifyPeerCertificate()) { | 
|  | return webrtc::SR_BLOCK; | 
|  | } | 
|  | break; | 
|  | case SSL_ERROR: | 
|  | case SSL_CLOSED: | 
|  | default: | 
|  | error = ssl_error_code_; | 
|  | return webrtc::SR_ERROR; | 
|  | } | 
|  |  | 
|  | // OpenSSL will return an error if we try to write zero bytes | 
|  | if (data.size() == 0) { | 
|  | written = 0; | 
|  | return webrtc::SR_SUCCESS; | 
|  | } | 
|  |  | 
|  | ssl_write_needs_read_ = false; | 
|  |  | 
|  | int code = | 
|  | SSL_write(ssl_, data.data(), webrtc::checked_cast<int>(data.size())); | 
|  | int ssl_error = SSL_get_error(ssl_, code); | 
|  | switch (ssl_error) { | 
|  | case SSL_ERROR_NONE: | 
|  | RTC_DLOG(LS_VERBOSE) << " -- success"; | 
|  | RTC_DCHECK_GT(code, 0); | 
|  | RTC_DCHECK_LE(code, data.size()); | 
|  | written = code; | 
|  | return webrtc::SR_SUCCESS; | 
|  | case SSL_ERROR_WANT_READ: | 
|  | RTC_DLOG(LS_VERBOSE) << " -- error want read"; | 
|  | ssl_write_needs_read_ = true; | 
|  | return webrtc::SR_BLOCK; | 
|  | case SSL_ERROR_WANT_WRITE: | 
|  | RTC_DLOG(LS_VERBOSE) << " -- error want write"; | 
|  | return webrtc::SR_BLOCK; | 
|  | case SSL_ERROR_ZERO_RETURN: | 
|  | default: | 
|  | Error("SSL_write", (ssl_error ? ssl_error : -1), 0, false); | 
|  | error = ssl_error_code_; | 
|  | return webrtc::SR_ERROR; | 
|  | } | 
|  | // not reached | 
|  | } | 
|  |  | 
|  | StreamResult OpenSSLStreamAdapter::Read(ArrayView<uint8_t> data, | 
|  | size_t& read, | 
|  | int& error) { | 
|  | RTC_DLOG(LS_VERBOSE) << "OpenSSLStreamAdapter::Read(" << data.size() << ")"; | 
|  | switch (state_) { | 
|  | case SSL_NONE: | 
|  | // pass-through in clear text | 
|  | return stream_->Read(data, read, error); | 
|  | case SSL_WAIT: | 
|  | case SSL_CONNECTING: | 
|  | return webrtc::SR_BLOCK; | 
|  | case SSL_CONNECTED: | 
|  | if (WaitingToVerifyPeerCertificate()) { | 
|  | return webrtc::SR_BLOCK; | 
|  | } | 
|  | break; | 
|  | case SSL_CLOSED: | 
|  | return webrtc::SR_EOS; | 
|  | case SSL_ERROR: | 
|  | default: | 
|  | error = ssl_error_code_; | 
|  | return webrtc::SR_ERROR; | 
|  | } | 
|  |  | 
|  | // Don't trust OpenSSL with zero byte reads | 
|  | if (data.size() == 0) { | 
|  | read = 0; | 
|  | return webrtc::SR_SUCCESS; | 
|  | } | 
|  |  | 
|  | ssl_read_needs_write_ = false; | 
|  |  | 
|  | const int code = | 
|  | SSL_read(ssl_, data.data(), webrtc::checked_cast<int>(data.size())); | 
|  | const int ssl_error = SSL_get_error(ssl_, code); | 
|  |  | 
|  | switch (ssl_error) { | 
|  | case SSL_ERROR_NONE: | 
|  | RTC_DLOG(LS_VERBOSE) << " -- success"; | 
|  | RTC_DCHECK_GT(code, 0); | 
|  | RTC_DCHECK_LE(code, data.size()); | 
|  | read = code; | 
|  |  | 
|  | if (ssl_mode_ == webrtc::SSL_MODE_DTLS) { | 
|  | // Enforce atomic reads -- this is a short read | 
|  | unsigned int pending = SSL_pending(ssl_); | 
|  |  | 
|  | if (pending) { | 
|  | RTC_DLOG(LS_INFO) << " -- short DTLS read. flushing"; | 
|  | FlushInput(pending); | 
|  | error = webrtc::SSE_MSG_TRUNC; | 
|  | return webrtc::SR_ERROR; | 
|  | } | 
|  | } | 
|  | return webrtc::SR_SUCCESS; | 
|  | case SSL_ERROR_WANT_READ: | 
|  | RTC_DLOG(LS_VERBOSE) << " -- error want read"; | 
|  | return webrtc::SR_BLOCK; | 
|  | case SSL_ERROR_WANT_WRITE: | 
|  | RTC_DLOG(LS_VERBOSE) << " -- error want write"; | 
|  | ssl_read_needs_write_ = true; | 
|  | return webrtc::SR_BLOCK; | 
|  | case SSL_ERROR_ZERO_RETURN: | 
|  | RTC_DLOG(LS_VERBOSE) << " -- remote side closed"; | 
|  | Close(); | 
|  | return webrtc::SR_EOS; | 
|  | default: | 
|  | Error("SSL_read", (ssl_error ? ssl_error : -1), 0, false); | 
|  | error = ssl_error_code_; | 
|  | return webrtc::SR_ERROR; | 
|  | } | 
|  | // not reached | 
|  | } | 
|  |  | 
|  | void OpenSSLStreamAdapter::FlushInput(unsigned int left) { | 
|  | unsigned char buf[2048]; | 
|  |  | 
|  | while (left) { | 
|  | // This should always succeed | 
|  | const int toread = (sizeof(buf) < left) ? sizeof(buf) : left; | 
|  | const int code = SSL_read(ssl_, buf, toread); | 
|  |  | 
|  | const int ssl_error = SSL_get_error(ssl_, code); | 
|  | RTC_DCHECK(ssl_error == SSL_ERROR_NONE); | 
|  |  | 
|  | if (ssl_error != SSL_ERROR_NONE) { | 
|  | RTC_DLOG(LS_VERBOSE) << " -- error " << code; | 
|  | Error("SSL_read", (ssl_error ? ssl_error : -1), 0, false); | 
|  | return; | 
|  | } | 
|  |  | 
|  | RTC_DLOG(LS_VERBOSE) << " -- flushed " << code << " bytes"; | 
|  | left -= code; | 
|  | } | 
|  | } | 
|  |  | 
|  | void OpenSSLStreamAdapter::Close() { | 
|  | Cleanup(0); | 
|  | RTC_DCHECK(state_ == SSL_CLOSED || state_ == SSL_ERROR); | 
|  | // When we're closed at SSL layer, also close the stream level which | 
|  | // performs necessary clean up. Otherwise, a new incoming packet after | 
|  | // this could overflow the stream buffer. | 
|  | stream_->Close(); | 
|  | } | 
|  |  | 
|  | StreamState OpenSSLStreamAdapter::GetState() const { | 
|  | switch (state_) { | 
|  | case SSL_WAIT: | 
|  | case SSL_CONNECTING: | 
|  | return webrtc::SS_OPENING; | 
|  | case SSL_CONNECTED: | 
|  | if (WaitingToVerifyPeerCertificate()) { | 
|  | return webrtc::SS_OPENING; | 
|  | } | 
|  | return webrtc::SS_OPEN; | 
|  | default: | 
|  | return webrtc::SS_CLOSED; | 
|  | } | 
|  | // not reached | 
|  | } | 
|  |  | 
|  | void OpenSSLStreamAdapter::OnEvent(int events, int err) { | 
|  | RTC_DCHECK_RUN_ON(&callback_sequence_); | 
|  | int events_to_signal = 0; | 
|  | int signal_error = 0; | 
|  |  | 
|  | if ((events & webrtc::SE_OPEN)) { | 
|  | RTC_DLOG(LS_VERBOSE) << "OpenSSLStreamAdapter::OnEvent SE_OPEN"; | 
|  | if (state_ != SSL_WAIT) { | 
|  | RTC_DCHECK(state_ == SSL_NONE); | 
|  | events_to_signal |= webrtc::SE_OPEN; | 
|  | } else { | 
|  | state_ = SSL_CONNECTING; | 
|  | if (int error = BeginSSL()) { | 
|  | Error("BeginSSL", error, 0, true); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if ((events & (webrtc::SE_READ | webrtc::SE_WRITE))) { | 
|  | RTC_DLOG(LS_VERBOSE) << "OpenSSLStreamAdapter::OnEvent" | 
|  | << ((events & webrtc::SE_READ) ? " SE_READ" : "") | 
|  | << ((events & webrtc::SE_WRITE) ? " SE_WRITE" : ""); | 
|  | if (state_ == SSL_NONE) { | 
|  | events_to_signal |= events & (webrtc::SE_READ | webrtc::SE_WRITE); | 
|  | } else if (state_ == SSL_CONNECTING) { | 
|  | if (int error = ContinueSSL()) { | 
|  | Error("ContinueSSL", error, 0, true); | 
|  | return; | 
|  | } | 
|  | } else if (state_ == SSL_CONNECTED) { | 
|  | if (((events & webrtc::SE_READ) && ssl_write_needs_read_) || | 
|  | (events & webrtc::SE_WRITE)) { | 
|  | RTC_DLOG(LS_VERBOSE) << " -- onStreamWriteable"; | 
|  | events_to_signal |= webrtc::SE_WRITE; | 
|  | } | 
|  | if (((events & webrtc::SE_WRITE) && ssl_read_needs_write_) || | 
|  | (events & webrtc::SE_READ)) { | 
|  | RTC_DLOG(LS_VERBOSE) << " -- onStreamReadable"; | 
|  | events_to_signal |= webrtc::SE_READ; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if ((events & webrtc::SE_CLOSE)) { | 
|  | RTC_DLOG(LS_VERBOSE) << "OpenSSLStreamAdapter::OnEvent(SE_CLOSE, " << err | 
|  | << ")"; | 
|  | Cleanup(0); | 
|  | events_to_signal |= webrtc::SE_CLOSE; | 
|  | // SE_CLOSE is the only event that uses the final parameter to OnEvent(). | 
|  | RTC_DCHECK(signal_error == 0); | 
|  | signal_error = err; | 
|  | } | 
|  |  | 
|  | if (events_to_signal) { | 
|  | // Note that the adapter presents itself as the origin of the stream events, | 
|  | // since users of the adapter may not recognize the adapted object. | 
|  | FireEvent(events_to_signal, signal_error); | 
|  | } | 
|  | } | 
|  |  | 
|  | void OpenSSLStreamAdapter::PostEvent(int events, int err) { | 
|  | owner_->PostTask(SafeTask(task_safety_.flag(), [this, events, err]() { | 
|  | RTC_DCHECK_RUN_ON(&callback_sequence_); | 
|  | FireEvent(events, err); | 
|  | })); | 
|  | } | 
|  |  | 
|  | void OpenSSLStreamAdapter::SetTimeout(int delay_ms) { | 
|  | // We need to accept 0 delay here as well as >0 delay, because | 
|  | // DTLSv1_get_timeout seems to frequently return 0 ms. | 
|  | RTC_DCHECK_GE(delay_ms, 0); | 
|  | RTC_DCHECK(!timeout_task_.Running()); | 
|  |  | 
|  | timeout_task_ = RepeatingTaskHandle::DelayedStart( | 
|  | owner_, TimeDelta::Millis(delay_ms), | 
|  | [flag = task_safety_.flag(), this]() { | 
|  | if (flag->alive()) { | 
|  | RTC_DLOG(LS_INFO) << "DTLS timeout expired"; | 
|  | timeout_task_.Stop(); | 
|  | int res = DTLSv1_handle_timeout(ssl_); | 
|  | if (res > 0) { | 
|  | retransmission_count_++; | 
|  | RTC_LOG(LS_INFO) << "DTLS retransmission"; | 
|  | } else if (res < 0) { | 
|  | RTC_LOG(LS_INFO) << "DTLSv1_handle_timeout() return -1"; | 
|  | Error("DTLSv1_handle_timeout", res, -1, true); | 
|  | return TimeDelta::PlusInfinity(); | 
|  | } | 
|  | // We check the timer even after SSL_CONNECTED, | 
|  | // but ContinueSSL() is only needed when SSL_CONNECTING | 
|  | if (state_ == SSL_CONNECTING) { | 
|  | ContinueSSL(); | 
|  | } | 
|  | } else { | 
|  | RTC_DCHECK_NOTREACHED(); | 
|  | } | 
|  | // This callback will never run again (stopped above). | 
|  | return TimeDelta::PlusInfinity(); | 
|  | }); | 
|  | } | 
|  |  | 
|  | int OpenSSLStreamAdapter::BeginSSL() { | 
|  | RTC_DCHECK(state_ == SSL_CONNECTING); | 
|  | // The underlying stream has opened. | 
|  | RTC_DLOG(LS_INFO) << "BeginSSL with peer."; | 
|  |  | 
|  | BIO* bio = nullptr; | 
|  |  | 
|  | // First set up the context. | 
|  | RTC_DCHECK(ssl_ctx_ == nullptr); | 
|  | ssl_ctx_ = SetupSSLContext(); | 
|  | if (!ssl_ctx_) { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | bio = BIO_new_stream(stream_.get()); | 
|  | if (!bio) { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | ssl_ = SSL_new(ssl_ctx_); | 
|  | if (!ssl_) { | 
|  | BIO_free(bio); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | SSL_set_app_data(ssl_, this); | 
|  |  | 
|  | SSL_set_bio(ssl_, bio, bio);  // the SSL object owns the bio now. | 
|  |  | 
|  | // Use SSL_set_mtu to configure MTU insted of | 
|  | // BIO_CTRL_DGRAM_QUERY_MTU | 
|  | SSL_set_options(ssl_, SSL_OP_NO_QUERY_MTU); | 
|  | SSL_set_mtu(ssl_, dtls_mtu_); | 
|  |  | 
|  | #ifdef OPENSSL_IS_BORINGSSL | 
|  | if (ssl_mode_ == webrtc::SSL_MODE_DTLS) { | 
|  | DTLSv1_set_initial_timeout_duration(ssl_, dtls_handshake_timeout_ms_); | 
|  | } | 
|  |  | 
|  | // Experimental code guarded by WebRTC-EnableDtlsPqc. | 
|  | if (enable_dtls_pqc_) { | 
|  | const uint16_t kGroups[] = {SSL_GROUP_X25519_MLKEM768, SSL_GROUP_X25519, | 
|  | SSL_GROUP_SECP256R1, SSL_GROUP_SECP384R1}; | 
|  | if (!SSL_set1_group_ids(ssl_, kGroups, std::size(kGroups))) { | 
|  | RTC_LOG(LS_WARNING) << "Failed to call SSL_set1_group_ids."; | 
|  | return -1; | 
|  | } | 
|  | } | 
|  | #endif | 
|  |  | 
|  | SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE | | 
|  | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); | 
|  |  | 
|  | // Do the connect | 
|  | return ContinueSSL(); | 
|  | } | 
|  |  | 
|  | int OpenSSLStreamAdapter::ContinueSSL() { | 
|  | RTC_DCHECK_RUN_ON(&callback_sequence_); | 
|  | RTC_DLOG(LS_VERBOSE) << "ContinueSSL"; | 
|  | RTC_DCHECK_EQ(state_, SSL_CONNECTING); | 
|  |  | 
|  | // Clear the DTLS timer | 
|  | timeout_task_.Stop(); | 
|  |  | 
|  | const int code = | 
|  | (role_ == webrtc::SSL_CLIENT) ? SSL_connect(ssl_) : SSL_accept(ssl_); | 
|  | const int ssl_error = SSL_get_error(ssl_, code); | 
|  |  | 
|  | switch (ssl_error) { | 
|  | case SSL_ERROR_NONE: | 
|  | RTC_DLOG(LS_INFO) << " -- success"; | 
|  | // By this point, OpenSSL should have given us a certificate, or errored | 
|  | // out if one was missing. | 
|  | RTC_DCHECK(peer_cert_chain_ || !GetClientAuthEnabled()); | 
|  |  | 
|  | state_ = SSL_CONNECTED; | 
|  | if (!WaitingToVerifyPeerCertificate()) { | 
|  | // We have everything we need to start the connection, so signal | 
|  | // SE_OPEN. If we need a client certificate fingerprint and don't have | 
|  | // it yet, we'll instead signal SE_OPEN in SetPeerCertificateDigest. | 
|  | // | 
|  | // TODO(deadbeef): Post this event asynchronously to unwind the stack. | 
|  | // The caller of ContinueSSL may be the same object listening for these | 
|  | // events and may not be prepared for reentrancy. | 
|  | // PostEvent(SE_OPEN | SE_READ | SE_WRITE, 0); | 
|  | FireEvent(webrtc::SE_OPEN | webrtc::SE_READ | webrtc::SE_WRITE, 0); | 
|  | } | 
|  | break; | 
|  | case SSL_ERROR_WANT_READ: | 
|  | RTC_DLOG(LS_INFO) << " -- error when we want to read"; | 
|  | break; | 
|  | case SSL_ERROR_WANT_WRITE: | 
|  | RTC_DLOG(LS_INFO) << " -- error when we want to write"; | 
|  | break; | 
|  | case SSL_ERROR_ZERO_RETURN: | 
|  | default: { | 
|  | SSLHandshakeError ssl_handshake_err = SSLHandshakeError::UNKNOWN; | 
|  | int err_code = ERR_peek_last_error(); | 
|  | if (err_code != 0 && ERR_GET_REASON(err_code) == SSL_R_NO_SHARED_CIPHER) { | 
|  | ssl_handshake_err = SSLHandshakeError::INCOMPATIBLE_CIPHERSUITE; | 
|  | } | 
|  | RTC_DLOG(LS_VERBOSE) << " -- error " << code << ", " << err_code << ", " | 
|  | << ERR_GET_REASON(err_code); | 
|  | if (handshake_error_) { | 
|  | handshake_error_(ssl_handshake_err); | 
|  | } | 
|  | return (ssl_error != 0) ? ssl_error : -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ssl_ != nullptr) { | 
|  | struct timeval timeout; | 
|  | if (DTLSv1_get_timeout(ssl_, &timeout)) { | 
|  | int delay = timeout.tv_sec * 1000 + timeout.tv_usec / 1000; | 
|  | SetTimeout(delay); | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void OpenSSLStreamAdapter::Error(absl::string_view context, | 
|  | int err, | 
|  | uint8_t alert, | 
|  | bool signal) { | 
|  | RTC_DCHECK_RUN_ON(&callback_sequence_); | 
|  | RTC_LOG(LS_WARNING) << "OpenSSLStreamAdapter::Error(" << context << ", " | 
|  | << err << ", " << static_cast<int>(alert) << ")"; | 
|  | state_ = SSL_ERROR; | 
|  | ssl_error_code_ = err; | 
|  | Cleanup(alert); | 
|  | if (signal) { | 
|  | FireEvent(webrtc::SE_CLOSE, err); | 
|  | } | 
|  | } | 
|  |  | 
|  | void OpenSSLStreamAdapter::Cleanup(uint8_t alert) { | 
|  | RTC_DLOG(LS_INFO) << "Cleanup"; | 
|  |  | 
|  | if (state_ != SSL_ERROR) { | 
|  | state_ = SSL_CLOSED; | 
|  | ssl_error_code_ = 0; | 
|  | } | 
|  |  | 
|  | if (ssl_) { | 
|  | int ret; | 
|  | // SSL_send_fatal_alert is only available in BoringSSL. | 
|  | #ifdef OPENSSL_IS_BORINGSSL | 
|  | if (alert) { | 
|  | ret = SSL_send_fatal_alert(ssl_, alert); | 
|  | if (ret < 0) { | 
|  | RTC_LOG(LS_WARNING) << "SSL_send_fatal_alert failed, error = " | 
|  | << SSL_get_error(ssl_, ret); | 
|  | } | 
|  | } else { | 
|  | #endif | 
|  | ret = SSL_shutdown(ssl_); | 
|  | if (ret < 0) { | 
|  | RTC_LOG(LS_WARNING) | 
|  | << "SSL_shutdown failed, error = " << SSL_get_error(ssl_, ret); | 
|  | } | 
|  | #ifdef OPENSSL_IS_BORINGSSL | 
|  | } | 
|  | #endif | 
|  | SSL_free(ssl_); | 
|  | ssl_ = nullptr; | 
|  | } | 
|  | if (ssl_ctx_) { | 
|  | SSL_CTX_free(ssl_ctx_); | 
|  | ssl_ctx_ = nullptr; | 
|  | } | 
|  | identity_.reset(); | 
|  | peer_cert_chain_.reset(); | 
|  |  | 
|  | // Clear the DTLS timer | 
|  | timeout_task_.Stop(); | 
|  | } | 
|  |  | 
|  | 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_ == webrtc::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; | 
|  | } | 
|  |  | 
|  | auto min_version = | 
|  | ssl_mode_ == webrtc::SSL_MODE_DTLS ? DTLS1_2_VERSION : TLS1_2_VERSION; | 
|  | auto max_version = GetMaxVersion(ssl_mode_, ssl_max_version_); | 
|  | #ifdef DTLS1_3_VERSION | 
|  | if (force_dtls_13_ == kForceDtls13Enabled) { | 
|  | max_version = DTLS1_3_VERSION; | 
|  | } else if (force_dtls_13_ == kForceDtls13Only) { | 
|  | min_version = DTLS1_3_VERSION; | 
|  | max_version = DTLS1_3_VERSION; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | SSL_CTX_set_min_proto_version(ctx, min_version); | 
|  | SSL_CTX_set_max_proto_version(ctx, max_version); | 
|  |  | 
|  | #ifdef OPENSSL_IS_BORINGSSL | 
|  | // SSL_CTX_set_current_time_cb is only supported in BoringSSL. | 
|  | 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)) { | 
|  | SSL_CTX_free(ctx); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // TODO(bugs.webrtc.org/339300437): Remove dependency. | 
|  | SSL_CTX_set_info_callback(ctx, OpenSSLAdapter::SSLInfoCallback); | 
|  |  | 
|  | int mode = SSL_VERIFY_PEER; | 
|  | if (GetClientAuthEnabled()) { | 
|  | // Require a certificate from the client. | 
|  | // Note: Normally this is always true in production, but it may be disabled | 
|  | // for testing purposes (e.g. SSLAdapter unit tests). | 
|  | mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; | 
|  | } | 
|  |  | 
|  | // Configure a custom certificate verification callback to check the peer | 
|  | // 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 | 
|  | // with SHA256 or SHA384 as the handshake hash. | 
|  | // This matches the list of SSLClientSocketImpl in Chromium. | 
|  | SSL_CTX_set_cipher_list( | 
|  | ctx, | 
|  | "DEFAULT:!NULL:!aNULL:!SHA256:!SHA384:!aECDH:!AESGCM+AES256:!aPSK:!3DES"); | 
|  |  | 
|  | if (!srtp_ciphers_.empty()) { | 
|  | if (SSL_CTX_set_tlsext_use_srtp(ctx, srtp_ciphers_.c_str())) { | 
|  | SSL_CTX_free(ctx); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | #ifdef OPENSSL_IS_BORINGSSL | 
|  | SSL_CTX_set_permute_extensions(ctx, true); | 
|  | #endif | 
|  |  | 
|  | #if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER >= 0x30000000L) | 
|  | SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); | 
|  | #endif | 
|  |  | 
|  | return ctx; | 
|  | } | 
|  |  | 
|  | bool OpenSSLStreamAdapter::VerifyPeerCertificate() { | 
|  | if (!HasPeerCertificateDigest() || !peer_cert_chain_ || | 
|  | !peer_cert_chain_->GetSize()) { | 
|  | RTC_LOG(LS_WARNING) << "Missing digest or peer certificate."; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Buffer computed_digest(0, EVP_MAX_MD_SIZE); | 
|  | if (!peer_cert_chain_->Get(0).ComputeDigest( | 
|  | peer_certificate_digest_algorithm_, computed_digest)) { | 
|  | RTC_LOG(LS_WARNING) << "Failed to compute peer cert digest."; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (computed_digest != peer_certificate_digest_value_) { | 
|  | RTC_LOG(LS_WARNING) | 
|  | << "Rejected peer certificate due to mismatched digest using " | 
|  | << peer_certificate_digest_algorithm_ << ". Expected " | 
|  | << hex_encode_with_delimiter(peer_certificate_digest_value_, ':') | 
|  | << " got " << hex_encode_with_delimiter(computed_digest, ':'); | 
|  | return false; | 
|  | } | 
|  | // Ignore any verification error if the digest matches, since there is no | 
|  | // value in checking the validity of a self-signed cert issued by untrusted | 
|  | // sources. | 
|  | RTC_DLOG(LS_INFO) << "Accepted peer certificate."; | 
|  | peer_certificate_verified_ = true; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<SSLCertChain> OpenSSLStreamAdapter::GetPeerSSLCertChain() | 
|  | const { | 
|  | 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*>( | 
|  | 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<webrtc::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() { | 
|  | #ifdef OPENSSL_IS_BORINGSSL | 
|  | return true; | 
|  | #else | 
|  | return false; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | #define CDEF(X) \ | 
|  | { static_cast<uint16_t>(TLS1_CK_##X & 0xffff), "TLS_" #X } | 
|  |  | 
|  | struct cipher_list { | 
|  | uint16_t cipher; | 
|  | const char* cipher_str; | 
|  | }; | 
|  |  | 
|  | // TODO(torbjorng): Perhaps add more cipher suites to these lists. | 
|  | static const cipher_list OK_RSA_ciphers[] = { | 
|  | CDEF(ECDHE_RSA_WITH_AES_128_CBC_SHA), | 
|  | CDEF(ECDHE_RSA_WITH_AES_256_CBC_SHA), | 
|  | CDEF(ECDHE_RSA_WITH_AES_128_GCM_SHA256), | 
|  | #ifdef TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA256 | 
|  | CDEF(ECDHE_RSA_WITH_AES_256_GCM_SHA256), | 
|  | #endif | 
|  | #ifdef TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256  // BoringSSL. | 
|  | CDEF(ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256), | 
|  | #elif defined(TLS1_RFC_ECDHE_ECDSA_WITH_CHACHA20_POLY1305)  // OpenSSL. | 
|  | CDEF(ECDHE_RSA_WITH_CHACHA20_POLY1305), | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | static const cipher_list OK_ECDSA_ciphers[] = { | 
|  | CDEF(ECDHE_ECDSA_WITH_AES_128_CBC_SHA), | 
|  | CDEF(ECDHE_ECDSA_WITH_AES_256_CBC_SHA), | 
|  | CDEF(ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), | 
|  | #ifdef TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA256 | 
|  | CDEF(ECDHE_ECDSA_WITH_AES_256_GCM_SHA256), | 
|  | #endif | 
|  | #ifdef TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256  // BoringSSL. | 
|  | CDEF(ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256), | 
|  | #elif defined(TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305)  // OpenSSL. | 
|  | CDEF(ECDHE_ECDSA_WITH_CHACHA20_POLY1305), | 
|  | #endif | 
|  | }; | 
|  | #undef CDEF | 
|  |  | 
|  | static const cipher_list OK_DTLS13_ciphers[] = { | 
|  | #ifdef TLS1_3_CK_AES_128_GCM_SHA256  // BoringSSL TLS 1.3 | 
|  | {static_cast<uint16_t>(TLS1_3_CK_AES_128_GCM_SHA256 & 0xffff), | 
|  | "TLS_AES_128_GCM_SHA256"}, | 
|  | #endif | 
|  | #ifdef TLS1_3_CK_AES_256_GCM_SHA256  // BoringSSL TLS 1.3 | 
|  | {static_cast<uint16_t>(TLS1_3_CK_AES_256_GCM_SHA256 & 0xffff), | 
|  | "TLS_AES_256_GCM_SHA256"}, | 
|  | #endif | 
|  | #ifdef TLS1_3_CK_CHACHA20_POLY1305_SHA256  // BoringSSL TLS 1.3 | 
|  | {static_cast<uint16_t>(TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff), | 
|  | "TLS_CHACHA20_POLY1305_SHA256"}, | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | bool OpenSSLStreamAdapter::IsAcceptableCipher(int cipher, KeyType key_type) { | 
|  | if (key_type == KT_RSA) { | 
|  | for (const cipher_list& c : OK_RSA_ciphers) { | 
|  | if (cipher == c.cipher) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (key_type == KT_ECDSA) { | 
|  | for (const cipher_list& c : OK_ECDSA_ciphers) { | 
|  | if (cipher == c.cipher) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | for (const cipher_list& c : OK_DTLS13_ciphers) { | 
|  | if (cipher == c.cipher) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool OpenSSLStreamAdapter::IsAcceptableCipher(absl::string_view cipher, | 
|  | KeyType key_type) { | 
|  | if (key_type == KT_RSA) { | 
|  | for (const cipher_list& c : OK_RSA_ciphers) { | 
|  | if (cipher == c.cipher_str) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (key_type == KT_ECDSA) { | 
|  | for (const cipher_list& c : OK_ECDSA_ciphers) { | 
|  | if (cipher == c.cipher_str) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | for (const cipher_list& c : OK_DTLS13_ciphers) { | 
|  | if (cipher == c.cipher_str) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void OpenSSLStreamAdapter::EnableTimeCallbackForTesting() { | 
|  | #ifdef OPENSSL_IS_BORINGSSL | 
|  | g_use_time_callback_for_testing = true; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | SSLProtocolVersion OpenSSLStreamAdapter::GetMaxSupportedDTLSProtocolVersion() { | 
|  | #if defined(OPENSSL_IS_BORINGSSL) && defined(DTLS1_3_VERSION) | 
|  | return webrtc::SSL_PROTOCOL_DTLS_13; | 
|  | #else | 
|  | return SSL_PROTOCOL_DTLS_12; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |