Commit 7dabbf60 authored by Zonr Chang's avatar Zonr Chang Committed by Facebook Github Bot

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
parent 827187dc
...@@ -234,7 +234,7 @@ AsyncSSLSocket::AsyncSSLSocket(const shared_ptr<SSLContext>& ctx, ...@@ -234,7 +234,7 @@ AsyncSSLSocket::AsyncSSLSocket(const shared_ptr<SSLContext>& ctx,
} }
} }
#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) #if FOLLY_OPENSSL_HAS_SNI
/** /**
* Create a client AsyncSSLSocket and allow tlsext_hostname * Create a client AsyncSSLSocket and allow tlsext_hostname
* to be sent in Client Hello. * to be sent in Client Hello.
...@@ -258,7 +258,7 @@ AsyncSSLSocket::AsyncSSLSocket(const shared_ptr<SSLContext>& ctx, ...@@ -258,7 +258,7 @@ AsyncSSLSocket::AsyncSSLSocket(const shared_ptr<SSLContext>& ctx,
AsyncSSLSocket(ctx, evb, fd, false, deferSecurityNegotiation) { AsyncSSLSocket(ctx, evb, fd, false, deferSecurityNegotiation) {
tlsextHostname_ = serverName; tlsextHostname_ = serverName;
} }
#endif #endif // FOLLY_OPENSSL_HAS_SNI
AsyncSSLSocket::~AsyncSSLSocket() { AsyncSSLSocket::~AsyncSSLSocket() {
VLOG(3) << "actual destruction of AsyncSSLSocket(this=" << this VLOG(3) << "actual destruction of AsyncSSLSocket(this=" << this
...@@ -519,7 +519,7 @@ void AsyncSSLSocket::detachSSLContext() { ...@@ -519,7 +519,7 @@ void AsyncSSLSocket::detachSSLContext() {
} }
#endif #endif
#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) #if FOLLY_OPENSSL_HAS_SNI
void AsyncSSLSocket::switchServerSSLContext( void AsyncSSLSocket::switchServerSSLContext(
const std::shared_ptr<SSLContext>& handshakeCtx) { const std::shared_ptr<SSLContext>& handshakeCtx) {
CHECK(server_); CHECK(server_);
...@@ -560,7 +560,7 @@ void AsyncSSLSocket::setServerName(std::string serverName) noexcept { ...@@ -560,7 +560,7 @@ void AsyncSSLSocket::setServerName(std::string serverName) noexcept {
tlsextHostname_ = std::move(serverName); tlsextHostname_ = std::move(serverName);
} }
#endif #endif // FOLLY_OPENSSL_HAS_SNI
void AsyncSSLSocket::timeoutExpired() noexcept { void AsyncSSLSocket::timeoutExpired() noexcept {
if (state_ == StateEnum::ESTABLISHED && if (state_ == StateEnum::ESTABLISHED &&
...@@ -736,7 +736,7 @@ void AsyncSSLSocket::sslConn( ...@@ -736,7 +736,7 @@ void AsyncSSLSocket::sslConn(
SSL_SESSION_free(sslSession_); SSL_SESSION_free(sslSession_);
sslSession_ = nullptr; sslSession_ = nullptr;
} }
#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) #if FOLLY_OPENSSL_HAS_SNI
if (tlsextHostname_.size()) { if (tlsextHostname_.size()) {
SSL_set_tlsext_host_name(ssl_, tlsextHostname_.c_str()); SSL_set_tlsext_host_name(ssl_, tlsextHostname_.c_str());
} }
...@@ -797,7 +797,7 @@ bool AsyncSSLSocket::getSelectedNextProtocolNoThrow( ...@@ -797,7 +797,7 @@ bool AsyncSSLSocket::getSelectedNextProtocolNoThrow(
SSLContext::NextProtocolType* protoType) const { SSLContext::NextProtocolType* protoType) const {
*protoName = nullptr; *protoName = nullptr;
*protoLen = 0; *protoLen = 0;
#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT) #if FOLLY_OPENSSL_HAS_ALPN
SSL_get0_alpn_selected(ssl_, protoName, protoLen); SSL_get0_alpn_selected(ssl_, protoName, protoLen);
if (*protoLen > 0) { if (*protoLen > 0) {
if (protoType) { if (protoType) {
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <folly/Bits.h> #include <folly/Bits.h>
#include <folly/io/IOBuf.h> #include <folly/io/IOBuf.h>
#include <folly/io/Cursor.h> #include <folly/io/Cursor.h>
#include <folly/portability/OpenSSL.h>
#include <folly/portability/Sockets.h> #include <folly/portability/Sockets.h>
namespace folly { namespace folly {
...@@ -202,7 +203,7 @@ class AsyncSSLSocket : public virtual AsyncSocket { ...@@ -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 * Create a client AsyncSSLSocket with tlsext_servername in
* the Client Hello message. * the Client Hello message.
...@@ -242,7 +243,7 @@ class AsyncSSLSocket : public virtual AsyncSocket { ...@@ -242,7 +243,7 @@ class AsyncSSLSocket : public virtual AsyncSocket {
new AsyncSSLSocket(ctx, evb, serverName, deferSecurityNegotiation), new AsyncSSLSocket(ctx, evb, serverName, deferSecurityNegotiation),
Destructor()); Destructor());
} }
#endif #endif // FOLLY_OPENSSL_HAS_SNI
/** /**
* TODO: implement support for SSL renegotiation. * TODO: implement support for SSL renegotiation.
...@@ -518,7 +519,7 @@ class AsyncSSLSocket : public virtual AsyncSocket { ...@@ -518,7 +519,7 @@ class AsyncSSLSocket : public virtual AsyncSocket {
void detachSSLContext(); void detachSSLContext();
#endif #endif
#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) #if FOLLY_OPENSSL_HAS_SNI
/** /**
* Switch the SSLContext to continue the SSL handshake. * Switch the SSLContext to continue the SSL handshake.
* It can only be used in server mode. * It can only be used in server mode.
...@@ -541,7 +542,7 @@ class AsyncSSLSocket : public virtual AsyncSocket { ...@@ -541,7 +542,7 @@ class AsyncSSLSocket : public virtual AsyncSocket {
* ClientHello message. * ClientHello message.
*/ */
void setServerName(std::string serverName) noexcept; void setServerName(std::string serverName) noexcept;
#endif #endif // FOLLY_OPENSSL_HAS_SNI
void timeoutExpired() noexcept; void timeoutExpired() noexcept;
...@@ -790,7 +791,7 @@ class AsyncSSLSocket : public virtual AsyncSocket { ...@@ -790,7 +791,7 @@ class AsyncSSLSocket : public virtual AsyncSocket {
// When openssl is about to sendmsg() across the minEorRawBytesNo_, // When openssl is about to sendmsg() across the minEorRawBytesNo_,
// it will pass MSG_EOR to sendmsg(). // it will pass MSG_EOR to sendmsg().
size_t minEorRawByteNo_{0}; size_t minEorRawByteNo_{0};
#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) #if FOLLY_OPENSSL_HAS_SNI
std::shared_ptr<folly::SSLContext> handshakeCtx_; std::shared_ptr<folly::SSLContext> handshakeCtx_;
std::string tlsextHostname_; std::string tlsextHostname_;
#endif #endif
......
...@@ -87,7 +87,7 @@ SSLContext::SSLContext(SSLVersion version) { ...@@ -87,7 +87,7 @@ SSLContext::SSLContext(SSLVersion version) {
SSL_CTX_set_options(ctx_, SSL_OP_NO_COMPRESSION); 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_callback(ctx_, baseServerNameOpenSSLCallback);
SSL_CTX_set_tlsext_servername_arg(ctx_, this); SSL_CTX_set_tlsext_servername_arg(ctx_, this);
#endif #endif
...@@ -371,7 +371,7 @@ void SSLContext::passwordCollector(std::shared_ptr<PasswordCollector> collector) ...@@ -371,7 +371,7 @@ void SSLContext::passwordCollector(std::shared_ptr<PasswordCollector> collector)
SSL_CTX_set_default_passwd_cb_userdata(ctx_, this); 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) { void SSLContext::setServerNameCallback(const ServerNameCallback& cb) {
serverNameCb_ = cb; serverNameCb_ = cb;
...@@ -466,9 +466,9 @@ void SSLContext::switchCiphersIfTLS11( ...@@ -466,9 +466,9 @@ void SSLContext::switchCiphersIfTLS11(
SSL_set_cipher_list(ssl, providedCiphersString_.c_str()); 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 */, int SSLContext::alpnSelectCallback(SSL* /* ssl */,
const unsigned char** out, const unsigned char** out,
unsigned char* outlen, unsigned char* outlen,
...@@ -494,7 +494,7 @@ int SSLContext::alpnSelectCallback(SSL* /* ssl */, ...@@ -494,7 +494,7 @@ int SSLContext::alpnSelectCallback(SSL* /* ssl */,
} }
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_OK;
} }
#endif #endif // FOLLY_OPENSSL_HAS_ALPN
#ifdef OPENSSL_NPN_NEGOTIATED #ifdef OPENSSL_NPN_NEGOTIATED
...@@ -552,7 +552,7 @@ bool SSLContext::setRandomizedAdvertisedNextProtocols( ...@@ -552,7 +552,7 @@ bool SSLContext::setRandomizedAdvertisedNextProtocols(
ctx_, advertisedNextProtocolCallback, this); ctx_, advertisedNextProtocolCallback, this);
SSL_CTX_set_next_proto_select_cb(ctx_, selectNextProtocolCallback, 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) { if ((uint8_t)protocolType & (uint8_t)NextProtocolType::ALPN) {
SSL_CTX_set_alpn_select_cb(ctx_, alpnSelectCallback, this); SSL_CTX_set_alpn_select_cb(ctx_, alpnSelectCallback, this);
// Client cannot really use randomized alpn // Client cannot really use randomized alpn
...@@ -576,7 +576,7 @@ void SSLContext::unsetNextProtocols() { ...@@ -576,7 +576,7 @@ void SSLContext::unsetNextProtocols() {
deleteNextProtocolsStrings(); deleteNextProtocolsStrings();
SSL_CTX_set_next_protos_advertised_cb(ctx_, nullptr, nullptr); SSL_CTX_set_next_protos_advertised_cb(ctx_, nullptr, nullptr);
SSL_CTX_set_next_proto_select_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_select_cb(ctx_, nullptr, nullptr);
SSL_CTX_set_alpn_protos(ctx_, nullptr, 0); SSL_CTX_set_alpn_protos(ctx_, nullptr, 0);
#endif #endif
......
...@@ -283,7 +283,7 @@ class SSLContext { ...@@ -283,7 +283,7 @@ class SSLContext {
virtual std::shared_ptr<PasswordCollector> passwordCollector() { virtual std::shared_ptr<PasswordCollector> passwordCollector() {
return collector_; return collector_;
} }
#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) #if FOLLY_OPENSSL_HAS_SNI
/** /**
* Provide SNI support * Provide SNI support
*/ */
...@@ -336,7 +336,7 @@ class SSLContext { ...@@ -336,7 +336,7 @@ class SSLContext {
*/ */
typedef std::function<void(SSL* ssl)> ClientHelloCallback; typedef std::function<void(SSL* ssl)> ClientHelloCallback;
virtual void addClientHelloCallback(const ClientHelloCallback& cb); virtual void addClientHelloCallback(const ClientHelloCallback& cb);
#endif #endif // FOLLY_OPENSSL_HAS_SNI
/** /**
* Create an SSL object from this context. * Create an SSL object from this context.
...@@ -519,7 +519,7 @@ class SSLContext { ...@@ -519,7 +519,7 @@ class SSLContext {
bool checkPeerName_; bool checkPeerName_;
std::string peerFixedName_; std::string peerFixedName_;
std::shared_ptr<PasswordCollector> collector_; std::shared_ptr<PasswordCollector> collector_;
#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) #if FOLLY_OPENSSL_HAS_SNI
ServerNameCallback serverNameCb_; ServerNameCallback serverNameCb_;
std::vector<ClientHelloCallback> clientHelloCbs_; std::vector<ClientHelloCallback> clientHelloCbs_;
#endif #endif
...@@ -553,7 +553,7 @@ class SSLContext { ...@@ -553,7 +553,7 @@ class SSLContext {
SSL* ssl, unsigned char **out, unsigned char *outlen, SSL* ssl, unsigned char **out, unsigned char *outlen,
const unsigned char *server, unsigned int server_len, void *args); 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, static int alpnSelectCallback(SSL* ssl,
const unsigned char** out, const unsigned char** out,
unsigned char* outlen, unsigned char* outlen,
...@@ -567,7 +567,7 @@ class SSLContext { ...@@ -567,7 +567,7 @@ class SSLContext {
static int passwordCallback(char* password, int size, int, void* data); 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 * The function that will be called directly from openssl
* in order for the application to get the tlsext_hostname just after * in order for the application to get the tlsext_hostname just after
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <folly/io/async/EventBase.h> #include <folly/io/async/EventBase.h>
#include <folly/portability/GMock.h> #include <folly/portability/GMock.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#include <folly/portability/OpenSSL.h>
#include <folly/portability/Sockets.h> #include <folly/portability/Sockets.h>
#include <folly/portability/Unistd.h> #include <folly/portability/Unistd.h>
...@@ -633,7 +634,7 @@ INSTANTIATE_TEST_CASE_P( ...@@ -633,7 +634,7 @@ INSTANTIATE_TEST_CASE_P(
SSLContext::NextProtocolType::ANY, SSLContext::NextProtocolType::ANY,
SSLContext::NextProtocolType::ANY))); SSLContext::NextProtocolType::ANY)));
#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT) #if FOLLY_OPENSSL_HAS_ALPN
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
AsyncSSLSocketTest, AsyncSSLSocketTest,
NextProtocolTLSExtTest, NextProtocolTLSExtTest,
...@@ -655,7 +656,7 @@ INSTANTIATE_TEST_CASE_P( ...@@ -655,7 +656,7 @@ INSTANTIATE_TEST_CASE_P(
::testing::Values(NextProtocolTypePair(SSLContext::NextProtocolType::NPN, ::testing::Values(NextProtocolTypePair(SSLContext::NextProtocolType::NPN,
SSLContext::NextProtocolType::NPN))); SSLContext::NextProtocolType::NPN)));
#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT) #if FOLLY_OPENSSL_HAS_ALPN
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
AsyncSSLSocketTest, AsyncSSLSocketTest,
NextProtocolMismatchTest, NextProtocolMismatchTest,
......
...@@ -35,6 +35,24 @@ namespace ssl { ...@@ -35,6 +35,24 @@ namespace ssl {
#define FOLLY_OPENSSL_IS_110 (OPENSSL_VERSION_NUMBER >= 0x10100000L) #define FOLLY_OPENSSL_IS_110 (OPENSSL_VERSION_NUMBER >= 0x10100000L)
#endif // !defined(OPENSSL_IS_BORINGSSL) #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, // 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 // 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 // which already exist in BoringSSL and 1.1.0, but there are few APIs such as
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment