Re-land: Add API to get negotiated SSL ciphers
This CL adds an API to the SSL stream adapters and transport channels to get the SSL cipher that was negotiated with the remote peer.
The previously approved CL https://webrtc-codereview.appspot.com/26009004/ was reverted in https://webrtc-codereview.appspot.com/40689004/ due to compilation issues while rolling into Chromium.
As the new method has landed in Chromium in https://crrev.com/bc321c76ace6e1d5a03440e554ccb207159802ec, this should be safe to land here now.
BUG=3976
R=pthatcher@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/37209004
Cr-Commit-Position: refs/heads/master@{#8343}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8343 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/base/opensslstreamadapter.cc b/webrtc/base/opensslstreamadapter.cc
index c18295f..0f82d28 100644
--- a/webrtc/base/opensslstreamadapter.cc
+++ b/webrtc/base/opensslstreamadapter.cc
@@ -20,6 +20,7 @@
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>
+#include <openssl/tls1.h>
#include <openssl/x509v3.h>
#include <vector>
@@ -56,6 +57,99 @@
};
#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 @@
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 @@
#endif
}
+std::string OpenSSLStreamAdapter::GetDefaultSslCipher() {
+ return kDefaultSslCipher;
+}
+
} // namespace rtc
#endif // HAVE_OPENSSL_SSL_H