diff --git a/AUTHORS b/AUTHORS index 09e4f6250..069c3322e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -37,5 +37,6 @@ Intel Corporation MIPS Technologies Mozilla Foundation Opera Software ASA +struktur AG Temasys Communications Vonage Holdings Corp. diff --git a/webrtc/base/nssstreamadapter.cc b/webrtc/base/nssstreamadapter.cc index 7152eda5c..1286bf96b 100644 --- a/webrtc/base/nssstreamadapter.cc +++ b/webrtc/base/nssstreamadapter.cc @@ -66,6 +66,10 @@ static const SrtpCipherMapEntry kSrtpCipherMap[] = { }; #endif +// Default cipher used between NSS stream adapters. +// This needs to be updated when the default of the SSL library changes. +static const char kDefaultSslCipher[] = "TLS_RSA_WITH_AES_128_CBC_SHA"; + // Implementation of NSPR methods static PRStatus StreamClose(PRFileDesc *socket) { @@ -866,6 +870,27 @@ SECStatus NSSStreamAdapter::GetClientAuthDataHook(void *arg, PRFileDesc *fd, return SECSuccess; } +bool NSSStreamAdapter::GetSslCipher(std::string* cipher) { + ASSERT(state_ == SSL_CONNECTED); + if (state_ != SSL_CONNECTED) + return false; + + SSLChannelInfo channel_info; + SECStatus rv = SSL_GetChannelInfo(ssl_fd_, &channel_info, + sizeof(channel_info)); + if (rv == SECFailure) + return false; + + SSLCipherSuiteInfo ciphersuite_info; + rv = SSL_GetCipherSuiteInfo(channel_info.cipherSuite, &ciphersuite_info, + sizeof(ciphersuite_info)); + if (rv == SECFailure) + return false; + + *cipher = ciphersuite_info.cipherSuiteName; + return true; +} + // RFC 5705 Key Exporter bool NSSStreamAdapter::ExportKeyingMaterial(const std::string& label, const uint8* context, @@ -1011,6 +1036,10 @@ bool NSSStreamAdapter::HaveExporter() { return true; } +std::string NSSStreamAdapter::GetDefaultSslCipher() { + return kDefaultSslCipher; +} + } // namespace rtc #endif // HAVE_NSS_SSL_H diff --git a/webrtc/base/nssstreamadapter.h b/webrtc/base/nssstreamadapter.h index 210a47933..afa2eb690 100644 --- a/webrtc/base/nssstreamadapter.h +++ b/webrtc/base/nssstreamadapter.h @@ -61,6 +61,8 @@ class NSSStreamAdapter : public SSLStreamAdapterHelper { size_t* written, int* error); void OnMessage(Message *msg); + virtual bool GetSslCipher(std::string* cipher); + // Key Extractor interface virtual bool ExportKeyingMaterial(const std::string& label, const uint8* context, @@ -77,6 +79,7 @@ class NSSStreamAdapter : public SSLStreamAdapterHelper { static bool HaveDtls(); static bool HaveDtlsSrtp(); static bool HaveExporter(); + static std::string GetDefaultSslCipher(); protected: // Override SSLStreamAdapter diff --git a/webrtc/base/opensslstreamadapter.cc b/webrtc/base/opensslstreamadapter.cc index c18295f57..0f82d281f 100644 --- a/webrtc/base/opensslstreamadapter.cc +++ b/webrtc/base/opensslstreamadapter.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,99 @@ static SrtpCipherMapEntry SrtpCipherMap[] = { }; #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 ////////////////////////////////////////////////////////////////////// @@ -222,6 +316,36 @@ bool OpenSSLStreamAdapter::SetPeerCertificateDigest(const std::string 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, @@ -877,6 +1001,10 @@ bool OpenSSLStreamAdapter::HaveExporter() { #endif } +std::string OpenSSLStreamAdapter::GetDefaultSslCipher() { + return kDefaultSslCipher; +} + } // namespace rtc #endif // HAVE_OPENSSL_SSL_H diff --git a/webrtc/base/opensslstreamadapter.h b/webrtc/base/opensslstreamadapter.h index 9506217b4..a9d98fd69 100644 --- a/webrtc/base/opensslstreamadapter.h +++ b/webrtc/base/opensslstreamadapter.h @@ -20,6 +20,7 @@ typedef struct ssl_st SSL; typedef struct ssl_ctx_st SSL_CTX; +typedef struct ssl_cipher_st SSL_CIPHER; typedef struct x509_store_ctx_st X509_STORE_CTX; namespace rtc { @@ -81,6 +82,11 @@ class OpenSSLStreamAdapter : public SSLStreamAdapter { virtual void Close(); virtual StreamState GetState() const; + // Return the RFC (5246, 3268, etc.) cipher name for an OpenSSL cipher. + static const char* GetRfcSslCipherName(const SSL_CIPHER* cipher); + + virtual bool GetSslCipher(std::string* cipher); + // Key Extractor interface virtual bool ExportKeyingMaterial(const std::string& label, const uint8* context, @@ -98,6 +104,7 @@ class OpenSSLStreamAdapter : public SSLStreamAdapter { static bool HaveDtls(); static bool HaveDtlsSrtp(); static bool HaveExporter(); + static std::string GetDefaultSslCipher(); protected: virtual void OnEvent(StreamInterface* stream, int events, int err); diff --git a/webrtc/base/sslstreamadapter.cc b/webrtc/base/sslstreamadapter.cc index 44df2eedd..513ae8caf 100644 --- a/webrtc/base/sslstreamadapter.cc +++ b/webrtc/base/sslstreamadapter.cc @@ -50,6 +50,9 @@ SSLStreamAdapter* SSLStreamAdapter::Create(StreamInterface* stream) { bool SSLStreamAdapter::HaveDtls() { return false; } bool SSLStreamAdapter::HaveDtlsSrtp() { return false; } bool SSLStreamAdapter::HaveExporter() { return false; } +std::string SSLStreamAdapter::GetDefaultSslCipher() { + return std::string(); +} #elif SSL_USE_OPENSSL bool SSLStreamAdapter::HaveDtls() { return OpenSSLStreamAdapter::HaveDtls(); @@ -60,6 +63,9 @@ bool SSLStreamAdapter::HaveDtlsSrtp() { bool SSLStreamAdapter::HaveExporter() { return OpenSSLStreamAdapter::HaveExporter(); } +std::string SSLStreamAdapter::GetDefaultSslCipher() { + return OpenSSLStreamAdapter::GetDefaultSslCipher(); +} #elif SSL_USE_NSS bool SSLStreamAdapter::HaveDtls() { return NSSStreamAdapter::HaveDtls(); @@ -70,6 +76,9 @@ bool SSLStreamAdapter::HaveDtlsSrtp() { bool SSLStreamAdapter::HaveExporter() { return NSSStreamAdapter::HaveExporter(); } +std::string SSLStreamAdapter::GetDefaultSslCipher() { + return NSSStreamAdapter::GetDefaultSslCipher(); +} #endif // !SSL_USE_SCHANNEL && !SSL_USE_OPENSSL && !SSL_USE_NSS /////////////////////////////////////////////////////////////////////////////// diff --git a/webrtc/base/sslstreamadapter.h b/webrtc/base/sslstreamadapter.h index ea966c54e..c940ecb68 100644 --- a/webrtc/base/sslstreamadapter.h +++ b/webrtc/base/sslstreamadapter.h @@ -119,6 +119,12 @@ class SSLStreamAdapter : public StreamAdapterInterface { // chain. The returned certificate is owned by the caller. virtual bool GetPeerCertificate(SSLCertificate** cert) const = 0; + // Retrieves the name of the cipher suite used for the connection + // (e.g. "TLS_RSA_WITH_AES_128_CBC_SHA"). + virtual bool GetSslCipher(std::string* cipher) { + return false; + } + // Key Exporter interface from RFC 5705 // Arguments are: // label -- the exporter label. @@ -155,6 +161,10 @@ class SSLStreamAdapter : public StreamAdapterInterface { static bool HaveDtlsSrtp(); static bool HaveExporter(); + // Returns the default Ssl cipher used between streams of this class. + // This is used by the unit tests. + static std::string GetDefaultSslCipher(); + private: // If true, the server certificate need not match the configured // server_name, and in fact missing certificate authority and other diff --git a/webrtc/base/sslstreamadapter_unittest.cc b/webrtc/base/sslstreamadapter_unittest.cc index b9d477d15..677be35f6 100644 --- a/webrtc/base/sslstreamadapter_unittest.cc +++ b/webrtc/base/sslstreamadapter_unittest.cc @@ -388,6 +388,13 @@ class SSLStreamAdapterTestBase : public testing::Test, return server_ssl_->GetPeerCertificate(cert); } + bool GetSslCipher(bool client, std::string *retval) { + if (client) + return client_ssl_->GetSslCipher(retval); + else + return server_ssl_->GetSslCipher(retval); + } + bool ExportKeyingMaterial(const char *label, const unsigned char *context, size_t context_len, @@ -939,3 +946,17 @@ TEST_F(SSLStreamAdapterTestDTLSFromPEMStrings, TestDTLSGetPeerCertificate) { rtc::SSLCertChain* server_peer_chain; ASSERT_FALSE(server_peer_cert->GetChain(&server_peer_chain)); } + +// Test getting the used DTLS ciphers. +TEST_F(SSLStreamAdapterTestDTLS, TestGetSslCipher) { + MAYBE_SKIP_TEST(HaveDtls); + TestHandshake(); + + std::string client_cipher; + ASSERT_TRUE(GetSslCipher(true, &client_cipher)); + std::string server_cipher; + ASSERT_TRUE(GetSslCipher(false, &server_cipher)); + + ASSERT_EQ(client_cipher, server_cipher); + ASSERT_EQ(rtc::SSLStreamAdapter::GetDefaultSslCipher(), client_cipher); +} diff --git a/webrtc/p2p/base/dtlstransportchannel.cc b/webrtc/p2p/base/dtlstransportchannel.cc index 9cceca350..956c52aec 100644 --- a/webrtc/p2p/base/dtlstransportchannel.cc +++ b/webrtc/p2p/base/dtlstransportchannel.cc @@ -186,6 +186,14 @@ bool DtlsTransportChannelWrapper::GetSslRole(rtc::SSLRole* role) const { return true; } +bool DtlsTransportChannelWrapper::GetSslCipher(std::string* cipher) { + if (dtls_state_ != STATE_OPEN) { + return false; + } + + return dtls_->GetSslCipher(cipher); +} + bool DtlsTransportChannelWrapper::SetRemoteFingerprint( const std::string& digest_alg, const uint8* digest, diff --git a/webrtc/p2p/base/dtlstransportchannel.h b/webrtc/p2p/base/dtlstransportchannel.h index 4c9c879b7..03a916b76 100644 --- a/webrtc/p2p/base/dtlstransportchannel.h +++ b/webrtc/p2p/base/dtlstransportchannel.h @@ -150,6 +150,9 @@ class DtlsTransportChannelWrapper : public TransportChannelImpl { virtual bool GetSslRole(rtc::SSLRole* role) const; virtual bool SetSslRole(rtc::SSLRole role); + // Find out which DTLS cipher was negotiated + virtual bool GetSslCipher(std::string* cipher); + // Once DTLS has been established, this method retrieves the certificate in // use by the remote peer, for use in external identity verification. virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const; diff --git a/webrtc/p2p/base/dtlstransportchannel_unittest.cc b/webrtc/p2p/base/dtlstransportchannel_unittest.cc index 52f8c1e72..f3086bb3a 100644 --- a/webrtc/p2p/base/dtlstransportchannel_unittest.cc +++ b/webrtc/p2p/base/dtlstransportchannel_unittest.cc @@ -213,6 +213,22 @@ class DtlsTestClient : public sigslot::has_slots<> { } } + void CheckSsl(const std::string& expected_cipher) { + for (std::vector::iterator it = + channels_.begin(); it != channels_.end(); ++it) { + std::string cipher; + + bool rv = (*it)->GetSslCipher(&cipher); + if (negotiated_dtls_ && !expected_cipher.empty()) { + ASSERT_TRUE(rv); + + ASSERT_EQ(cipher, expected_cipher); + } else { + ASSERT_FALSE(rv); + } + } + } + void SendPackets(size_t channel, size_t size, size_t count, bool srtp) { ASSERT(channel < channels_.size()); rtc::scoped_ptr packet(new char[size]); @@ -433,6 +449,8 @@ class DtlsTransportChannelTest : public testing::Test { client1_.CheckSrtp(""); client2_.CheckSrtp(""); } + client1_.CheckSsl(rtc::SSLStreamAdapter::GetDefaultSslCipher()); + client2_.CheckSsl(rtc::SSLStreamAdapter::GetDefaultSslCipher()); return true; } diff --git a/webrtc/p2p/base/fakesession.h b/webrtc/p2p/base/fakesession.h index 13eceefe1..6f43b65de 100644 --- a/webrtc/p2p/base/fakesession.h +++ b/webrtc/p2p/base/fakesession.h @@ -246,6 +246,10 @@ class FakeTransportChannel : public TransportChannelImpl, return false; } + virtual bool GetSslCipher(std::string* cipher) { + return false; + } + virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const { if (!identity_) return false; diff --git a/webrtc/p2p/base/p2ptransportchannel.h b/webrtc/p2p/base/p2ptransportchannel.h index f8756dc02..cd852d06a 100644 --- a/webrtc/p2p/base/p2ptransportchannel.h +++ b/webrtc/p2p/base/p2ptransportchannel.h @@ -109,11 +109,16 @@ class P2PTransportChannel : public TransportChannelImpl, return false; } - // Find out which DTLS-SRTP cipher was negotiated + // Find out which DTLS-SRTP cipher was negotiated. virtual bool GetSrtpCipher(std::string* cipher) { return false; } + // Find out which DTLS cipher was negotiated. + virtual bool GetSslCipher(std::string* cipher) { + return false; + } + // Returns false because the channel is not encrypted by default. virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const { return false; diff --git a/webrtc/p2p/base/rawtransportchannel.h b/webrtc/p2p/base/rawtransportchannel.h index a4d9ce01d..3455325c5 100644 --- a/webrtc/p2p/base/rawtransportchannel.h +++ b/webrtc/p2p/base/rawtransportchannel.h @@ -114,11 +114,16 @@ class RawTransportChannel : public TransportChannelImpl, return false; } - // Find out which DTLS-SRTP cipher was negotiated + // Find out which DTLS-SRTP cipher was negotiated. virtual bool GetSrtpCipher(std::string* cipher) { return false; } + // Find out which DTLS cipher was negotiated. + virtual bool GetSslCipher(std::string* cipher) { + return false; + } + // Returns false because the channel is not DTLS. virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const { return false; diff --git a/webrtc/p2p/base/transport.cc b/webrtc/p2p/base/transport.cc index b03e2d5f7..0569cc041 100644 --- a/webrtc/p2p/base/transport.cc +++ b/webrtc/p2p/base/transport.cc @@ -454,9 +454,12 @@ bool Transport::GetStats_w(TransportStats* stats) { for (ChannelMap::iterator iter = channels_.begin(); iter != channels_.end(); ++iter) { + ChannelMapEntry& entry = iter->second; TransportChannelStats substats; - substats.component = iter->second->component(); - if (!iter->second->GetStats(&substats.connection_infos)) { + substats.component = entry->component(); + entry->GetSrtpCipher(&substats.srtp_cipher); + entry->GetSslCipher(&substats.ssl_cipher); + if (!entry->GetStats(&substats.connection_infos)) { return false; } stats->channel_stats.push_back(substats); diff --git a/webrtc/p2p/base/transport.h b/webrtc/p2p/base/transport.h index abead7fac..32c6bb357 100644 --- a/webrtc/p2p/base/transport.h +++ b/webrtc/p2p/base/transport.h @@ -106,6 +106,8 @@ typedef std::vector ConnectionInfos; struct TransportChannelStats { int component; ConnectionInfos connection_infos; + std::string srtp_cipher; + std::string ssl_cipher; }; // Information about all the channels of a transport. diff --git a/webrtc/p2p/base/transportchannel.h b/webrtc/p2p/base/transportchannel.h index d26a18534..3d32b6326 100644 --- a/webrtc/p2p/base/transportchannel.h +++ b/webrtc/p2p/base/transportchannel.h @@ -100,9 +100,12 @@ class TransportChannel : public sigslot::has_slots<> { // Sets up the ciphers to use for DTLS-SRTP. virtual bool SetSrtpCiphers(const std::vector& ciphers) = 0; - // Finds out which DTLS-SRTP cipher was negotiated + // Finds out which DTLS-SRTP cipher was negotiated. virtual bool GetSrtpCipher(std::string* cipher) = 0; + // Finds out which DTLS cipher was negotiated. + virtual bool GetSslCipher(std::string* cipher) = 0; + // Gets a copy of the local SSL identity, owned by the caller. virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const = 0; diff --git a/webrtc/p2p/base/transportchannelproxy.cc b/webrtc/p2p/base/transportchannelproxy.cc index a8535fa46..a278d9646 100644 --- a/webrtc/p2p/base/transportchannelproxy.cc +++ b/webrtc/p2p/base/transportchannelproxy.cc @@ -186,6 +186,14 @@ bool TransportChannelProxy::GetSrtpCipher(std::string* cipher) { return impl_->GetSrtpCipher(cipher); } +bool TransportChannelProxy::GetSslCipher(std::string* cipher) { + ASSERT(rtc::Thread::Current() == worker_thread_); + if (!impl_) { + return false; + } + return impl_->GetSslCipher(cipher); +} + bool TransportChannelProxy::GetLocalIdentity( rtc::SSLIdentity** identity) const { ASSERT(rtc::Thread::Current() == worker_thread_); diff --git a/webrtc/p2p/base/transportchannelproxy.h b/webrtc/p2p/base/transportchannelproxy.h index 46803f736..19870028b 100644 --- a/webrtc/p2p/base/transportchannelproxy.h +++ b/webrtc/p2p/base/transportchannelproxy.h @@ -61,6 +61,7 @@ class TransportChannelProxy : public TransportChannel, virtual bool SetSslRole(rtc::SSLRole role); virtual bool SetSrtpCiphers(const std::vector& ciphers); virtual bool GetSrtpCipher(std::string* cipher); + virtual bool GetSslCipher(std::string* cipher); virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const; virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const; virtual bool ExportKeyingMaterial(const std::string& label,