Commit 2fa292de authored by Sotirios Delimanolis's avatar Sotirios Delimanolis Committed by Facebook GitHub Bot

Set SSLContext minimum version through SSL_CTX_set_min_proto_version for OpenSSL >= 1.1.0

Summary:
Attempt to set minimum version of an OpenSSL context through `SSL_CTX_set_min_proto_version` instead of disabling them explicitly through options, as recommended here: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_min_proto_version.html

The test checks that the `SSLContext`'s `SSL_CTX` can keep a lower version regardless of the OpenSSL's configured minimum.

Reviewed By: yfeldblum

Differential Revision: D22338879

fbshipit-source-id: 356328c2ffba2a6a9d4243300a11fc823bc345d7
parent bff1bb83
......@@ -28,6 +28,8 @@
// ---------------------------------------------------------------------
// SSLContext implementation
// ---------------------------------------------------------------------
namespace folly {
namespace {
int getExDataIndex() {
......@@ -36,51 +38,84 @@ int getExDataIndex() {
return index;
}
} // namespace
namespace folly {
//
// For OpenSSL portability API
// SSLContext implementation
SSLContext::SSLContext(SSLVersion version) {
folly::ssl::init();
/**
* Configure the given SSL context to use the given version.
*/
void configureProtocolVersion(SSL_CTX* ctx, SSLContext::SSLVersion version) {
#if FOLLY_OPENSSL_PREREQ(1, 1, 0)
// Disable TLS 1.3 by default, for now, if this version of OpenSSL
// supports it. There are some semantic differences (e.g. assumptions
// on getSession() returning a resumable session, SSL_CTX_set_ciphersuites,
// etc.)
//
SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
ctx_ = SSL_CTX_new(SSLv23_method());
if (ctx_ == nullptr) {
throw std::runtime_error("SSL_CTX_new: " + getErrors());
/*
* From the OpenSSL docs https://fburl.com/ii9k29qw:
* Setting the minimum or maximum version to 0, will enable protocol versions
* down to the lowest version, or up to the highest version supported by the
* library, respectively.
*
* We can use that as the default/fallback.
*/
int minVersion = 0;
switch (version) {
case SSLContext::SSLVersion::TLSv1:
minVersion = TLS1_VERSION;
break;
case SSLContext::SSLVersion::SSLv3:
minVersion = SSL3_VERSION;
break;
case SSLContext::SSLVersion::TLSv1_2:
minVersion = TLS1_2_VERSION;
break;
case SSLContext::SSLVersion::SSLv2:
default:
// do nothing
break;
}
int setMinProtoResult = SSL_CTX_set_min_proto_version(ctx, minVersion);
DCHECK(setMinProtoResult == 1)
<< sformat("unsupported min TLS protocol version: 0x{:04x}", minVersion);
#else
int opt = 0;
switch (version) {
case TLSv1:
case SSLContext::SSLVersion::TLSv1:
opt = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
break;
case SSLv3:
case SSLContext::SSLVersion::SSLv3:
opt = SSL_OP_NO_SSLv2;
break;
case TLSv1_2:
case SSLContext::SSLVersion::TLSv1_2:
opt = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 |
SSL_OP_NO_TLSv1_1;
break;
case SSLv2:
case SSLContext::SSLVersion::SSLv2:
default:
// do nothing
break;
}
int newOpt = SSL_CTX_set_options(ctx, opt);
DCHECK((newOpt & opt) == opt);
#endif // FOLLY_OPENSSL_PREREQ(1, 1, 0)
}
// Disable TLS 1.3 by default, for now, if this version of OpenSSL
// supports it. There are some semantic differences (e.g. assumptions
// on getSession() returning a resumable session, SSL_CTX_set_ciphersuites,
// etc.)
//
#if FOLLY_OPENSSL_IS_110
SSL_CTX_set_max_proto_version(ctx_, TLS1_2_VERSION);
#endif
} // namespace
int newOpt = SSL_CTX_set_options(ctx_, opt);
DCHECK((newOpt & opt) == opt);
//
// For OpenSSL portability API
// SSLContext implementation
SSLContext::SSLContext(SSLVersion version) {
folly::ssl::init();
ctx_ = SSL_CTX_new(SSLv23_method());
if (ctx_ == nullptr) {
throw std::runtime_error("SSL_CTX_new: " + getErrors());
}
// configure the TLS version used
configureProtocolVersion(ctx_, version);
SSL_CTX_set_mode(ctx_, SSL_MODE_AUTO_RETRY);
......
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/FileUtil.h>
#include <folly/io/async/SSLContext.h>
#include <gtest/gtest.h>
#include "common/files/FileUtil.h"
using namespace facebook::files;
/*
* This test is meant to verify that SSLContext correctly sets its minimum
* protocol version and is not blocked by OpenSSL's default config.
*/
namespace folly {
// need OpenSSL version 1.1.1 for the SSL_CTX_get_min_proto_version function
// should reduce this prereq's scope if new tests are added that don't need it
#if FOLLY_OPENSSL_PREREQ(1, 1, 1)
/*
* The default OpenSSL config file contents for version OpenSSL 1.1.1c FIPS 28
* May 2019. This should set the MinProtocol to TLS 1.2 and SECLEVEL to 2.
*/
const std::string kOpenSSLConf = folly::stripLeftMargin(R"(
CipherString = @SECLEVEL=2:kEECDH:kRSA:kEDH:kPSK:kDHEPSK:kECDHEPSK:-aDSS:-3DES:!DES:!RC4:!RC2:!IDEA:-SEED:!eNULL:!aNULL:!MD5:-SHA384:-CAMELLIA:-ARIA:-AESCCM8
Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256
MinProtocol = TLSv1.2
)");
class SSLContextRegressionTest : public testing::Test {
public:
void SetUp() override {
TemporaryFile confFile(nullptr, "", true);
FileUtil::writeStringToFile(StringPiece(kOpenSSLConf), confFile.filename());
// simulate the system environment by loading a config file that should
// represent the CentOS 8 configuration
int result = CONF_modules_load_file(confFile.filename(), nullptr, 0);
ASSERT_EQ(result, 1) << "Failed to load OpenSSL conf from temporary file.";
}
};
// Tests that specifying a TLS version actually sets the underlying SSL
// context's minimum to that same version (and not the default in the config).
TEST_F(SSLContextRegressionTest, IsNotAffectedBySystemEnvironment) {
auto ctx = std::make_shared<SSLContext>(SSLContext::SSLVersion::TLSv1);
ASSERT_EQ(SSL_CTX_get_min_proto_version(ctx->getSSLCtx()), TLS1_VERSION);
}
#endif
} // namespace folly
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