Commit 0e0710e3 authored by Xiangyu Bu's avatar Xiangyu Bu Committed by Facebook Github Bot

Let SSLContext::setCipherList accept generic container type.

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
parent 389f2c45
...@@ -87,30 +87,6 @@ void SSLContext::ciphers(const std::string& ciphers) { ...@@ -87,30 +87,6 @@ void SSLContext::ciphers(const std::string& ciphers) {
setCiphersOrThrow(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( void SSLContext::setClientECCurvesList(
const std::vector<std::string>& ecCurves) { const std::vector<std::string>& ecCurves) {
if (ecCurves.size() == 0) { if (ecCurves.size() == 0) {
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/Range.h> #include <folly/Range.h>
#include <folly/String.h>
#include <folly/io/async/ssl/OpenSSLUtils.h> #include <folly/io/async/ssl/OpenSSLUtils.h>
#include <folly/portability/OpenSSL.h> #include <folly/portability/OpenSSL.h>
#include <folly/ssl/OpenSSLLockTypes.h> #include <folly/ssl/OpenSSLLockTypes.h>
...@@ -130,26 +131,64 @@ class SSLContext { ...@@ -130,26 +131,64 @@ class SSLContext {
*/ */
virtual void ciphers(const std::string& ciphers); 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 * Low-level method that attempts to set the provided ciphers on the
* SSL_CTX object, and throws if something goes wrong. * SSL_CTX object, and throws if something goes wrong.
*/ */
virtual void setCiphersOrThrow(const std::string& ciphers); virtual void setCiphersOrThrow(const std::string& ciphers);
/**
* Set default ciphers to be used in SSL handshake process.
*/
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 * Sets the signature algorithms to be used during SSL negotiation
* for TLS1.2+ * for TLS1.2+.
*
* @param sigalgs A list of signature algorithms, eg. RSA+SHA512
*/ */
void setSignatureAlgorithms(const std::vector<std::string>& sigalgs);
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. * Sets the list of EC curves supported by the client.
......
...@@ -14,43 +14,22 @@ ...@@ -14,43 +14,22 @@
* limitations under the License. * limitations under the License.
*/ */
#include "SSLOptions.h" #include <folly/io/async/SSLOptions.h>
#include <folly/Format.h>
#include <folly/Logging.h>
namespace folly { namespace folly {
namespace ssl { namespace ssl {
const std::vector<std::string>& SSLCommonOptions::getCipherList() { namespace ssl_options_detail {
static const std::vector<std::string> kCommonCipherList = { void logDfatal(std::exception const& e) {
"ECDHE-ECDSA-AES128-GCM-SHA256", LOG(DFATAL) << exceptionStr(e);
"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;
} }
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) { void SSLCommonOptions::setClientOptions(SSLContext& ctx) {
#ifdef SSL_MODE_HANDSHAKE_CUTTHROUGH #ifdef SSL_MODE_HANDSHAKE_CUTTHROUGH
ctx.enableFalseStart(); ctx.enableFalseStart();
......
...@@ -16,25 +16,47 @@ ...@@ -16,25 +16,47 @@
#pragma once #pragma once
#include <folly/Format.h> #include <folly/Array.h>
#include <folly/io/async/SSLContext.h> #include <folly/io/async/SSLContext.h>
#include <glog/logging.h>
namespace folly { namespace folly {
namespace ssl { namespace ssl {
namespace ssl_options_detail {
void logDfatal(std::exception const&);
}
struct SSLCommonOptions { 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. * 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, * Set common parameters on a client SSL context, for example,
...@@ -44,21 +66,31 @@ struct SSLCommonOptions { ...@@ -44,21 +66,31 @@ struct SSLCommonOptions {
static void setClientOptions(SSLContext& ctx); 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> template <typename TSSLOptions>
void setCipherSuites(SSLContext& ctx) { void setCipherSuites(SSLContext& ctx) {
try { try {
ctx.setCipherList(TSSLOptions::getCipherList()); ctx.setCipherList(TSSLOptions::kCipherList);
} catch (std::runtime_error const& e) { } 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> template <typename TSSLOptions>
void setSignatureAlgorithms(SSLContext& ctx) { void setSignatureAlgorithms(SSLContext& ctx) {
try { try {
ctx.setSignatureAlgorithms(TSSLOptions::getSignatureAlgorithms()); ctx.setSignatureAlgorithms(TSSLOptions::kSignatureAlgorithms);
} catch (std::runtime_error const& e) { } catch (std::runtime_error const& e) {
LOG(DFATAL) << exceptionStr(e); ssl_options_detail::logDfatal(e);
} }
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <folly/io/async/SSLContext.h> #include <folly/io/async/SSLContext.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#include <folly/ssl/OpenSSLPtrTypes.h>
using namespace std; using namespace std;
using namespace testing; using namespace testing;
...@@ -30,12 +31,11 @@ class SSLContextTest : public testing::Test { ...@@ -30,12 +31,11 @@ class SSLContextTest : public testing::Test {
void SSLContextTest::verifySSLCipherList(const vector<string>& ciphers) { void SSLContextTest::verifySSLCipherList(const vector<string>& ciphers) {
int i = 0; int i = 0;
SSL* ssl = ctx.createSSL(); ssl::SSLUniquePtr ssl(ctx.createSSL());
for (auto& cipher : ciphers) { 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)); ASSERT_EQ(nullptr, SSL_get_cipher_list(ssl.get(), i));
SSL_free(ssl);
} }
TEST_F(SSLContextTest, TestSetCipherString) { TEST_F(SSLContextTest, TestSetCipherString) {
......
...@@ -26,18 +26,15 @@ namespace folly { ...@@ -26,18 +26,15 @@ namespace folly {
class SSLOptionsTest : public testing::Test {}; 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; int i = 0;
ssl::SSLUniquePtr ssl(ctx.createSSL()); ssl::SSLUniquePtr ssl(ctx.createSSL());
for (auto& cipher : ciphers) { for (auto& cipher : ssl::SSLCommonOptions::kCipherList) {
ASSERT_STREQ(cipher.c_str(), SSL_get_cipher_list(ssl.get(), i++)); ASSERT_STREQ(cipher, SSL_get_cipher_list(ssl.get(), i++));
} }
ASSERT_EQ(nullptr, 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());
}
} }
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