| /* | 
 |  *  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. | 
 |  */ | 
 |  | 
 | #if HAVE_CONFIG_H | 
 | #include "config.h" | 
 | #endif  // HAVE_CONFIG_H | 
 |  | 
 | #if HAVE_OPENSSL_SSL_H | 
 |  | 
 | #include "webrtc/base/opensslstreamadapter.h" | 
 |  | 
 | #include <openssl/bio.h> | 
 | #include <openssl/crypto.h> | 
 | #include <openssl/err.h> | 
 | #include <openssl/rand.h> | 
 | #include <openssl/tls1.h> | 
 | #include <openssl/x509v3.h> | 
 |  | 
 | #include <vector> | 
 |  | 
 | #include "webrtc/base/common.h" | 
 | #include "webrtc/base/logging.h" | 
 | #include "webrtc/base/safe_conversions.h" | 
 | #include "webrtc/base/stream.h" | 
 | #include "webrtc/base/openssl.h" | 
 | #include "webrtc/base/openssladapter.h" | 
 | #include "webrtc/base/openssldigest.h" | 
 | #include "webrtc/base/opensslidentity.h" | 
 | #include "webrtc/base/stringutils.h" | 
 | #include "webrtc/base/thread.h" | 
 |  | 
 | namespace rtc { | 
 |  | 
 | #if (OPENSSL_VERSION_NUMBER >= 0x10001000L) | 
 | #define HAVE_DTLS_SRTP | 
 | #endif | 
 |  | 
 | #ifdef HAVE_DTLS_SRTP | 
 | // SRTP cipher suite table | 
 | struct SrtpCipherMapEntry { | 
 |   const char* external_name; | 
 |   const char* internal_name; | 
 | }; | 
 |  | 
 | // This isn't elegant, but it's better than an external reference | 
 | static SrtpCipherMapEntry SrtpCipherMap[] = { | 
 |   {"AES_CM_128_HMAC_SHA1_80", "SRTP_AES128_CM_SHA1_80"}, | 
 |   {"AES_CM_128_HMAC_SHA1_32", "SRTP_AES128_CM_SHA1_32"}, | 
 |   {NULL, NULL} | 
 | }; | 
 | #endif | 
 |  | 
 | // Cipher name table. Maps internal OpenSSL cipher ids to the RFC name. | 
 | struct SslCipherMapEntry { | 
 |   uint32_t openssl_id; | 
 |   const char* rfc_name; | 
 | }; | 
 |  | 
 | #define DEFINE_CIPHER_ENTRY_SSL3(name)  {SSL3_CK_##name, "TLS_"#name} | 
 | #define DEFINE_CIPHER_ENTRY_TLS1(name)  {TLS1_CK_##name, "TLS_"#name} | 
 |  | 
 | // There currently is no method available to get a RFC-compliant name for a | 
 | // cipher suite from BoringSSL, so we need to define the mapping manually here. | 
 | // This should go away once BoringSSL supports "SSL_CIPHER_standard_name" | 
 | // (as available in OpenSSL if compiled with tracing enabled) or a similar | 
 | // method. | 
 | static const 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), | 
 |  | 
 | #ifdef OPENSSL_IS_BORINGSSL | 
 |   {TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, | 
 |       "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"}, | 
 |   {TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, | 
 |       "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"}, | 
 |   {TLS1_CK_DHE_RSA_CHACHA20_POLY1305, | 
 |       "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256"}, | 
 | #endif | 
 |  | 
 |   {0, NULL} | 
 | }; | 
 |  | 
 | // Default cipher used between OpenSSL/BoringSSL stream adapters. | 
 | // This needs to be updated when the default of the SSL library changes. | 
 | static const char kDefaultSslCipher[] = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"; | 
 |  | 
 | ////////////////////////////////////////////////////////////////////// | 
 | // 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); | 
 |  | 
 | // TODO(davidben): This should be const once BoringSSL is assumed. | 
 | static BIO_METHOD methods_stream = { | 
 |   BIO_TYPE_BIO, | 
 |   "stream", | 
 |   stream_write, | 
 |   stream_read, | 
 |   stream_puts, | 
 |   0, | 
 |   stream_ctrl, | 
 |   stream_new, | 
 |   stream_free, | 
 |   NULL, | 
 | }; | 
 |  | 
 | static BIO_METHOD* BIO_s_stream() { return(&methods_stream); } | 
 |  | 
 | static BIO* BIO_new_stream(StreamInterface* stream) { | 
 |   BIO* ret = BIO_new(BIO_s_stream()); | 
 |   if (ret == NULL) | 
 |     return NULL; | 
 |   ret->ptr = stream; | 
 |   return ret; | 
 | } | 
 |  | 
 | // bio methods return 1 (or at least non-zero) on success and 0 on failure. | 
 |  | 
 | static int stream_new(BIO* b) { | 
 |   b->shutdown = 0; | 
 |   b->init = 1; | 
 |   b->num = 0;  // 1 means end-of-stream | 
 |   b->ptr = 0; | 
 |   return 1; | 
 | } | 
 |  | 
 | static int stream_free(BIO* b) { | 
 |   if (b == NULL) | 
 |     return 0; | 
 |   return 1; | 
 | } | 
 |  | 
 | static int stream_read(BIO* b, char* out, int outl) { | 
 |   if (!out) | 
 |     return -1; | 
 |   StreamInterface* stream = static_cast<StreamInterface*>(b->ptr); | 
 |   BIO_clear_retry_flags(b); | 
 |   size_t read; | 
 |   int error; | 
 |   StreamResult result = stream->Read(out, outl, &read, &error); | 
 |   if (result == SR_SUCCESS) { | 
 |     return checked_cast<int>(read); | 
 |   } else if (result == SR_EOS) { | 
 |     b->num = 1; | 
 |   } else if (result == 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*>(b->ptr); | 
 |   BIO_clear_retry_flags(b); | 
 |   size_t written; | 
 |   int error; | 
 |   StreamResult result = stream->Write(in, inl, &written, &error); | 
 |   if (result == SR_SUCCESS) { | 
 |     return checked_cast<int>(written); | 
 |   } else if (result == SR_BLOCK) { | 
 |     BIO_set_retry_write(b); | 
 |   } | 
 |   return -1; | 
 | } | 
 |  | 
 | static int stream_puts(BIO* b, const char* str) { | 
 |   return stream_write(b, str, checked_cast<int>(strlen(str))); | 
 | } | 
 |  | 
 | static long stream_ctrl(BIO* b, int cmd, long num, void* ptr) { | 
 |   RTC_UNUSED(num); | 
 |   RTC_UNUSED(ptr); | 
 |  | 
 |   switch (cmd) { | 
 |     case BIO_CTRL_RESET: | 
 |       return 0; | 
 |     case BIO_CTRL_EOF: | 
 |       return b->num; | 
 |     case BIO_CTRL_WPENDING: | 
 |     case BIO_CTRL_PENDING: | 
 |       return 0; | 
 |     case BIO_CTRL_FLUSH: | 
 |       return 1; | 
 |     default: | 
 |       return 0; | 
 |   } | 
 | } | 
 |  | 
 | ///////////////////////////////////////////////////////////////////////////// | 
 | // OpenSSLStreamAdapter | 
 | ///////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | OpenSSLStreamAdapter::OpenSSLStreamAdapter(StreamInterface* stream) | 
 |     : SSLStreamAdapter(stream), | 
 |       state_(SSL_NONE), | 
 |       role_(SSL_CLIENT), | 
 |       ssl_read_needs_write_(false), ssl_write_needs_read_(false), | 
 |       ssl_(NULL), ssl_ctx_(NULL), | 
 |       custom_verification_succeeded_(false), | 
 |       ssl_mode_(SSL_MODE_TLS) { | 
 | } | 
 |  | 
 | OpenSSLStreamAdapter::~OpenSSLStreamAdapter() { | 
 |   Cleanup(); | 
 | } | 
 |  | 
 | void OpenSSLStreamAdapter::SetIdentity(SSLIdentity* identity) { | 
 |   ASSERT(!identity_); | 
 |   identity_.reset(static_cast<OpenSSLIdentity*>(identity)); | 
 | } | 
 |  | 
 | void OpenSSLStreamAdapter::SetServerRole(SSLRole role) { | 
 |   role_ = role; | 
 | } | 
 |  | 
 | bool OpenSSLStreamAdapter::GetPeerCertificate(SSLCertificate** cert) const { | 
 |   if (!peer_certificate_) | 
 |     return false; | 
 |  | 
 |   *cert = peer_certificate_->GetReference(); | 
 |   return true; | 
 | } | 
 |  | 
 | bool OpenSSLStreamAdapter::SetPeerCertificateDigest(const std::string | 
 |                                                     &digest_alg, | 
 |                                                     const unsigned char* | 
 |                                                     digest_val, | 
 |                                                     size_t digest_len) { | 
 |   ASSERT(!peer_certificate_); | 
 |   ASSERT(peer_certificate_digest_algorithm_.size() == 0); | 
 |   ASSERT(ssl_server_name_.empty()); | 
 |   size_t expected_len; | 
 |  | 
 |   if (!OpenSSLDigest::GetDigestSize(digest_alg, &expected_len)) { | 
 |     LOG(LS_WARNING) << "Unknown digest algorithm: " << digest_alg; | 
 |     return false; | 
 |   } | 
 |   if (expected_len != digest_len) | 
 |     return false; | 
 |  | 
 |   peer_certificate_digest_value_.SetData(digest_val, digest_len); | 
 |   peer_certificate_digest_algorithm_ = digest_alg; | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | const char* OpenSSLStreamAdapter::GetRfcSslCipherName( | 
 |     const SSL_CIPHER* cipher) { | 
 |   ASSERT(cipher != NULL); | 
 |   for (const SslCipherMapEntry* entry = kSslCipherMap; entry->rfc_name; | 
 |        ++entry) { | 
 |     if (cipher->id == entry->openssl_id) { | 
 |       return entry->rfc_name; | 
 |     } | 
 |   } | 
 |   return NULL; | 
 | } | 
 |  | 
 | bool OpenSSLStreamAdapter::GetSslCipher(std::string* cipher) { | 
 |   if (state_ != SSL_CONNECTED) | 
 |     return false; | 
 |  | 
 |   const SSL_CIPHER* current_cipher = SSL_get_current_cipher(ssl_); | 
 |   if (current_cipher == NULL) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   const char* cipher_name = GetRfcSslCipherName(current_cipher); | 
 |   if (cipher_name == NULL) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   *cipher = cipher_name; | 
 |   return true; | 
 | } | 
 |  | 
 | // Key Extractor interface | 
 | bool OpenSSLStreamAdapter::ExportKeyingMaterial(const std::string& label, | 
 |                                                 const uint8* context, | 
 |                                                 size_t context_len, | 
 |                                                 bool use_context, | 
 |                                                 uint8* result, | 
 |                                                 size_t result_len) { | 
 | #ifdef HAVE_DTLS_SRTP | 
 |   int i; | 
 |  | 
 |   i = SSL_export_keying_material(ssl_, result, result_len, | 
 |                                  label.c_str(), label.length(), | 
 |                                  const_cast<uint8 *>(context), | 
 |                                  context_len, use_context); | 
 |  | 
 |   if (i != 1) | 
 |     return false; | 
 |  | 
 |   return true; | 
 | #else | 
 |   return false; | 
 | #endif | 
 | } | 
 |  | 
 | bool OpenSSLStreamAdapter::SetDtlsSrtpCiphers( | 
 |     const std::vector<std::string>& ciphers) { | 
 | #ifdef HAVE_DTLS_SRTP | 
 |   std::string internal_ciphers; | 
 |  | 
 |   if (state_ != SSL_NONE) | 
 |     return false; | 
 |  | 
 |   for (std::vector<std::string>::const_iterator cipher = ciphers.begin(); | 
 |        cipher != ciphers.end(); ++cipher) { | 
 |     bool found = false; | 
 |     for (SrtpCipherMapEntry *entry = SrtpCipherMap; entry->internal_name; | 
 |          ++entry) { | 
 |       if (*cipher == entry->external_name) { | 
 |         found = true; | 
 |         if (!internal_ciphers.empty()) | 
 |           internal_ciphers += ":"; | 
 |         internal_ciphers += entry->internal_name; | 
 |         break; | 
 |       } | 
 |     } | 
 |  | 
 |     if (!found) { | 
 |       LOG(LS_ERROR) << "Could not find cipher: " << *cipher; | 
 |       return false; | 
 |     } | 
 |   } | 
 |  | 
 |   if (internal_ciphers.empty()) | 
 |     return false; | 
 |  | 
 |   srtp_ciphers_ = internal_ciphers; | 
 |   return true; | 
 | #else | 
 |   return false; | 
 | #endif | 
 | } | 
 |  | 
 | bool OpenSSLStreamAdapter::GetDtlsSrtpCipher(std::string* cipher) { | 
 | #ifdef HAVE_DTLS_SRTP | 
 |   ASSERT(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; | 
 |  | 
 |   for (SrtpCipherMapEntry *entry = SrtpCipherMap; | 
 |        entry->internal_name; ++entry) { | 
 |     if (!strcmp(entry->internal_name, srtp_profile->name)) { | 
 |       *cipher = entry->external_name; | 
 |       return true; | 
 |     } | 
 |   } | 
 |  | 
 |   ASSERT(false);  // This should never happen | 
 |  | 
 |   return false; | 
 | #else | 
 |   return false; | 
 | #endif | 
 | } | 
 |  | 
 | int OpenSSLStreamAdapter::StartSSLWithServer(const char* server_name) { | 
 |   ASSERT(server_name != NULL && server_name[0] != '\0'); | 
 |   ssl_server_name_ = server_name; | 
 |   return StartSSL(); | 
 | } | 
 |  | 
 | int OpenSSLStreamAdapter::StartSSLWithPeer() { | 
 |   ASSERT(ssl_server_name_.empty()); | 
 |   // It is permitted to specify peer_certificate_ only later. | 
 |   return StartSSL(); | 
 | } | 
 |  | 
 | void OpenSSLStreamAdapter::SetMode(SSLMode mode) { | 
 |   ASSERT(state_ == SSL_NONE); | 
 |   ssl_mode_ = mode; | 
 | } | 
 |  | 
 | // | 
 | // StreamInterface Implementation | 
 | // | 
 |  | 
 | StreamResult OpenSSLStreamAdapter::Write(const void* data, size_t data_len, | 
 |                                          size_t* written, int* error) { | 
 |   LOG(LS_VERBOSE) << "OpenSSLStreamAdapter::Write(" << data_len << ")"; | 
 |  | 
 |   switch (state_) { | 
 |   case SSL_NONE: | 
 |     // pass-through in clear text | 
 |     return StreamAdapterInterface::Write(data, data_len, written, error); | 
 |  | 
 |   case SSL_WAIT: | 
 |   case SSL_CONNECTING: | 
 |     return SR_BLOCK; | 
 |  | 
 |   case SSL_CONNECTED: | 
 |     break; | 
 |  | 
 |   case SSL_ERROR: | 
 |   case SSL_CLOSED: | 
 |   default: | 
 |     if (error) | 
 |       *error = ssl_error_code_; | 
 |     return SR_ERROR; | 
 |   } | 
 |  | 
 |   // OpenSSL will return an error if we try to write zero bytes | 
 |   if (data_len == 0) { | 
 |     if (written) | 
 |       *written = 0; | 
 |     return SR_SUCCESS; | 
 |   } | 
 |  | 
 |   ssl_write_needs_read_ = false; | 
 |  | 
 |   int code = SSL_write(ssl_, data, checked_cast<int>(data_len)); | 
 |   int ssl_error = SSL_get_error(ssl_, code); | 
 |   switch (ssl_error) { | 
 |   case SSL_ERROR_NONE: | 
 |     LOG(LS_VERBOSE) << " -- success"; | 
 |     ASSERT(0 < code && static_cast<unsigned>(code) <= data_len); | 
 |     if (written) | 
 |       *written = code; | 
 |     return SR_SUCCESS; | 
 |   case SSL_ERROR_WANT_READ: | 
 |     LOG(LS_VERBOSE) << " -- error want read"; | 
 |     ssl_write_needs_read_ = true; | 
 |     return SR_BLOCK; | 
 |   case SSL_ERROR_WANT_WRITE: | 
 |     LOG(LS_VERBOSE) << " -- error want write"; | 
 |     return SR_BLOCK; | 
 |  | 
 |   case SSL_ERROR_ZERO_RETURN: | 
 |   default: | 
 |     Error("SSL_write", (ssl_error ? ssl_error : -1), false); | 
 |     if (error) | 
 |       *error = ssl_error_code_; | 
 |     return SR_ERROR; | 
 |   } | 
 |   // not reached | 
 | } | 
 |  | 
 | StreamResult OpenSSLStreamAdapter::Read(void* data, size_t data_len, | 
 |                                         size_t* read, int* error) { | 
 |   LOG(LS_VERBOSE) << "OpenSSLStreamAdapter::Read(" << data_len << ")"; | 
 |   switch (state_) { | 
 |     case SSL_NONE: | 
 |       // pass-through in clear text | 
 |       return StreamAdapterInterface::Read(data, data_len, read, error); | 
 |  | 
 |     case SSL_WAIT: | 
 |     case SSL_CONNECTING: | 
 |       return SR_BLOCK; | 
 |  | 
 |     case SSL_CONNECTED: | 
 |       break; | 
 |  | 
 |     case SSL_CLOSED: | 
 |       return SR_EOS; | 
 |  | 
 |     case SSL_ERROR: | 
 |     default: | 
 |       if (error) | 
 |         *error = ssl_error_code_; | 
 |       return SR_ERROR; | 
 |   } | 
 |  | 
 |   // Don't trust OpenSSL with zero byte reads | 
 |   if (data_len == 0) { | 
 |     if (read) | 
 |       *read = 0; | 
 |     return SR_SUCCESS; | 
 |   } | 
 |  | 
 |   ssl_read_needs_write_ = false; | 
 |  | 
 |   int code = SSL_read(ssl_, data, checked_cast<int>(data_len)); | 
 |   int ssl_error = SSL_get_error(ssl_, code); | 
 |   switch (ssl_error) { | 
 |     case SSL_ERROR_NONE: | 
 |       LOG(LS_VERBOSE) << " -- success"; | 
 |       ASSERT(0 < code && static_cast<unsigned>(code) <= data_len); | 
 |       if (read) | 
 |         *read = code; | 
 |  | 
 |       if (ssl_mode_ == SSL_MODE_DTLS) { | 
 |         // Enforce atomic reads -- this is a short read | 
 |         unsigned int pending = SSL_pending(ssl_); | 
 |  | 
 |         if (pending) { | 
 |           LOG(LS_INFO) << " -- short DTLS read. flushing"; | 
 |           FlushInput(pending); | 
 |           if (error) | 
 |             *error = SSE_MSG_TRUNC; | 
 |           return SR_ERROR; | 
 |         } | 
 |       } | 
 |       return SR_SUCCESS; | 
 |     case SSL_ERROR_WANT_READ: | 
 |       LOG(LS_VERBOSE) << " -- error want read"; | 
 |       return SR_BLOCK; | 
 |     case SSL_ERROR_WANT_WRITE: | 
 |       LOG(LS_VERBOSE) << " -- error want write"; | 
 |       ssl_read_needs_write_ = true; | 
 |       return SR_BLOCK; | 
 |     case SSL_ERROR_ZERO_RETURN: | 
 |       LOG(LS_VERBOSE) << " -- remote side closed"; | 
 |       return SR_EOS; | 
 |       break; | 
 |     default: | 
 |       LOG(LS_VERBOSE) << " -- error " << code; | 
 |       Error("SSL_read", (ssl_error ? ssl_error : -1), false); | 
 |       if (error) | 
 |         *error = ssl_error_code_; | 
 |       return SR_ERROR; | 
 |   } | 
 |   // not reached | 
 | } | 
 |  | 
 | void OpenSSLStreamAdapter::FlushInput(unsigned int left) { | 
 |   unsigned char buf[2048]; | 
 |  | 
 |   while (left) { | 
 |     // This should always succeed | 
 |     int toread = (sizeof(buf) < left) ? sizeof(buf) : left; | 
 |     int code = SSL_read(ssl_, buf, toread); | 
 |  | 
 |     int ssl_error = SSL_get_error(ssl_, code); | 
 |     ASSERT(ssl_error == SSL_ERROR_NONE); | 
 |  | 
 |     if (ssl_error != SSL_ERROR_NONE) { | 
 |       LOG(LS_VERBOSE) << " -- error " << code; | 
 |       Error("SSL_read", (ssl_error ? ssl_error : -1), false); | 
 |       return; | 
 |     } | 
 |  | 
 |     LOG(LS_VERBOSE) << " -- flushed " << code << " bytes"; | 
 |     left -= code; | 
 |   } | 
 | } | 
 |  | 
 | void OpenSSLStreamAdapter::Close() { | 
 |   Cleanup(); | 
 |   ASSERT(state_ == SSL_CLOSED || state_ == SSL_ERROR); | 
 |   StreamAdapterInterface::Close(); | 
 | } | 
 |  | 
 | StreamState OpenSSLStreamAdapter::GetState() const { | 
 |   switch (state_) { | 
 |     case SSL_WAIT: | 
 |     case SSL_CONNECTING: | 
 |       return SS_OPENING; | 
 |     case SSL_CONNECTED: | 
 |       return SS_OPEN; | 
 |     default: | 
 |       return SS_CLOSED; | 
 |   }; | 
 |   // not reached | 
 | } | 
 |  | 
 | void OpenSSLStreamAdapter::OnEvent(StreamInterface* stream, int events, | 
 |                                    int err) { | 
 |   int events_to_signal = 0; | 
 |   int signal_error = 0; | 
 |   ASSERT(stream == this->stream()); | 
 |   if ((events & SE_OPEN)) { | 
 |     LOG(LS_VERBOSE) << "OpenSSLStreamAdapter::OnEvent SE_OPEN"; | 
 |     if (state_ != SSL_WAIT) { | 
 |       ASSERT(state_ == SSL_NONE); | 
 |       events_to_signal |= SE_OPEN; | 
 |     } else { | 
 |       state_ = SSL_CONNECTING; | 
 |       if (int err = BeginSSL()) { | 
 |         Error("BeginSSL", err, true); | 
 |         return; | 
 |       } | 
 |     } | 
 |   } | 
 |   if ((events & (SE_READ|SE_WRITE))) { | 
 |     LOG(LS_VERBOSE) << "OpenSSLStreamAdapter::OnEvent" | 
 |                  << ((events & SE_READ) ? " SE_READ" : "") | 
 |                  << ((events & SE_WRITE) ? " SE_WRITE" : ""); | 
 |     if (state_ == SSL_NONE) { | 
 |       events_to_signal |= events & (SE_READ|SE_WRITE); | 
 |     } else if (state_ == SSL_CONNECTING) { | 
 |       if (int err = ContinueSSL()) { | 
 |         Error("ContinueSSL", err, true); | 
 |         return; | 
 |       } | 
 |     } else if (state_ == SSL_CONNECTED) { | 
 |       if (((events & SE_READ) && ssl_write_needs_read_) || | 
 |           (events & SE_WRITE)) { | 
 |         LOG(LS_VERBOSE) << " -- onStreamWriteable"; | 
 |         events_to_signal |= SE_WRITE; | 
 |       } | 
 |       if (((events & SE_WRITE) && ssl_read_needs_write_) || | 
 |           (events & SE_READ)) { | 
 |         LOG(LS_VERBOSE) << " -- onStreamReadable"; | 
 |         events_to_signal |= SE_READ; | 
 |       } | 
 |     } | 
 |   } | 
 |   if ((events & SE_CLOSE)) { | 
 |     LOG(LS_VERBOSE) << "OpenSSLStreamAdapter::OnEvent(SE_CLOSE, " << err << ")"; | 
 |     Cleanup(); | 
 |     events_to_signal |= SE_CLOSE; | 
 |     // SE_CLOSE is the only event that uses the final parameter to OnEvent(). | 
 |     ASSERT(signal_error == 0); | 
 |     signal_error = err; | 
 |   } | 
 |   if (events_to_signal) | 
 |     StreamAdapterInterface::OnEvent(stream, events_to_signal, signal_error); | 
 | } | 
 |  | 
 | int OpenSSLStreamAdapter::StartSSL() { | 
 |   ASSERT(state_ == SSL_NONE); | 
 |  | 
 |   if (StreamAdapterInterface::GetState() != SS_OPEN) { | 
 |     state_ = SSL_WAIT; | 
 |     return 0; | 
 |   } | 
 |  | 
 |   state_ = SSL_CONNECTING; | 
 |   if (int err = BeginSSL()) { | 
 |     Error("BeginSSL", err, false); | 
 |     return err; | 
 |   } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | int OpenSSLStreamAdapter::BeginSSL() { | 
 |   ASSERT(state_ == SSL_CONNECTING); | 
 |   // The underlying stream has open. If we are in peer-to-peer mode | 
 |   // then a peer certificate must have been specified by now. | 
 |   ASSERT(!ssl_server_name_.empty() || | 
 |          !peer_certificate_digest_algorithm_.empty()); | 
 |   LOG(LS_INFO) << "BeginSSL: " | 
 |                << (!ssl_server_name_.empty() ? ssl_server_name_ : | 
 |                                                "with peer"); | 
 |  | 
 |   BIO* bio = NULL; | 
 |  | 
 |   // First set up the context | 
 |   ASSERT(ssl_ctx_ == NULL); | 
 |   ssl_ctx_ = SetupSSLContext(); | 
 |   if (!ssl_ctx_) | 
 |     return -1; | 
 |  | 
 |   bio = BIO_new_stream(static_cast<StreamInterface*>(stream())); | 
 |   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. | 
 |  | 
 |   SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE | | 
 |                SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); | 
 |  | 
 |   // Specify an ECDH group for ECDHE ciphers, otherwise they cannot be | 
 |   // negotiated when acting as the server. Use NIST's P-256 which is commonly | 
 |   // supported. | 
 |   EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); | 
 |   if (ecdh == NULL) | 
 |     return -1; | 
 |   SSL_set_options(ssl_, SSL_OP_SINGLE_ECDH_USE); | 
 |   SSL_set_tmp_ecdh(ssl_, ecdh); | 
 |   EC_KEY_free(ecdh); | 
 |  | 
 |   // Do the connect | 
 |   return ContinueSSL(); | 
 | } | 
 |  | 
 | int OpenSSLStreamAdapter::ContinueSSL() { | 
 |   LOG(LS_VERBOSE) << "ContinueSSL"; | 
 |   ASSERT(state_ == SSL_CONNECTING); | 
 |  | 
 |   // Clear the DTLS timer | 
 |   Thread::Current()->Clear(this, MSG_TIMEOUT); | 
 |  | 
 |   int code = (role_ == SSL_CLIENT) ? SSL_connect(ssl_) : SSL_accept(ssl_); | 
 |   int ssl_error; | 
 |   switch (ssl_error = SSL_get_error(ssl_, code)) { | 
 |     case SSL_ERROR_NONE: | 
 |       LOG(LS_VERBOSE) << " -- success"; | 
 |  | 
 |       if (!SSLPostConnectionCheck(ssl_, ssl_server_name_.c_str(), NULL, | 
 |                                   peer_certificate_digest_algorithm_)) { | 
 |         LOG(LS_ERROR) << "TLS post connection check failed"; | 
 |         return -1; | 
 |       } | 
 |  | 
 |       state_ = SSL_CONNECTED; | 
 |       StreamAdapterInterface::OnEvent(stream(), SE_OPEN|SE_READ|SE_WRITE, 0); | 
 |       break; | 
 |  | 
 |     case SSL_ERROR_WANT_READ: { | 
 |         LOG(LS_VERBOSE) << " -- error want read"; | 
 |         struct timeval timeout; | 
 |         if (DTLSv1_get_timeout(ssl_, &timeout)) { | 
 |           int delay = timeout.tv_sec * 1000 + timeout.tv_usec/1000; | 
 |  | 
 |           Thread::Current()->PostDelayed(delay, this, MSG_TIMEOUT, 0); | 
 |         } | 
 |       } | 
 |       break; | 
 |  | 
 |     case SSL_ERROR_WANT_WRITE: | 
 |       LOG(LS_VERBOSE) << " -- error want write"; | 
 |       break; | 
 |  | 
 |     case SSL_ERROR_ZERO_RETURN: | 
 |     default: | 
 |       LOG(LS_VERBOSE) << " -- error " << code; | 
 |       return (ssl_error != 0) ? ssl_error : -1; | 
 |   } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | void OpenSSLStreamAdapter::Error(const char* context, int err, bool signal) { | 
 |   LOG(LS_WARNING) << "OpenSSLStreamAdapter::Error(" | 
 |                   << context << ", " << err << ")"; | 
 |   state_ = SSL_ERROR; | 
 |   ssl_error_code_ = err; | 
 |   Cleanup(); | 
 |   if (signal) | 
 |     StreamAdapterInterface::OnEvent(stream(), SE_CLOSE, err); | 
 | } | 
 |  | 
 | void OpenSSLStreamAdapter::Cleanup() { | 
 |   LOG(LS_INFO) << "Cleanup"; | 
 |  | 
 |   if (state_ != SSL_ERROR) { | 
 |     state_ = SSL_CLOSED; | 
 |     ssl_error_code_ = 0; | 
 |   } | 
 |  | 
 |   if (ssl_) { | 
 |     int ret = SSL_shutdown(ssl_); | 
 |     if (ret < 0) { | 
 |       LOG(LS_WARNING) << "SSL_shutdown failed, error = " | 
 |                       << SSL_get_error(ssl_, ret); | 
 |     } | 
 |  | 
 |     SSL_free(ssl_); | 
 |     ssl_ = NULL; | 
 |   } | 
 |   if (ssl_ctx_) { | 
 |     SSL_CTX_free(ssl_ctx_); | 
 |     ssl_ctx_ = NULL; | 
 |   } | 
 |   identity_.reset(); | 
 |   peer_certificate_.reset(); | 
 |  | 
 |   // Clear the DTLS timer | 
 |   Thread::Current()->Clear(this, MSG_TIMEOUT); | 
 | } | 
 |  | 
 |  | 
 | void OpenSSLStreamAdapter::OnMessage(Message* msg) { | 
 |   // Process our own messages and then pass others to the superclass | 
 |   if (MSG_TIMEOUT == msg->message_id) { | 
 |     LOG(LS_INFO) << "DTLS timeout expired"; | 
 |     DTLSv1_handle_timeout(ssl_); | 
 |     ContinueSSL(); | 
 |   } else { | 
 |     StreamInterface::OnMessage(msg); | 
 |   } | 
 | } | 
 |  | 
 | SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() { | 
 |   SSL_CTX *ctx = NULL; | 
 |  | 
 |   if (role_ == SSL_CLIENT) { | 
 |     ctx = SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ? | 
 |         DTLSv1_client_method() : TLSv1_client_method()); | 
 |   } else { | 
 |     ctx = SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ? | 
 |         DTLSv1_server_method() : TLSv1_server_method()); | 
 |   } | 
 |   if (ctx == NULL) | 
 |     return NULL; | 
 |  | 
 |   if (identity_ && !identity_->ConfigureIdentity(ctx)) { | 
 |     SSL_CTX_free(ctx); | 
 |     return NULL; | 
 |   } | 
 |  | 
 | #ifdef _DEBUG | 
 |   SSL_CTX_set_info_callback(ctx, OpenSSLAdapter::SSLInfoCallback); | 
 | #endif | 
 |  | 
 |   int mode = SSL_VERIFY_PEER; | 
 |   if (client_auth_enabled()) { | 
 |     // 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; | 
 |   } | 
 |  | 
 |   SSL_CTX_set_verify(ctx, mode, SSLVerifyCallback); | 
 |   SSL_CTX_set_verify_depth(ctx, 4); | 
 |   SSL_CTX_set_cipher_list(ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); | 
 |  | 
 | #ifdef HAVE_DTLS_SRTP | 
 |   if (!srtp_ciphers_.empty()) { | 
 |     if (SSL_CTX_set_tlsext_use_srtp(ctx, srtp_ciphers_.c_str())) { | 
 |       SSL_CTX_free(ctx); | 
 |       return NULL; | 
 |     } | 
 |   } | 
 | #endif | 
 |  | 
 |   return ctx; | 
 | } | 
 |  | 
 | int OpenSSLStreamAdapter::SSLVerifyCallback(int ok, X509_STORE_CTX* store) { | 
 |   // Get our SSL structure 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)); | 
 |  | 
 |   if (stream->peer_certificate_digest_algorithm_.empty()) { | 
 |     return 0; | 
 |   } | 
 |   X509* cert = X509_STORE_CTX_get_current_cert(store); | 
 |   int depth = X509_STORE_CTX_get_error_depth(store); | 
 |  | 
 |   // For now We ignore the parent certificates and verify the leaf against | 
 |   // the digest. | 
 |   // | 
 |   // TODO(jiayl): Verify the chain is a proper chain and report the chain to | 
 |   // |stream->peer_certificate_|, like what NSS does. | 
 |   if (depth > 0) { | 
 |     LOG(LS_INFO) << "Ignored chained certificate at depth " << depth; | 
 |     return 1; | 
 |   } | 
 |  | 
 |   unsigned char digest[EVP_MAX_MD_SIZE]; | 
 |   size_t digest_length; | 
 |   if (!OpenSSLCertificate::ComputeDigest( | 
 |            cert, | 
 |            stream->peer_certificate_digest_algorithm_, | 
 |            digest, sizeof(digest), | 
 |            &digest_length)) { | 
 |     LOG(LS_WARNING) << "Failed to compute peer cert digest."; | 
 |     return 0; | 
 |   } | 
 |  | 
 |   Buffer computed_digest(digest, digest_length); | 
 |   if (computed_digest != stream->peer_certificate_digest_value_) { | 
 |     LOG(LS_WARNING) << "Rejected peer certificate due to mismatched digest."; | 
 |     return 0; | 
 |   } | 
 |   // 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. | 
 |   LOG(LS_INFO) << "Accepted peer certificate."; | 
 |  | 
 |   // Record the peer's certificate. | 
 |   stream->peer_certificate_.reset(new OpenSSLCertificate(cert)); | 
 |   return 1; | 
 | } | 
 |  | 
 | // This code is taken from the "Network Security with OpenSSL" | 
 | // sample in chapter 5 | 
 | bool OpenSSLStreamAdapter::SSLPostConnectionCheck(SSL* ssl, | 
 |                                                   const char* server_name, | 
 |                                                   const X509* peer_cert, | 
 |                                                   const std::string | 
 |                                                   &peer_digest) { | 
 |   ASSERT(server_name != NULL); | 
 |   bool ok; | 
 |   if (server_name[0] != '\0') {  // traditional mode | 
 |     ok = OpenSSLAdapter::VerifyServerName(ssl, server_name, ignore_bad_cert()); | 
 |  | 
 |     if (ok) { | 
 |       ok = (SSL_get_verify_result(ssl) == X509_V_OK || | 
 |             custom_verification_succeeded_); | 
 |     } | 
 |   } else {  // peer-to-peer mode | 
 |     ASSERT((peer_cert != NULL) || (!peer_digest.empty())); | 
 |     // no server name validation | 
 |     ok = true; | 
 |   } | 
 |  | 
 |   if (!ok && ignore_bad_cert()) { | 
 |     LOG(LS_ERROR) << "SSL_get_verify_result(ssl) = " | 
 |                   << SSL_get_verify_result(ssl); | 
 |     LOG(LS_INFO) << "Other TLS post connection checks failed."; | 
 |     ok = true; | 
 |   } | 
 |  | 
 |   return ok; | 
 | } | 
 |  | 
 | bool OpenSSLStreamAdapter::HaveDtls() { | 
 |   return true; | 
 | } | 
 |  | 
 | bool OpenSSLStreamAdapter::HaveDtlsSrtp() { | 
 | #ifdef HAVE_DTLS_SRTP | 
 |   return true; | 
 | #else | 
 |   return false; | 
 | #endif | 
 | } | 
 |  | 
 | bool OpenSSLStreamAdapter::HaveExporter() { | 
 | #ifdef HAVE_DTLS_SRTP | 
 |   return true; | 
 | #else | 
 |   return false; | 
 | #endif | 
 | } | 
 |  | 
 | std::string OpenSSLStreamAdapter::GetDefaultSslCipher() { | 
 |   return kDefaultSslCipher; | 
 | } | 
 |  | 
 | }  // namespace rtc | 
 |  | 
 | #endif  // HAVE_OPENSSL_SSL_H |