src: Enable TLSv1.3 if OpenSSL supports it

If OpenSSL supports TLSv1.3, enable it by default for all applications
under src.  BoringSSL can work at the moment although it does not
unlock all the features nghttpx offers.  OpenSSL's TLSv1.3 support is
still WIP at the time of writing.
This commit is contained in:
Tatsuhiro Tsujikawa 2017-02-15 00:40:43 +09:00
parent 6ecfac6954
commit 9e8d9d658a
7 changed files with 134 additions and 71 deletions

View File

@ -2122,6 +2122,13 @@ int HttpServer::run() {
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
if (nghttp2::ssl::ssl_ctx_set_proto_versions(
ssl_ctx, nghttp2::ssl::NGHTTP2_TLS_MIN_VERSION,
nghttp2::ssl::NGHTTP2_TLS_MAX_VERSION) != 0) {
std::cerr << "Could not set TLS versions" << std::endl;
return -1;
}
if (SSL_CTX_set_cipher_list(ssl_ctx, ssl::DEFAULT_CIPHER_LIST) == 0) {
std::cerr << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
return -1;

View File

@ -2242,6 +2242,13 @@ int main(int argc, char **argv) {
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
if (nghttp2::ssl::ssl_ctx_set_proto_versions(
ssl_ctx, nghttp2::ssl::NGHTTP2_TLS_MIN_VERSION,
nghttp2::ssl::NGHTTP2_TLS_MAX_VERSION) != 0) {
std::cerr << "Could not set TLS versions" << std::endl;
exit(EXIT_FAILURE);
}
if (SSL_CTX_set_cipher_list(ssl_ctx, config.ciphers.c_str()) == 0) {
std::cerr << "SSL_CTX_set_cipher_list with " << config.ciphers
<< " failed: " << ERR_error_string(ERR_get_error(), nullptr)

View File

@ -2246,6 +2246,15 @@ int communicate(
SSL_CTX_set_options(ssl_ctx, ssl_opts);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
if (nghttp2::ssl::ssl_ctx_set_proto_versions(
ssl_ctx, nghttp2::ssl::NGHTTP2_TLS_MIN_VERSION,
nghttp2::ssl::NGHTTP2_TLS_MAX_VERSION) != 0) {
std::cerr << "[ERROR] Could not set TLS versions" << std::endl;
result = -1;
goto fin;
}
if (SSL_CTX_set_cipher_list(ssl_ctx, ssl::DEFAULT_CIPHER_LIST) == 0) {
std::cerr << "[ERROR] " << ERR_error_string(ERR_get_error(), nullptr)
<< std::endl;

View File

@ -1369,7 +1369,11 @@ constexpr auto DEFAULT_NPN_LIST = StringRef::from_lit("h2,h2-16,h2-14,"
namespace {
constexpr auto DEFAULT_TLS_MIN_PROTO_VERSION = StringRef::from_lit("TLSv1.1");
#ifdef TLS1_3_VERSION
constexpr auto DEFAULT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("TLSv1.3");
#else // !TLS1_3_VERSION
constexpr auto DEFAULT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("TLSv1.2");
#endif // !TLS1_3_VERSION
} // namespace
namespace {
@ -2060,23 +2064,33 @@ SSL/TLS:
Path to file that contains client certificate used in
backend client authentication.
--tls-min-proto-version=<VER>
Specify minimum SSL/TLS protocol. The following
protocols are available: TLSv1.2, TLSv1.1 and TLSv1.0.
The name matching is done in case-insensitive manner.
The versions between --tls-min-proto-version and
--tls-max-proto-version are enabled. If the protocol
list advertised by client does not overlap this range,
you will receive the error message "unknown protocol".
Specify minimum SSL/TLS protocol. The name matching is
done in case-insensitive manner. The versions between
--tls-min-proto-version and --tls-max-proto-version are
enabled. If the protocol list advertised by client does
not overlap this range, you will receive the error
message "unknown protocol". The available versions are:
)"
#ifdef TLS1_3_VERSION
"TLSv1.3, "
#endif // TLS1_3_VERSION
"TLSv1.2, TLSv1.1, and TLSv1.0"
R"(
Default: )"
<< DEFAULT_TLS_MIN_PROTO_VERSION << R"(
--tls-max-proto-version=<VER>
Specify maximum SSL/TLS protocol. The following
protocols are available: TLSv1.2, TLSv1.1 and TLSv1.0.
The name matching is done in case-insensitive manner.
The versions between --tls-min-proto-version and
--tls-max-proto-version are enabled. If the protocol
list advertised by client does not overlap this range,
you will receive the error message "unknown protocol".
Specify maximum SSL/TLS protocol. The name matching is
done in case-insensitive manner. The versions between
--tls-min-proto-version and --tls-max-proto-version are
enabled. If the protocol list advertised by client does
not overlap this range, you will receive the error
message "unknown protocol". The available versions are:
)"
#ifdef TLS1_3_VERSION
"TLSv1.3, "
#endif // TLS1_3_VERSION
"TLSv1.2, TLSv1.1, and TLSv1.0"
R"(
Default: )"
<< DEFAULT_TLS_MAX_PROTO_VERSION << R"(
--tls-ticket-key-file=<PATH>

View File

@ -639,55 +639,6 @@ long int create_tls_proto_mask(const std::vector<StringRef> &tls_proto_list) {
return res;
}
#if defined(OPENSSL_IS_BORINGSSL)
namespace {
int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max) {
SSL_CTX_set_min_version(ssl_ctx, min);
SSL_CTX_set_max_version(ssl_ctx, max);
return 0;
}
} // namespace
#elif OPENSSL_1_1_API
namespace {
int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max) {
if (SSL_CTX_set_min_proto_version(ssl_ctx, min) != 1 ||
SSL_CTX_set_max_proto_version(ssl_ctx, max) != 1) {
return -1;
}
return 0;
}
} // namespace
#else // !OPENSSL_1_1_API
namespace {
int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max) {
long int opts = 0;
// TODO We depends on the ordering of protocol version macro in
// OpenSSL.
if (min > TLS1_VERSION) {
opts |= SSL_OP_NO_TLSv1;
}
if (min > TLS1_1_VERSION) {
opts |= SSL_OP_NO_TLSv1_1;
}
if (min > TLS1_2_VERSION) {
opts |= SSL_OP_NO_TLSv1_2;
}
if (max < TLS1_2_VERSION) {
opts |= SSL_OP_NO_TLSv1_2;
}
if (max < TLS1_1_VERSION) {
opts |= SSL_OP_NO_TLSv1_1;
}
SSL_CTX_set_options(ssl_ctx, opts);
return 0;
}
} // namespace
#endif // !OPENSSL_1_1_API
SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file,
const std::vector<uint8_t> &sct_data
#ifdef HAVE_NEVERBLEED
@ -712,10 +663,9 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file,
SSL_CTX_set_options(ssl_ctx, ssl_opts | tlsconf.tls_proto_mask);
if (ssl_ctx_set_proto_versions(ssl_ctx, tlsconf.min_proto_version,
tlsconf.max_proto_version) != 0) {
LOG(FATAL) << "Could not set TLS protocol version: "
<< ERR_error_string(ERR_get_error(), nullptr);
if (nghttp2::ssl::ssl_ctx_set_proto_versions(
ssl_ctx, tlsconf.min_proto_version, tlsconf.max_proto_version) != 0) {
LOG(FATAL) << "Could not set TLS protocol version";
DIE();
}
@ -953,10 +903,9 @@ SSL_CTX *create_ssl_client_context(
SSL_CTX_set_options(ssl_ctx, ssl_opts | tlsconf.tls_proto_mask);
if (ssl_ctx_set_proto_versions(ssl_ctx, tlsconf.min_proto_version,
tlsconf.max_proto_version) != 0) {
LOG(FATAL) << "Could not set TLS protocol version: "
<< ERR_error_string(ERR_get_error(), nullptr);
if (nghttp2::ssl::ssl_ctx_set_proto_versions(
ssl_ctx, tlsconf.min_proto_version, tlsconf.max_proto_version) != 0) {
LOG(FATAL) << "Could not set TLS protocol version";
DIE();
}
@ -1742,6 +1691,11 @@ SSL_SESSION *reuse_tls_session(const TLSSessionCache &cache) {
}
int proto_version_from_string(const StringRef &v) {
#ifdef TLS1_3_VERSION
if (util::strieq_l("TLSv1.3", v)) {
return TLS1_3_VERSION;
}
#endif // TLS1_3_VERSION
if (util::strieq_l("TLSv1.2", v)) {
return TLS1_2_VERSION;
}

View File

@ -83,6 +83,10 @@ const char *get_tls_protocol(SSL *ssl) {
return "SSLv2";
case SSL3_VERSION:
return "SSLv3";
#ifdef TLS1_3_VERSION
case TLS1_3_VERSION:
return "TLSv1.3";
#endif // TLS1_3_VERSION
case TLS1_2_VERSION:
return "TLSv1.2";
case TLS1_1_VERSION:
@ -159,6 +163,45 @@ void libssl_init() {
OpenSSL_add_all_algorithms();
}
int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max) {
#if OPENSSL_1_1_API
if (SSL_CTX_set_min_proto_version(ssl_ctx, min) != 1 ||
SSL_CTX_set_max_proto_version(ssl_ctx, max) != 1) {
return -1;
}
return 0;
#elif defined(OPENSSL_IS_BORINGSSL)
SSL_CTX_set_min_version(ssl_ctx, min);
SSL_CTX_set_max_version(ssl_ctx, max);
return 0;
#else // !defined(OPENSSL_IS_BORINGSSL)
long int opts = 0;
// TODO We depends on the ordering of protocol version macro in
// OpenSSL.
if (min > TLS1_VERSION) {
opts |= SSL_OP_NO_TLSv1;
}
if (min > TLS1_1_VERSION) {
opts |= SSL_OP_NO_TLSv1_1;
}
if (min > TLS1_2_VERSION) {
opts |= SSL_OP_NO_TLSv1_2;
}
if (max < TLS1_2_VERSION) {
opts |= SSL_OP_NO_TLSv1_2;
}
if (max < TLS1_1_VERSION) {
opts |= SSL_OP_NO_TLSv1_1;
}
SSL_CTX_set_options(ssl_ctx, opts);
return 0;
#endif // !defined(OPENSSL_IS_BORINGSSL)
}
} // namespace ssl
} // namespace nghttp2

View File

@ -49,7 +49,25 @@ public:
// suites by mozilla.
//
// https://wiki.mozilla.org/Security/Server_Side_TLS
//
// Plus TLSv1.3 cipher suites if defined.
constexpr char DEFAULT_CIPHER_LIST[] =
#ifdef TLS1_3_TXT_AES_256_GCM_SHA384
TLS1_3_TXT_AES_256_GCM_SHA384
":"
#endif // TLS1_3_TXT_AES_256_GCM_SHA384
#ifdef TLS1_3_TXT_CHACHA20_POLY1305_SHA256
TLS1_3_TXT_CHACHA20_POLY1305_SHA256 ":"
#endif // TLS1_3_TXT_CHACHA20_POLY1305_SHA256
#ifdef TLS1_3_TXT_AES_128_GCM_SHA256
TLS1_3_TXT_AES_128_GCM_SHA256 ":"
#endif // TLS1_3_TXT_AES_128_GCM_SHA256
#ifdef TLS1_3_TXT_AES_128_CCM_SHA256
TLS1_3_TXT_AES_128_CCM_SHA256 ":"
#endif // TLS1_3_TXT_AES_128_CCM_SHA256
#ifdef TLS1_3_TXT_AES_128_CCM_8_SHA256
TLS1_3_TXT_AES_128_CCM_8_SHA256 ":"
#endif // TLS1_3_TXT_AES_128_CCM_8_SHA256
"ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-"
"AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-"
"SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-"
@ -61,6 +79,13 @@ constexpr char DEFAULT_CIPHER_LIST[] =
"SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-"
"SHA:DES-CBC3-SHA:!DSS";
constexpr auto NGHTTP2_TLS_MIN_VERSION = TLS1_VERSION;
#ifdef TLS1_3_VERSION
constexpr auto NGHTTP2_TLS_MAX_VERSION = TLS1_3_VERSION;
#else // !TLS1_3_VERSION
constexpr auto NGHTTP2_TLS_MAX_VERSION = TLS1_2_VERSION;
#endif // !TLS1_3_VERSION
const char *get_tls_protocol(SSL *ssl);
struct TLSSessionInfo {
@ -91,6 +116,10 @@ bool check_http2_requirement(SSL *ssl);
// Initializes OpenSSL library
void libssl_init();
// Sets TLS min and max versions to |ssl_ctx|. This function returns
// 0 if it succeeds, or -1.
int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max);
} // namespace ssl
} // namespace nghttp2