Let SSLContext::setCipherList accept generic container type.
authorXiangyu Bu <xbu@fb.com>
Fri, 18 Aug 2017 23:35:27 +0000 (16:35 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Fri, 18 Aug 2017 23:49:54 +0000 (16:49 -0700)
Summary:
Make SSLContext::setCipherList() and SSLContext::setSignatureAlgorithms()
accept std::array besides std::vector so that cipher lists in SSLOptions
can be initialized POD.

Reviewed By: yfeldblum

Differential Revision: D5578758

fbshipit-source-id: 7e5c2e9a75600e93c89e7b13a9042434a4189384

folly/io/async/SSLContext.cpp
folly/io/async/SSLContext.h
folly/io/async/SSLOptions.cpp
folly/io/async/SSLOptions.h
folly/io/async/test/SSLContextTest.cpp
folly/io/async/test/SSLOptionsTest.cpp

index 45936d0ce3a78b1bf99e2e722d3e042781a19c75..58f6defad2f8d58f084228897e11e9e58334ee67 100644 (file)
@@ -87,30 +87,6 @@ void SSLContext::ciphers(const std::string& ciphers) {
   setCiphersOrThrow(ciphers);
 }
 
-void SSLContext::setCipherList(const std::vector<std::string>& ciphers) {
-  if (ciphers.size() == 0) {
-    return;
-  }
-  std::string opensslCipherList;
-  join(":", ciphers, opensslCipherList);
-  setCiphersOrThrow(opensslCipherList);
-}
-
-void SSLContext::setSignatureAlgorithms(
-    const std::vector<std::string>& sigalgs) {
-  if (sigalgs.size() == 0) {
-    return;
-  }
-#if OPENSSL_VERSION_NUMBER >= 0x1000200fL
-  std::string opensslSigAlgsList;
-  join(":", sigalgs, opensslSigAlgsList);
-  int rc = SSL_CTX_set1_sigalgs_list(ctx_, opensslSigAlgsList.c_str());
-  if (rc == 0) {
-    throw std::runtime_error("SSL_CTX_set1_sigalgs_list " + getErrors());
-  }
-#endif
-}
-
 void SSLContext::setClientECCurvesList(
     const std::vector<std::string>& ecCurves) {
   if (ecCurves.size() == 0) {
index d556806fa552d001081d847eec136d5d3506e296..4e5077144ef95c6675100fade52f9bc52f79ce38 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <folly/Portability.h>
 #include <folly/Range.h>
+#include <folly/String.h>
 #include <folly/io/async/ssl/OpenSSLUtils.h>
 #include <folly/portability/OpenSSL.h>
 #include <folly/ssl/OpenSSLLockTypes.h>
@@ -130,13 +131,6 @@ class SSLContext {
    */
   virtual void ciphers(const std::string& ciphers);
 
-  /**
-   * Set default ciphers to be used in SSL handshake process.
-   *
-   * @param ciphers A list of ciphers to use for TLS.
-   */
-  virtual void setCipherList(const std::vector<std::string>& ciphers);
-
   /**
    * Low-level method that attempts to set the provided ciphers on the
    * SSL_CTX object, and throws if something goes wrong.
@@ -144,12 +138,57 @@ class SSLContext {
   virtual void setCiphersOrThrow(const std::string& ciphers);
 
   /**
-   * Sets the signature algorithms to be used during SSL negotiation
-   * for TLS1.2+
-   *
-   * @param sigalgs A list of signature algorithms, eg. RSA+SHA512
+   * Set default ciphers to be used in SSL handshake process.
    */
-  void setSignatureAlgorithms(const std::vector<std::string>& sigalgs);
+
+  template <typename Iterator>
+  void setCipherList(Iterator ibegin, Iterator iend) {
+    if (ibegin != iend) {
+      std::string opensslCipherList;
+      folly::join(":", ibegin, iend, opensslCipherList);
+      setCiphersOrThrow(opensslCipherList);
+    }
+  }
+
+  template <typename Container>
+  void setCipherList(const Container& cipherList) {
+    using namespace std;
+    setCipherList(begin(cipherList), end(cipherList));
+  }
+
+  template <typename Value>
+  void setCipherList(const std::initializer_list<Value>& cipherList) {
+    setCipherList(cipherList.begin(), cipherList.end());
+  }
+
+  /**
+   * Sets the signature algorithms to be used during SSL negotiation
+   * for TLS1.2+.
+   */
+
+  template <typename Iterator>
+  void setSignatureAlgorithms(Iterator ibegin, Iterator iend) {
+    if (ibegin != iend) {
+#if OPENSSL_VERSION_NUMBER >= 0x1000200fL
+      std::string opensslSigAlgsList;
+      join(":", ibegin, iend, opensslSigAlgsList);
+      if (!SSL_CTX_set1_sigalgs_list(ctx_, opensslSigAlgsList.c_str())) {
+        throw std::runtime_error("SSL_CTX_set1_sigalgs_list " + getErrors());
+      }
+#endif
+    }
+  }
+
+  template <typename Container>
+  void setSignatureAlgorithms(const Container& sigalgs) {
+    using namespace std;
+    setSignatureAlgorithms(begin(sigalgs), end(sigalgs));
+  }
+
+  template <typename Value>
+  void setSignatureAlgorithms(const std::initializer_list<Value>& sigalgs) {
+    setSignatureAlgorithms(sigalgs.begin(), sigalgs.end());
+  }
 
   /**
    * Sets the list of EC curves supported by the client.
index bada56c345a589f94150c996c982599ac5b36bb4..32f3ccb68f95e94031b3a6b5f411939470863626 100644 (file)
  * limitations under the License.
  */
 
-#include "SSLOptions.h"
+#include <folly/io/async/SSLOptions.h>
+#include <folly/Format.h>
+#include <folly/Logging.h>
 
 namespace folly {
 namespace ssl {
 
-const std::vector<std::string>& SSLCommonOptions::getCipherList() {
-  static const std::vector<std::string> kCommonCipherList = {
-      "ECDHE-ECDSA-AES128-GCM-SHA256",
-      "ECDHE-RSA-AES128-GCM-SHA256",
-      "ECDHE-ECDSA-AES256-GCM-SHA384",
-      "ECDHE-RSA-AES256-GCM-SHA384",
-      "ECDHE-ECDSA-AES256-SHA",
-      "ECDHE-RSA-AES256-SHA",
-      "ECDHE-ECDSA-AES128-SHA",
-      "ECDHE-RSA-AES128-SHA",
-      "ECDHE-RSA-AES256-SHA384",
-      "AES128-GCM-SHA256",
-      "AES256-SHA",
-      "AES128-SHA",
-  };
-  return kCommonCipherList;
+namespace ssl_options_detail {
+void logDfatal(std::exception const& e) {
+  LOG(DFATAL) << exceptionStr(e);
 }
-
-const std::vector<std::string>& SSLCommonOptions::getSignatureAlgorithms() {
-  static const std::vector<std::string> kCommonSigAlgs = {
-      "RSA+SHA512",
-      "ECDSA+SHA512",
-      "RSA+SHA384",
-      "ECDSA+SHA384",
-      "RSA+SHA256",
-      "ECDSA+SHA256",
-      "RSA+SHA1",
-      "ECDSA+SHA1",
-  };
-  return kCommonSigAlgs;
 }
 
+constexpr std::array<const char*, 12> SSLCommonOptions::kCipherList;
+constexpr std::array<const char*, 8> SSLCommonOptions::kSignatureAlgorithms;
+
 void SSLCommonOptions::setClientOptions(SSLContext& ctx) {
 #ifdef SSL_MODE_HANDSHAKE_CUTTHROUGH
   ctx.enableFalseStart();
index 963cad27af76d5d99780390754b27e7eb34516a5..94dc8ed188f4968f0d35e84546d96940a72fb434 100644 (file)
 
 #pragma once
 
-#include <folly/Format.h>
+#include <folly/Array.h>
 #include <folly/io/async/SSLContext.h>
 
-#include <glog/logging.h>
-
 namespace folly {
 namespace ssl {
 
+namespace ssl_options_detail {
+void logDfatal(std::exception const&);
+}
+
 struct SSLCommonOptions {
   /**
-   * Return the cipher list recommended for this options configuration.
+   * The cipher list recommended for this options configuration.
    */
-  static const std::vector<std::string>& getCipherList();
+  static constexpr auto kCipherList = folly::make_array(
+      "ECDHE-ECDSA-AES128-GCM-SHA256",
+      "ECDHE-RSA-AES128-GCM-SHA256",
+      "ECDHE-ECDSA-AES256-GCM-SHA384",
+      "ECDHE-RSA-AES256-GCM-SHA384",
+      "ECDHE-ECDSA-AES256-SHA",
+      "ECDHE-RSA-AES256-SHA",
+      "ECDHE-ECDSA-AES128-SHA",
+      "ECDHE-RSA-AES128-SHA",
+      "ECDHE-RSA-AES256-SHA384",
+      "AES128-GCM-SHA256",
+      "AES256-SHA",
+      "AES128-SHA");
 
   /**
-   * Return the list of signature algorithms recommended for this options
+   * The list of signature algorithms recommended for this options
    * configuration.
    */
-  static const std::vector<std::string>& getSignatureAlgorithms();
+  static constexpr auto kSignatureAlgorithms = folly::make_array(
+      "RSA+SHA512",
+      "ECDSA+SHA512",
+      "RSA+SHA384",
+      "ECDSA+SHA384",
+      "RSA+SHA256",
+      "ECDSA+SHA256",
+      "RSA+SHA1",
+      "ECDSA+SHA1");
 
   /**
    * Set common parameters on a client SSL context, for example,
@@ -44,21 +66,31 @@ struct SSLCommonOptions {
   static void setClientOptions(SSLContext& ctx);
 };
 
+/**
+ * Set the cipher suite of ctx to that in TSSLOptions, and print any runtime
+ * error it catches.
+ * @param ctx The SSLContext to apply the desired SSL options to.
+ */
 template <typename TSSLOptions>
 void setCipherSuites(SSLContext& ctx) {
   try {
-    ctx.setCipherList(TSSLOptions::getCipherList());
+    ctx.setCipherList(TSSLOptions::kCipherList);
   } catch (std::runtime_error const& e) {
-    LOG(DFATAL) << exceptionStr(e);
+    ssl_options_detail::logDfatal(e);
   }
 }
 
+/**
+ * Set the signature algorithm list of ctx to that in TSSLOptions, and print
+ * any runtime errors it catche.
+ * @param ctx The SSLContext to apply the desired SSL options to.
+ */
 template <typename TSSLOptions>
 void setSignatureAlgorithms(SSLContext& ctx) {
   try {
-    ctx.setSignatureAlgorithms(TSSLOptions::getSignatureAlgorithms());
+    ctx.setSignatureAlgorithms(TSSLOptions::kSignatureAlgorithms);
   } catch (std::runtime_error const& e) {
-    LOG(DFATAL) << exceptionStr(e);
+    ssl_options_detail::logDfatal(e);
   }
 }
 
index 98f6467c2007e61fb88bfad4e87ab6b82c5616b8..7ecf0553b79187ae449f60f80a446707c33bb1a3 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <folly/io/async/SSLContext.h>
 #include <folly/portability/GTest.h>
+#include <folly/ssl/OpenSSLPtrTypes.h>
 
 using namespace std;
 using namespace testing;
@@ -30,12 +31,11 @@ class SSLContextTest : public testing::Test {
 
 void SSLContextTest::verifySSLCipherList(const vector<string>& ciphers) {
   int i = 0;
-  SSL* ssl = ctx.createSSL();
+  ssl::SSLUniquePtr ssl(ctx.createSSL());
   for (auto& cipher : ciphers) {
-    ASSERT_STREQ(cipher.c_str(), SSL_get_cipher_list(ssl, i++));
+    ASSERT_STREQ(cipher.c_str(), SSL_get_cipher_list(ssl.get(), i++));
   }
-  ASSERT_EQ(nullptr, SSL_get_cipher_list(ssl, i));
-  SSL_free(ssl);
+  ASSERT_EQ(nullptr, SSL_get_cipher_list(ssl.get(), i));
 }
 
 TEST_F(SSLContextTest, TestSetCipherString) {
index f0c8f97419fbcf9b07d27f8b378af90f093495dc..471f93135cd8846ae836c81dcf6c45be1ce97a31 100644 (file)
@@ -26,18 +26,15 @@ namespace folly {
 
 class SSLOptionsTest : public testing::Test {};
 
-void verifySSLCipherList(SSLContext& ctx, const vector<string>& ciphers) {
+TEST_F(SSLOptionsTest, TestSetCommonCipherList) {
+  SSLContext ctx;
+  ssl::setCipherSuites<ssl::SSLCommonOptions>(ctx);
+
   int i = 0;
   ssl::SSLUniquePtr ssl(ctx.createSSL());
-  for (auto& cipher : ciphers) {
-    ASSERT_STREQ(cipher.c_str(), SSL_get_cipher_list(ssl.get(), i++));
+  for (auto& cipher : ssl::SSLCommonOptions::kCipherList) {
+    ASSERT_STREQ(cipher, SSL_get_cipher_list(ssl.get(), i++));
   }
   ASSERT_EQ(nullptr, SSL_get_cipher_list(ssl.get(), i));
 }
-
-TEST_F(SSLOptionsTest, TestSetCommonCipherList) {
-  SSLContext ctx;
-  ssl::setCipherSuites<ssl::SSLCommonOptions>(ctx);
-  verifySSLCipherList(ctx, ssl::SSLCommonOptions::getCipherList());
-}
 }