From 297902cc56497f15901c322bf7f5dfc9b6cffd17 Mon Sep 17 00:00:00 2001 From: Shijin Kong Date: Thu, 29 Jan 2015 10:54:53 -0800 Subject: [PATCH] enable ssl false start with Next Protocol Negotiation (NPN) extension Summary: This speeds up TLS handshake and might be a factor of liger perf regression. The enabling is guarded by an #ifdef. The condition itself is defined in an openssl patch. Test Plan: folly unit tests pass. Tried on devices as well and from tcpdump data was sent before the new ticket was received, essentially speeded up the handshake process. Reviewed By: subodh@fb.com Subscribers: trunkagent, kmdent, seanc, benyluo, ssl-diffs@, ranjeeth, folly-diffs@ FB internal diff: D1806856 Tasks: 5284979 Signature: t1:1806856:1422494521:0a048ea9001da13b5d698b5a764d1e66dcbedc99 --- folly/io/async/SSLContext.cpp | 92 +++++++++++++++++++++++++++++++++++ folly/io/async/SSLContext.h | 32 ++++++++++++ 2 files changed, 124 insertions(+) diff --git a/folly/io/async/SSLContext.cpp b/folly/io/async/SSLContext.cpp index 1b0018fd..4f732609 100644 --- a/folly/io/async/SSLContext.cpp +++ b/folly/io/async/SSLContext.cpp @@ -419,6 +419,90 @@ int SSLContext::advertisedNextProtocolCallback(SSL* ssl, return SSL_TLSEXT_ERR_OK; } +#if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH) && \ + FOLLY_SSLCONTEXT_USE_TLS_FALSE_START +SSLContext::SSLFalseStartChecker::SSLFalseStartChecker() : + // The list was generated as follows: + // grep "_CK_" openssl-1.0.1e/ssl/s3_lib.c -A 4 | while read A && read B && read C && read D && read E && read F; do echo $A $B $C $D $E; done | \ + // grep "\(SSL_kDHr\|SSL_kDHd\|SSL_kEDH\|SSL_kECDHr\|SSL_kECDHe\|SSL_kEECDH\)" | grep -v SSL_aNULL | grep SSL_AES | awk -F, '{ print $1"," }' + ciphers_{ + TLS1_CK_DH_DSS_WITH_AES_128_SHA, + TLS1_CK_DH_RSA_WITH_AES_128_SHA, + TLS1_CK_DHE_DSS_WITH_AES_128_SHA, + TLS1_CK_DHE_RSA_WITH_AES_128_SHA, + TLS1_CK_DH_DSS_WITH_AES_256_SHA, + TLS1_CK_DH_RSA_WITH_AES_256_SHA, + TLS1_CK_DHE_DSS_WITH_AES_256_SHA, + TLS1_CK_DHE_RSA_WITH_AES_256_SHA, + TLS1_CK_DH_DSS_WITH_AES_128_SHA256, + TLS1_CK_DH_RSA_WITH_AES_128_SHA256, + TLS1_CK_DHE_DSS_WITH_AES_128_SHA256, + TLS1_CK_DHE_RSA_WITH_AES_128_SHA256, + TLS1_CK_DH_DSS_WITH_AES_256_SHA256, + TLS1_CK_DH_RSA_WITH_AES_256_SHA256, + TLS1_CK_DHE_DSS_WITH_AES_256_SHA256, + TLS1_CK_DHE_RSA_WITH_AES_256_SHA256, + TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_DH_RSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_DH_RSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_DHE_DSS_WITH_AES_128_GCM_SHA256, + TLS1_CK_DHE_DSS_WITH_AES_256_GCM_SHA384, + TLS1_CK_DH_DSS_WITH_AES_128_GCM_SHA256, + TLS1_CK_DH_DSS_WITH_AES_256_GCM_SHA384, + TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256, + TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384, + TLS1_CK_ECDH_ECDSA_WITH_AES_128_SHA256, + TLS1_CK_ECDH_ECDSA_WITH_AES_256_SHA384, + TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256, + TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384, + TLS1_CK_ECDH_RSA_WITH_AES_128_SHA256, + TLS1_CK_ECDH_RSA_WITH_AES_256_SHA384, + TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_ECDH_RSA_WITH_AES_128_GCM_SHA256, + } { + length_ = sizeof(ciphers_)/sizeof(ciphers_[0]); + width_ = sizeof(ciphers_[0]); + qsort(ciphers_, length_, width_, compare_ulong); +} + +bool SSLContext::SSLFalseStartChecker::canUseFalseStartWithCipher( + const SSL_CIPHER *cipher) { + unsigned long cid = cipher->id; + unsigned long *r = + (unsigned long*)bsearch(&cid, ciphers_, length_, width_, compare_ulong); + return r != nullptr; +} + +int +SSLContext::SSLFalseStartChecker::compare_ulong(const void *x, const void *y) { + if (*(unsigned long *)x < *(unsigned long *)y) { + return -1; + } + if (*(unsigned long *)x > *(unsigned long *)y) { + return 1; + } + return 0; +}; + +bool SSLContext::canUseFalseStartWithCipher(const SSL_CIPHER *cipher) { + return falseStartChecker_.canUseFalseStartWithCipher(cipher); +} +#endif + int SSLContext::selectNextProtocolCallback( SSL* ssl, unsigned char **out, unsigned char *outlen, const unsigned char *server, unsigned int server_len, void *data) { @@ -444,6 +528,14 @@ int SSLContext::selectNextProtocolCallback( if (retval != OPENSSL_NPN_NEGOTIATED) { VLOG(3) << "SSLContext::selectNextProcolCallback() " << "unable to pick a next protocol."; +#if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH) && \ + FOLLY_SSLCONTEXT_USE_TLS_FALSE_START + } else { + const SSL_CIPHER *cipher = ssl->s3->tmp.new_cipher; + if (cipher && ctx->canUseFalseStartWithCipher(cipher)) { + SSL_set_mode(ssl, SSL_MODE_HANDSHAKE_CUTTHROUGH); + } +#endif } return SSL_TLSEXT_ERR_OK; } diff --git a/folly/io/async/SSLContext.h b/folly/io/async/SSLContext.h index fb7eafac..1718bfca 100644 --- a/folly/io/async/SSLContext.h +++ b/folly/io/async/SSLContext.h @@ -31,6 +31,10 @@ #include +#ifndef FOLLY_NO_CONFIG +#include +#endif + namespace folly { /** @@ -326,6 +330,11 @@ class SSLContext { */ void unsetNextProtocols(); void deleteNextProtocolsStrings(); + +#if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH) && \ + FOLLY_SSLCONTEXT_USE_TLS_FALSE_START + bool canUseFalseStartWithCipher(const SSL_CIPHER *cipher); +#endif #endif // OPENSSL_NPN_NEGOTIATED /** @@ -432,6 +441,29 @@ class SSLContext { static int selectNextProtocolCallback( SSL* ssl, unsigned char **out, unsigned char *outlen, const unsigned char *server, unsigned int server_len, void *args); + +#if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH) && \ + FOLLY_SSLCONTEXT_USE_TLS_FALSE_START + // This class contains all allowed ciphers for SSL false start. Call its + // `canUseFalseStartWithCipher` to check for cipher qualification. + class SSLFalseStartChecker { + public: + SSLFalseStartChecker(); + + bool canUseFalseStartWithCipher(const SSL_CIPHER *cipher); + + private: + static int compare_ulong(const void *x, const void *y); + + // All ciphers that are allowed to use false start. + unsigned long ciphers_[47]; + unsigned int length_; + unsigned int width_; + }; + + SSLFalseStartChecker falseStartChecker_; +#endif + #endif // OPENSSL_NPN_NEGOTIATED static int passwordCallback(char* password, int size, int, void* data); -- 2.34.1