1*d9f75844SAndroid Build Coastguard Worker /* 2*d9f75844SAndroid Build Coastguard Worker * Copyright 2004 The WebRTC Project Authors. All rights reserved. 3*d9f75844SAndroid Build Coastguard Worker * 4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license 5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source 6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found 7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may 8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree. 9*d9f75844SAndroid Build Coastguard Worker */ 10*d9f75844SAndroid Build Coastguard Worker 11*d9f75844SAndroid Build Coastguard Worker #ifndef RTC_BASE_OPENSSL_STREAM_ADAPTER_H_ 12*d9f75844SAndroid Build Coastguard Worker #define RTC_BASE_OPENSSL_STREAM_ADAPTER_H_ 13*d9f75844SAndroid Build Coastguard Worker 14*d9f75844SAndroid Build Coastguard Worker #include <openssl/ossl_typ.h> 15*d9f75844SAndroid Build Coastguard Worker #include <stddef.h> 16*d9f75844SAndroid Build Coastguard Worker #include <stdint.h> 17*d9f75844SAndroid Build Coastguard Worker 18*d9f75844SAndroid Build Coastguard Worker #include <memory> 19*d9f75844SAndroid Build Coastguard Worker #include <string> 20*d9f75844SAndroid Build Coastguard Worker #include <vector> 21*d9f75844SAndroid Build Coastguard Worker 22*d9f75844SAndroid Build Coastguard Worker #include "absl/strings/string_view.h" 23*d9f75844SAndroid Build Coastguard Worker #include "absl/types/optional.h" 24*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/buffer.h" 25*d9f75844SAndroid Build Coastguard Worker #ifdef OPENSSL_IS_BORINGSSL 26*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/boringssl_identity.h" 27*d9f75844SAndroid Build Coastguard Worker #else 28*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/openssl_identity.h" 29*d9f75844SAndroid Build Coastguard Worker #endif 30*d9f75844SAndroid Build Coastguard Worker #include "api/task_queue/pending_task_safety_flag.h" 31*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/ssl_identity.h" 32*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/ssl_stream_adapter.h" 33*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/stream.h" 34*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/system/rtc_export.h" 35*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/task_utils/repeating_task.h" 36*d9f75844SAndroid Build Coastguard Worker 37*d9f75844SAndroid Build Coastguard Worker namespace rtc { 38*d9f75844SAndroid Build Coastguard Worker 39*d9f75844SAndroid Build Coastguard Worker // This class was written with OpenSSLAdapter (a socket adapter) as a 40*d9f75844SAndroid Build Coastguard Worker // starting point. It has similar structure and functionality, but uses a 41*d9f75844SAndroid Build Coastguard Worker // "peer-to-peer" mode, verifying the peer's certificate using a digest 42*d9f75844SAndroid Build Coastguard Worker // sent over a secure signaling channel. 43*d9f75844SAndroid Build Coastguard Worker // 44*d9f75844SAndroid Build Coastguard Worker // Static methods to initialize and deinit the SSL library are in 45*d9f75844SAndroid Build Coastguard Worker // OpenSSLAdapter. These should probably be moved out to a neutral class. 46*d9f75844SAndroid Build Coastguard Worker // 47*d9f75844SAndroid Build Coastguard Worker // In a few cases I have factored out some OpenSSLAdapter code into static 48*d9f75844SAndroid Build Coastguard Worker // methods so it can be reused from this class. Eventually that code should 49*d9f75844SAndroid Build Coastguard Worker // probably be moved to a common support class. Unfortunately there remain a 50*d9f75844SAndroid Build Coastguard Worker // few duplicated sections of code. I have not done more restructuring because 51*d9f75844SAndroid Build Coastguard Worker // I did not want to affect existing code that uses OpenSSLAdapter. 52*d9f75844SAndroid Build Coastguard Worker // 53*d9f75844SAndroid Build Coastguard Worker // This class does not support the SSL connection restart feature present in 54*d9f75844SAndroid Build Coastguard Worker // OpenSSLAdapter. I am not entirely sure how the feature is useful and I am 55*d9f75844SAndroid Build Coastguard Worker // not convinced that it works properly. 56*d9f75844SAndroid Build Coastguard Worker // 57*d9f75844SAndroid Build Coastguard Worker // This implementation is careful to disallow data exchange after an SSL error, 58*d9f75844SAndroid Build Coastguard Worker // and it has an explicit SSL_CLOSED state. It should not be possible to send 59*d9f75844SAndroid Build Coastguard Worker // any data in clear after one of the StartSSL methods has been called. 60*d9f75844SAndroid Build Coastguard Worker 61*d9f75844SAndroid Build Coastguard Worker // Look in sslstreamadapter.h for documentation of the methods. 62*d9f75844SAndroid Build Coastguard Worker 63*d9f75844SAndroid Build Coastguard Worker class SSLCertChain; 64*d9f75844SAndroid Build Coastguard Worker 65*d9f75844SAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////////////// 66*d9f75844SAndroid Build Coastguard Worker 67*d9f75844SAndroid Build Coastguard Worker // If `allow` has a value, its value determines if legacy TLS protocols are 68*d9f75844SAndroid Build Coastguard Worker // allowed, overriding the default configuration. 69*d9f75844SAndroid Build Coastguard Worker // If `allow` has no value, any previous override is removed and the default 70*d9f75844SAndroid Build Coastguard Worker // configuration is restored. 71*d9f75844SAndroid Build Coastguard Worker RTC_EXPORT void SetAllowLegacyTLSProtocols(const absl::optional<bool>& allow); 72*d9f75844SAndroid Build Coastguard Worker 73*d9f75844SAndroid Build Coastguard Worker class OpenSSLStreamAdapter final : public SSLStreamAdapter { 74*d9f75844SAndroid Build Coastguard Worker public: 75*d9f75844SAndroid Build Coastguard Worker explicit OpenSSLStreamAdapter(std::unique_ptr<StreamInterface> stream); 76*d9f75844SAndroid Build Coastguard Worker ~OpenSSLStreamAdapter() override; 77*d9f75844SAndroid Build Coastguard Worker 78*d9f75844SAndroid Build Coastguard Worker void SetIdentity(std::unique_ptr<SSLIdentity> identity) override; 79*d9f75844SAndroid Build Coastguard Worker SSLIdentity* GetIdentityForTesting() const override; 80*d9f75844SAndroid Build Coastguard Worker 81*d9f75844SAndroid Build Coastguard Worker // Default argument is for compatibility 82*d9f75844SAndroid Build Coastguard Worker void SetServerRole(SSLRole role = SSL_SERVER) override; 83*d9f75844SAndroid Build Coastguard Worker bool SetPeerCertificateDigest( 84*d9f75844SAndroid Build Coastguard Worker absl::string_view digest_alg, 85*d9f75844SAndroid Build Coastguard Worker const unsigned char* digest_val, 86*d9f75844SAndroid Build Coastguard Worker size_t digest_len, 87*d9f75844SAndroid Build Coastguard Worker SSLPeerCertificateDigestError* error = nullptr) override; 88*d9f75844SAndroid Build Coastguard Worker 89*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<SSLCertChain> GetPeerSSLCertChain() const override; 90*d9f75844SAndroid Build Coastguard Worker 91*d9f75844SAndroid Build Coastguard Worker // Goes from state SSL_NONE to either SSL_CONNECTING or SSL_WAIT, depending 92*d9f75844SAndroid Build Coastguard Worker // on whether the underlying stream is already open or not. 93*d9f75844SAndroid Build Coastguard Worker int StartSSL() override; 94*d9f75844SAndroid Build Coastguard Worker void SetMode(SSLMode mode) override; 95*d9f75844SAndroid Build Coastguard Worker void SetMaxProtocolVersion(SSLProtocolVersion version) override; 96*d9f75844SAndroid Build Coastguard Worker void SetInitialRetransmissionTimeout(int timeout_ms) override; 97*d9f75844SAndroid Build Coastguard Worker 98*d9f75844SAndroid Build Coastguard Worker StreamResult Read(rtc::ArrayView<uint8_t> data, 99*d9f75844SAndroid Build Coastguard Worker size_t& read, 100*d9f75844SAndroid Build Coastguard Worker int& error) override; 101*d9f75844SAndroid Build Coastguard Worker StreamResult Write(rtc::ArrayView<const uint8_t> data, 102*d9f75844SAndroid Build Coastguard Worker size_t& written, 103*d9f75844SAndroid Build Coastguard Worker int& error) override; 104*d9f75844SAndroid Build Coastguard Worker void Close() override; 105*d9f75844SAndroid Build Coastguard Worker StreamState GetState() const override; 106*d9f75844SAndroid Build Coastguard Worker 107*d9f75844SAndroid Build Coastguard Worker // TODO(guoweis): Move this away from a static class method. 108*d9f75844SAndroid Build Coastguard Worker static std::string SslCipherSuiteToName(int crypto_suite); 109*d9f75844SAndroid Build Coastguard Worker 110*d9f75844SAndroid Build Coastguard Worker bool GetSslCipherSuite(int* cipher) override; 111*d9f75844SAndroid Build Coastguard Worker 112*d9f75844SAndroid Build Coastguard Worker SSLProtocolVersion GetSslVersion() const override; 113*d9f75844SAndroid Build Coastguard Worker bool GetSslVersionBytes(int* version) const override; 114*d9f75844SAndroid Build Coastguard Worker // Key Extractor interface 115*d9f75844SAndroid Build Coastguard Worker bool ExportKeyingMaterial(absl::string_view label, 116*d9f75844SAndroid Build Coastguard Worker const uint8_t* context, 117*d9f75844SAndroid Build Coastguard Worker size_t context_len, 118*d9f75844SAndroid Build Coastguard Worker bool use_context, 119*d9f75844SAndroid Build Coastguard Worker uint8_t* result, 120*d9f75844SAndroid Build Coastguard Worker size_t result_len) override; 121*d9f75844SAndroid Build Coastguard Worker 122*d9f75844SAndroid Build Coastguard Worker // DTLS-SRTP interface 123*d9f75844SAndroid Build Coastguard Worker bool SetDtlsSrtpCryptoSuites(const std::vector<int>& crypto_suites) override; 124*d9f75844SAndroid Build Coastguard Worker bool GetDtlsSrtpCryptoSuite(int* crypto_suite) override; 125*d9f75844SAndroid Build Coastguard Worker 126*d9f75844SAndroid Build Coastguard Worker bool IsTlsConnected() override; 127*d9f75844SAndroid Build Coastguard Worker 128*d9f75844SAndroid Build Coastguard Worker // Capabilities interfaces. 129*d9f75844SAndroid Build Coastguard Worker static bool IsBoringSsl(); 130*d9f75844SAndroid Build Coastguard Worker 131*d9f75844SAndroid Build Coastguard Worker static bool IsAcceptableCipher(int cipher, KeyType key_type); 132*d9f75844SAndroid Build Coastguard Worker static bool IsAcceptableCipher(absl::string_view cipher, KeyType key_type); 133*d9f75844SAndroid Build Coastguard Worker 134*d9f75844SAndroid Build Coastguard Worker // Use our timeutils.h source of timing in BoringSSL, allowing us to test 135*d9f75844SAndroid Build Coastguard Worker // using a fake clock. 136*d9f75844SAndroid Build Coastguard Worker static void EnableTimeCallbackForTesting(); 137*d9f75844SAndroid Build Coastguard Worker 138*d9f75844SAndroid Build Coastguard Worker private: 139*d9f75844SAndroid Build Coastguard Worker enum SSLState { 140*d9f75844SAndroid Build Coastguard Worker // Before calling one of the StartSSL methods, data flows 141*d9f75844SAndroid Build Coastguard Worker // in clear text. 142*d9f75844SAndroid Build Coastguard Worker SSL_NONE, 143*d9f75844SAndroid Build Coastguard Worker SSL_WAIT, // waiting for the stream to open to start SSL negotiation 144*d9f75844SAndroid Build Coastguard Worker SSL_CONNECTING, // SSL negotiation in progress 145*d9f75844SAndroid Build Coastguard Worker SSL_CONNECTED, // SSL stream successfully established 146*d9f75844SAndroid Build Coastguard Worker SSL_ERROR, // some SSL error occurred, stream is closed 147*d9f75844SAndroid Build Coastguard Worker SSL_CLOSED // Clean close 148*d9f75844SAndroid Build Coastguard Worker }; 149*d9f75844SAndroid Build Coastguard Worker 150*d9f75844SAndroid Build Coastguard Worker void OnEvent(StreamInterface* stream, int events, int err); 151*d9f75844SAndroid Build Coastguard Worker 152*d9f75844SAndroid Build Coastguard Worker void PostEvent(int events, int err); 153*d9f75844SAndroid Build Coastguard Worker void SetTimeout(int delay_ms); 154*d9f75844SAndroid Build Coastguard Worker 155*d9f75844SAndroid Build Coastguard Worker // The following three methods return 0 on success and a negative 156*d9f75844SAndroid Build Coastguard Worker // error code on failure. The error code may be from OpenSSL or -1 157*d9f75844SAndroid Build Coastguard Worker // on some other error cases, so it can't really be interpreted 158*d9f75844SAndroid Build Coastguard Worker // unfortunately. 159*d9f75844SAndroid Build Coastguard Worker 160*d9f75844SAndroid Build Coastguard Worker // Prepare SSL library, state is SSL_CONNECTING. 161*d9f75844SAndroid Build Coastguard Worker int BeginSSL(); 162*d9f75844SAndroid Build Coastguard Worker // Perform SSL negotiation steps. 163*d9f75844SAndroid Build Coastguard Worker int ContinueSSL(); 164*d9f75844SAndroid Build Coastguard Worker 165*d9f75844SAndroid Build Coastguard Worker // Error handler helper. signal is given as true for errors in 166*d9f75844SAndroid Build Coastguard Worker // asynchronous contexts (when an error method was not returned 167*d9f75844SAndroid Build Coastguard Worker // through some other method), and in that case an SE_CLOSE event is 168*d9f75844SAndroid Build Coastguard Worker // raised on the stream with the specified error. 169*d9f75844SAndroid Build Coastguard Worker // A 0 error means a graceful close, otherwise there is not really enough 170*d9f75844SAndroid Build Coastguard Worker // context to interpret the error code. 171*d9f75844SAndroid Build Coastguard Worker // `alert` indicates an alert description (one of the SSL_AD constants) to 172*d9f75844SAndroid Build Coastguard Worker // send to the remote endpoint when closing the association. If 0, a normal 173*d9f75844SAndroid Build Coastguard Worker // shutdown will be performed. 174*d9f75844SAndroid Build Coastguard Worker void Error(absl::string_view context, int err, uint8_t alert, bool signal); 175*d9f75844SAndroid Build Coastguard Worker void Cleanup(uint8_t alert); 176*d9f75844SAndroid Build Coastguard Worker 177*d9f75844SAndroid Build Coastguard Worker // Flush the input buffers by reading left bytes (for DTLS) 178*d9f75844SAndroid Build Coastguard Worker void FlushInput(unsigned int left); 179*d9f75844SAndroid Build Coastguard Worker 180*d9f75844SAndroid Build Coastguard Worker // SSL library configuration 181*d9f75844SAndroid Build Coastguard Worker SSL_CTX* SetupSSLContext(); 182*d9f75844SAndroid Build Coastguard Worker // Verify the peer certificate matches the signaled digest. 183*d9f75844SAndroid Build Coastguard Worker bool VerifyPeerCertificate(); 184*d9f75844SAndroid Build Coastguard Worker 185*d9f75844SAndroid Build Coastguard Worker #ifdef OPENSSL_IS_BORINGSSL 186*d9f75844SAndroid Build Coastguard Worker // SSL certificate verification callback. See SSL_CTX_set_custom_verify. 187*d9f75844SAndroid Build Coastguard Worker static enum ssl_verify_result_t SSLVerifyCallback(SSL* ssl, 188*d9f75844SAndroid Build Coastguard Worker uint8_t* out_alert); 189*d9f75844SAndroid Build Coastguard Worker #else 190*d9f75844SAndroid Build Coastguard Worker // SSL certificate verification callback. See 191*d9f75844SAndroid Build Coastguard Worker // SSL_CTX_set_cert_verify_callback. 192*d9f75844SAndroid Build Coastguard Worker static int SSLVerifyCallback(X509_STORE_CTX* store, void* arg); 193*d9f75844SAndroid Build Coastguard Worker #endif 194*d9f75844SAndroid Build Coastguard Worker WaitingToVerifyPeerCertificate()195*d9f75844SAndroid Build Coastguard Worker bool WaitingToVerifyPeerCertificate() const { 196*d9f75844SAndroid Build Coastguard Worker return GetClientAuthEnabled() && !peer_certificate_verified_; 197*d9f75844SAndroid Build Coastguard Worker } 198*d9f75844SAndroid Build Coastguard Worker HasPeerCertificateDigest()199*d9f75844SAndroid Build Coastguard Worker bool HasPeerCertificateDigest() const { 200*d9f75844SAndroid Build Coastguard Worker return !peer_certificate_digest_algorithm_.empty() && 201*d9f75844SAndroid Build Coastguard Worker !peer_certificate_digest_value_.empty(); 202*d9f75844SAndroid Build Coastguard Worker } 203*d9f75844SAndroid Build Coastguard Worker 204*d9f75844SAndroid Build Coastguard Worker const std::unique_ptr<StreamInterface> stream_; 205*d9f75844SAndroid Build Coastguard Worker 206*d9f75844SAndroid Build Coastguard Worker rtc::Thread* const owner_; 207*d9f75844SAndroid Build Coastguard Worker webrtc::ScopedTaskSafety task_safety_; 208*d9f75844SAndroid Build Coastguard Worker webrtc::RepeatingTaskHandle timeout_task_; 209*d9f75844SAndroid Build Coastguard Worker 210*d9f75844SAndroid Build Coastguard Worker SSLState state_; 211*d9f75844SAndroid Build Coastguard Worker SSLRole role_; 212*d9f75844SAndroid Build Coastguard Worker int ssl_error_code_; // valid when state_ == SSL_ERROR or SSL_CLOSED 213*d9f75844SAndroid Build Coastguard Worker // Whether the SSL negotiation is blocked on needing to read or 214*d9f75844SAndroid Build Coastguard Worker // write to the wrapped stream. 215*d9f75844SAndroid Build Coastguard Worker bool ssl_read_needs_write_; 216*d9f75844SAndroid Build Coastguard Worker bool ssl_write_needs_read_; 217*d9f75844SAndroid Build Coastguard Worker 218*d9f75844SAndroid Build Coastguard Worker SSL* ssl_; 219*d9f75844SAndroid Build Coastguard Worker SSL_CTX* ssl_ctx_; 220*d9f75844SAndroid Build Coastguard Worker 221*d9f75844SAndroid Build Coastguard Worker // Our key and certificate. 222*d9f75844SAndroid Build Coastguard Worker #ifdef OPENSSL_IS_BORINGSSL 223*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<BoringSSLIdentity> identity_; 224*d9f75844SAndroid Build Coastguard Worker #else 225*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<OpenSSLIdentity> identity_; 226*d9f75844SAndroid Build Coastguard Worker #endif 227*d9f75844SAndroid Build Coastguard Worker // The certificate chain that the peer presented. Initially null, until the 228*d9f75844SAndroid Build Coastguard Worker // connection is established. 229*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<SSLCertChain> peer_cert_chain_; 230*d9f75844SAndroid Build Coastguard Worker bool peer_certificate_verified_ = false; 231*d9f75844SAndroid Build Coastguard Worker // The digest of the certificate that the peer must present. 232*d9f75844SAndroid Build Coastguard Worker Buffer peer_certificate_digest_value_; 233*d9f75844SAndroid Build Coastguard Worker std::string peer_certificate_digest_algorithm_; 234*d9f75844SAndroid Build Coastguard Worker 235*d9f75844SAndroid Build Coastguard Worker // The DtlsSrtp ciphers 236*d9f75844SAndroid Build Coastguard Worker std::string srtp_ciphers_; 237*d9f75844SAndroid Build Coastguard Worker 238*d9f75844SAndroid Build Coastguard Worker // Do DTLS or not 239*d9f75844SAndroid Build Coastguard Worker SSLMode ssl_mode_; 240*d9f75844SAndroid Build Coastguard Worker 241*d9f75844SAndroid Build Coastguard Worker // Max. allowed protocol version 242*d9f75844SAndroid Build Coastguard Worker SSLProtocolVersion ssl_max_version_; 243*d9f75844SAndroid Build Coastguard Worker 244*d9f75844SAndroid Build Coastguard Worker // A 50-ms initial timeout ensures rapid setup on fast connections, but may 245*d9f75844SAndroid Build Coastguard Worker // be too aggressive for low bandwidth links. 246*d9f75844SAndroid Build Coastguard Worker int dtls_handshake_timeout_ms_ = 50; 247*d9f75844SAndroid Build Coastguard Worker 248*d9f75844SAndroid Build Coastguard Worker // TODO(https://bugs.webrtc.org/10261): Completely remove this option in M84. 249*d9f75844SAndroid Build Coastguard Worker const bool support_legacy_tls_protocols_flag_; 250*d9f75844SAndroid Build Coastguard Worker }; 251*d9f75844SAndroid Build Coastguard Worker 252*d9f75844SAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////// 253*d9f75844SAndroid Build Coastguard Worker 254*d9f75844SAndroid Build Coastguard Worker } // namespace rtc 255*d9f75844SAndroid Build Coastguard Worker 256*d9f75844SAndroid Build Coastguard Worker #endif // RTC_BASE_OPENSSL_STREAM_ADAPTER_H_ 257