From: Zonr Chang <zonr.net@gmail.com>
Date: Mon, 2 Jan 2017 00:24:34 +0000 (-0800)
Subject: Add FOLLY_OPENSSL_HAS_ALPN and FOLLY_OPENSSL_HAS_SNI.
X-Git-Tag: v2017.03.06.00~145
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=7dabbf602e29b5613568d438b6a7896041d60f6a;p=folly.git

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
---

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<SSLContext>& 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<SSLContext>& 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<SSLContext>& 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 <folly/Bits.h>
 #include <folly/io/IOBuf.h>
 #include <folly/io/Cursor.h>
+#include <folly/portability/OpenSSL.h>
 #include <folly/portability/Sockets.h>
 
 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<folly::SSLContext> 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<PasswordCollector> 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> 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<void(SSL* ssl)> 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<PasswordCollector> collector_;
-#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT)
+#if FOLLY_OPENSSL_HAS_SNI
   ServerNameCallback serverNameCb_;
   std::vector<ClientHelloCallback> 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 <folly/io/async/EventBase.h>
 #include <folly/portability/GMock.h>
 #include <folly/portability/GTest.h>
+#include <folly/portability/OpenSSL.h>
 #include <folly/portability/Sockets.h>
 #include <folly/portability/Unistd.h>
 
@@ -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