From c85159a3ad124f41ab46e567a595c02748d0da46 Mon Sep 17 00:00:00 2001 From: Kyle Nekritz Date: Thu, 3 Mar 2016 10:33:19 -0800 Subject: [PATCH] Use false start with ALPN. Summary: All the work we do in SSLContext to check the cipher and NPN usage is actually completely unnecessary since OpenSSL internally checks the cipher and use of ALPN/NPN after you set the SSL_MODE option (see `ssl3_can_cutthrough()` in ssl_lib.c). This just sets the option on the SSLContext instead. Reviewed By: siyengar Differential Revision: D3002063 fb-gh-sync-id: 4514faf9ed2eb42a6e41d9e682b2c8aa52c46691 shipit-source-id: 4514faf9ed2eb42a6e41d9e682b2c8aa52c46691 --- folly/io/async/SSLContext.cpp | 74 +++-------------------------------- folly/io/async/SSLContext.h | 36 +++++------------ 2 files changed, 15 insertions(+), 95 deletions(-) diff --git a/folly/io/async/SSLContext.cpp b/folly/io/async/SSLContext.cpp index 6e51db56..637a0e1f 100644 --- a/folly/io/async/SSLContext.cpp +++ b/folly/io/async/SSLContext.cpp @@ -510,66 +510,6 @@ 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() : - ciphers_{ - TLS1_CK_DHE_DSS_WITH_AES_128_SHA, - TLS1_CK_DHE_RSA_WITH_AES_128_SHA, - TLS1_CK_DHE_DSS_WITH_AES_256_SHA, - TLS1_CK_DHE_RSA_WITH_AES_256_SHA, - TLS1_CK_DHE_DSS_WITH_AES_128_SHA256, - TLS1_CK_DHE_RSA_WITH_AES_128_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_DHE_DSS_WITH_AES_128_GCM_SHA256, - TLS1_CK_DHE_DSS_WITH_AES_256_GCM_SHA384, - TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - TLS1_CK_ECDHE_ECDSA_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_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - } { - 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, @@ -606,14 +546,6 @@ int SSLContext::selectNextProtocolCallback(SSL* ssl, 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; } @@ -766,6 +698,12 @@ void SSLContext::setSSLLockTypes(std::map inLockTypes) { lockTypes() = inLockTypes; } +#if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH) +void SSLContext::enableFalseStart() { + SSL_CTX_set_mode(ctx_, SSL_MODE_HANDSHAKE_CUTTHROUGH); +} +#endif + void SSLContext::markInitialized() { std::lock_guard g(initMutex()); initialized_ = true; diff --git a/folly/io/async/SSLContext.h b/folly/io/async/SSLContext.h index 09592b46..03d41758 100644 --- a/folly/io/async/SSLContext.h +++ b/folly/io/async/SSLContext.h @@ -376,11 +376,6 @@ 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 /** @@ -437,6 +432,15 @@ class SSLContext { bool checkPeerName() { return checkPeerName_; } std::string peerFixedName() { return peerFixedName_; } +#if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH) + /** + * Enable TLS false start, saving a roundtrip for full handshakes. Will only + * be used if the server uses NPN or ALPN, and a strong forward-secure cipher + * is negotiated. + */ + void enableFalseStart(); +#endif + /** * Helper to match a hostname versus a pattern. */ @@ -512,28 +516,6 @@ class SSLContext { #endif size_t pickNextProtocols(); -#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