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) {
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;
}
#include <glog/logging.h>
+#ifndef FOLLY_NO_CONFIG
+#include <folly/folly-config.h>
+#endif
+
namespace folly {
/**
*/
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
/**
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);