From 7dabbf602e29b5613568d438b6a7896041d60f6a Mon Sep 17 00:00:00 2001 From: Zonr Chang Date: Sun, 1 Jan 2017 16:24:34 -0800 Subject: [PATCH] Add FOLLY_OPENSSL_HAS_ALPN and FOLLY_OPENSSL_HAS_SNI. Summary: This expresses the intention of long predicate on OpenSSL version and OPENSSL_NO_TLSEXT more clearly. This also enables ALPN and SNI support when BoringSSL is in use. ALPN is an essential function to make HTTP/2 work when building Proxygen with BoringSSL. Closes https://github.com/facebook/folly/pull/534 Reviewed By: Orvid Differential Revision: D4375391 Pulled By: yfeldblum fbshipit-source-id: 009f311bceb0ee911d904d96a3e678a5f7241575 --- folly/io/async/AsyncSSLSocket.cpp | 12 ++++++------ folly/io/async/AsyncSSLSocket.h | 11 ++++++----- folly/io/async/SSLContext.cpp | 14 +++++++------- folly/io/async/SSLContext.h | 10 +++++----- folly/io/async/test/AsyncSSLSocketTest.cpp | 5 +++-- folly/portability/OpenSSL.h | 18 ++++++++++++++++++ 6 files changed, 45 insertions(+), 25 deletions(-) diff --git a/folly/io/async/AsyncSSLSocket.cpp b/folly/io/async/AsyncSSLSocket.cpp index a61e7617..36acfc2a 100644 --- a/folly/io/async/AsyncSSLSocket.cpp +++ b/folly/io/async/AsyncSSLSocket.cpp @@ -234,7 +234,7 @@ AsyncSSLSocket::AsyncSSLSocket(const shared_ptr& ctx, } } -#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_SNI /** * Create a client AsyncSSLSocket and allow tlsext_hostname * to be sent in Client Hello. @@ -258,7 +258,7 @@ AsyncSSLSocket::AsyncSSLSocket(const shared_ptr& ctx, AsyncSSLSocket(ctx, evb, fd, false, deferSecurityNegotiation) { tlsextHostname_ = serverName; } -#endif +#endif // FOLLY_OPENSSL_HAS_SNI AsyncSSLSocket::~AsyncSSLSocket() { VLOG(3) << "actual destruction of AsyncSSLSocket(this=" << this @@ -519,7 +519,7 @@ void AsyncSSLSocket::detachSSLContext() { } #endif -#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_SNI void AsyncSSLSocket::switchServerSSLContext( const std::shared_ptr& handshakeCtx) { CHECK(server_); @@ -560,7 +560,7 @@ void AsyncSSLSocket::setServerName(std::string serverName) noexcept { tlsextHostname_ = std::move(serverName); } -#endif +#endif // FOLLY_OPENSSL_HAS_SNI void AsyncSSLSocket::timeoutExpired() noexcept { if (state_ == StateEnum::ESTABLISHED && @@ -736,7 +736,7 @@ void AsyncSSLSocket::sslConn( SSL_SESSION_free(sslSession_); sslSession_ = nullptr; } -#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_SNI if (tlsextHostname_.size()) { SSL_set_tlsext_host_name(ssl_, tlsextHostname_.c_str()); } @@ -797,7 +797,7 @@ bool AsyncSSLSocket::getSelectedNextProtocolNoThrow( SSLContext::NextProtocolType* protoType) const { *protoName = nullptr; *protoLen = 0; -#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_ALPN SSL_get0_alpn_selected(ssl_, protoName, protoLen); if (*protoLen > 0) { if (protoType) { diff --git a/folly/io/async/AsyncSSLSocket.h b/folly/io/async/AsyncSSLSocket.h index 17bdd9c9..39f8fe9e 100644 --- a/folly/io/async/AsyncSSLSocket.h +++ b/folly/io/async/AsyncSSLSocket.h @@ -32,6 +32,7 @@ #include #include #include +#include #include namespace folly { @@ -202,7 +203,7 @@ class AsyncSSLSocket : public virtual AsyncSocket { } -#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_SNI /** * Create a client AsyncSSLSocket with tlsext_servername in * the Client Hello message. @@ -242,7 +243,7 @@ class AsyncSSLSocket : public virtual AsyncSocket { new AsyncSSLSocket(ctx, evb, serverName, deferSecurityNegotiation), Destructor()); } -#endif +#endif // FOLLY_OPENSSL_HAS_SNI /** * TODO: implement support for SSL renegotiation. @@ -518,7 +519,7 @@ class AsyncSSLSocket : public virtual AsyncSocket { void detachSSLContext(); #endif -#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_SNI /** * Switch the SSLContext to continue the SSL handshake. * It can only be used in server mode. @@ -541,7 +542,7 @@ class AsyncSSLSocket : public virtual AsyncSocket { * ClientHello message. */ void setServerName(std::string serverName) noexcept; -#endif +#endif // FOLLY_OPENSSL_HAS_SNI void timeoutExpired() noexcept; @@ -790,7 +791,7 @@ class AsyncSSLSocket : public virtual AsyncSocket { // When openssl is about to sendmsg() across the minEorRawBytesNo_, // it will pass MSG_EOR to sendmsg(). size_t minEorRawByteNo_{0}; -#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_SNI std::shared_ptr handshakeCtx_; std::string tlsextHostname_; #endif diff --git a/folly/io/async/SSLContext.cpp b/folly/io/async/SSLContext.cpp index ddb60e35..b69c6e1d 100644 --- a/folly/io/async/SSLContext.cpp +++ b/folly/io/async/SSLContext.cpp @@ -87,7 +87,7 @@ SSLContext::SSLContext(SSLVersion version) { SSL_CTX_set_options(ctx_, SSL_OP_NO_COMPRESSION); -#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_SNI SSL_CTX_set_tlsext_servername_callback(ctx_, baseServerNameOpenSSLCallback); SSL_CTX_set_tlsext_servername_arg(ctx_, this); #endif @@ -371,7 +371,7 @@ void SSLContext::passwordCollector(std::shared_ptr collector) SSL_CTX_set_default_passwd_cb_userdata(ctx_, this); } -#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_SNI void SSLContext::setServerNameCallback(const ServerNameCallback& cb) { serverNameCb_ = cb; @@ -466,9 +466,9 @@ void SSLContext::switchCiphersIfTLS11( SSL_set_cipher_list(ssl, providedCiphersString_.c_str()); } } -#endif +#endif // FOLLY_OPENSSL_HAS_SNI -#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_ALPN int SSLContext::alpnSelectCallback(SSL* /* ssl */, const unsigned char** out, unsigned char* outlen, @@ -494,7 +494,7 @@ int SSLContext::alpnSelectCallback(SSL* /* ssl */, } return SSL_TLSEXT_ERR_OK; } -#endif +#endif // FOLLY_OPENSSL_HAS_ALPN #ifdef OPENSSL_NPN_NEGOTIATED @@ -552,7 +552,7 @@ bool SSLContext::setRandomizedAdvertisedNextProtocols( ctx_, advertisedNextProtocolCallback, this); SSL_CTX_set_next_proto_select_cb(ctx_, selectNextProtocolCallback, this); } -#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_ALPN if ((uint8_t)protocolType & (uint8_t)NextProtocolType::ALPN) { SSL_CTX_set_alpn_select_cb(ctx_, alpnSelectCallback, this); // Client cannot really use randomized alpn @@ -576,7 +576,7 @@ void SSLContext::unsetNextProtocols() { deleteNextProtocolsStrings(); SSL_CTX_set_next_protos_advertised_cb(ctx_, nullptr, nullptr); SSL_CTX_set_next_proto_select_cb(ctx_, nullptr, nullptr); -#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_ALPN SSL_CTX_set_alpn_select_cb(ctx_, nullptr, nullptr); SSL_CTX_set_alpn_protos(ctx_, nullptr, 0); #endif diff --git a/folly/io/async/SSLContext.h b/folly/io/async/SSLContext.h index 2b927c77..8e62782f 100644 --- a/folly/io/async/SSLContext.h +++ b/folly/io/async/SSLContext.h @@ -283,7 +283,7 @@ class SSLContext { virtual std::shared_ptr passwordCollector() { return collector_; } -#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_SNI /** * Provide SNI support */ @@ -336,7 +336,7 @@ class SSLContext { */ typedef std::function ClientHelloCallback; virtual void addClientHelloCallback(const ClientHelloCallback& cb); -#endif +#endif // FOLLY_OPENSSL_HAS_SNI /** * Create an SSL object from this context. @@ -519,7 +519,7 @@ class SSLContext { bool checkPeerName_; std::string peerFixedName_; std::shared_ptr collector_; -#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_SNI ServerNameCallback serverNameCb_; std::vector clientHelloCbs_; #endif @@ -553,7 +553,7 @@ class SSLContext { SSL* ssl, unsigned char **out, unsigned char *outlen, const unsigned char *server, unsigned int server_len, void *args); -#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_ALPN static int alpnSelectCallback(SSL* ssl, const unsigned char** out, unsigned char* outlen, @@ -567,7 +567,7 @@ class SSLContext { static int passwordCallback(char* password, int size, int, void* data); -#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_SNI /** * The function that will be called directly from openssl * in order for the application to get the tlsext_hostname just after diff --git a/folly/io/async/test/AsyncSSLSocketTest.cpp b/folly/io/async/test/AsyncSSLSocketTest.cpp index 30109874..173564a9 100644 --- a/folly/io/async/test/AsyncSSLSocketTest.cpp +++ b/folly/io/async/test/AsyncSSLSocketTest.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -633,7 +634,7 @@ INSTANTIATE_TEST_CASE_P( SSLContext::NextProtocolType::ANY, SSLContext::NextProtocolType::ANY))); -#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_ALPN INSTANTIATE_TEST_CASE_P( AsyncSSLSocketTest, NextProtocolTLSExtTest, @@ -655,7 +656,7 @@ INSTANTIATE_TEST_CASE_P( ::testing::Values(NextProtocolTypePair(SSLContext::NextProtocolType::NPN, SSLContext::NextProtocolType::NPN))); -#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT) +#if FOLLY_OPENSSL_HAS_ALPN INSTANTIATE_TEST_CASE_P( AsyncSSLSocketTest, NextProtocolMismatchTest, diff --git a/folly/portability/OpenSSL.h b/folly/portability/OpenSSL.h index 97ed213b..47bd9a07 100644 --- a/folly/portability/OpenSSL.h +++ b/folly/portability/OpenSSL.h @@ -35,6 +35,24 @@ namespace ssl { #define FOLLY_OPENSSL_IS_110 (OPENSSL_VERSION_NUMBER >= 0x10100000L) #endif // !defined(OPENSSL_IS_BORINGSSL) +// BoringSSL and OpenSSL 1.0.2 later with TLS extension support ALPN. +#if defined(OPENSSL_IS_BORINGSSL) || \ + (OPENSSL_VERSION_NUMBER >= 0x1000200fL && \ + !defined(OPENSSL_NO_TLSEXT)) +#define FOLLY_OPENSSL_HAS_ALPN 1 +#else +#define FOLLY_OPENSSL_HAS_ALPN 0 +#endif + +// BoringSSL and OpenSSL 0.9.8f later with TLS extension support SNI. +#if defined(OPENSSL_IS_BORINGSSL) || \ + (OPENSSL_VERSION_NUMBER >= 0x00908070L && \ + !defined(OPENSSL_NO_TLSEXT)) +#define FOLLY_OPENSSL_HAS_SNI 1 +#else +#define FOLLY_OPENSSL_HAS_SNI 0 +#endif + // This class attempts to "unify" the OpenSSL libssl APIs between OpenSSL 1.0.2, // 1.1.0 and BoringSSL. The general idea is to provide wrapper methods for 1.0.2 // which already exist in BoringSSL and 1.1.0, but there are few APIs such as -- 2.34.1