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_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); 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) { if (SSL_CTX_set_cipher_list(ssl_ctx, ssl::DEFAULT_CIPHER_LIST) == 0) {
std::cerr << ERR_error_string(ERR_get_error(), nullptr) << std::endl; std::cerr << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
return -1; 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_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); 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) { if (SSL_CTX_set_cipher_list(ssl_ctx, config.ciphers.c_str()) == 0) {
std::cerr << "SSL_CTX_set_cipher_list with " << config.ciphers std::cerr << "SSL_CTX_set_cipher_list with " << config.ciphers
<< " failed: " << ERR_error_string(ERR_get_error(), nullptr) << " 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_options(ssl_ctx, ssl_opts);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); 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) { if (SSL_CTX_set_cipher_list(ssl_ctx, ssl::DEFAULT_CIPHER_LIST) == 0) {
std::cerr << "[ERROR] " << ERR_error_string(ERR_get_error(), nullptr) std::cerr << "[ERROR] " << ERR_error_string(ERR_get_error(), nullptr)
<< std::endl; << std::endl;

View File

@ -1369,7 +1369,11 @@ constexpr auto DEFAULT_NPN_LIST = StringRef::from_lit("h2,h2-16,h2-14,"
namespace { namespace {
constexpr auto DEFAULT_TLS_MIN_PROTO_VERSION = StringRef::from_lit("TLSv1.1"); 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"); constexpr auto DEFAULT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("TLSv1.2");
#endif // !TLS1_3_VERSION
} // namespace } // namespace
namespace { namespace {
@ -2060,23 +2064,33 @@ SSL/TLS:
Path to file that contains client certificate used in Path to file that contains client certificate used in
backend client authentication. backend client authentication.
--tls-min-proto-version=<VER> --tls-min-proto-version=<VER>
Specify minimum SSL/TLS protocol. The following Specify minimum SSL/TLS protocol. The name matching is
protocols are available: TLSv1.2, TLSv1.1 and TLSv1.0. done in case-insensitive manner. The versions between
The name matching is done in case-insensitive manner. --tls-min-proto-version and --tls-max-proto-version are
The versions between --tls-min-proto-version and enabled. If the protocol list advertised by client does
--tls-max-proto-version are enabled. If the protocol not overlap this range, you will receive the error
list advertised by client does not overlap this range, message "unknown protocol". The available versions are:
you will receive the error message "unknown protocol". )"
#ifdef TLS1_3_VERSION
"TLSv1.3, "
#endif // TLS1_3_VERSION
"TLSv1.2, TLSv1.1, and TLSv1.0"
R"(
Default: )" Default: )"
<< DEFAULT_TLS_MIN_PROTO_VERSION << R"( << DEFAULT_TLS_MIN_PROTO_VERSION << R"(
--tls-max-proto-version=<VER> --tls-max-proto-version=<VER>
Specify maximum SSL/TLS protocol. The following Specify maximum SSL/TLS protocol. The name matching is
protocols are available: TLSv1.2, TLSv1.1 and TLSv1.0. done in case-insensitive manner. The versions between
The name matching is done in case-insensitive manner. --tls-min-proto-version and --tls-max-proto-version are
The versions between --tls-min-proto-version and enabled. If the protocol list advertised by client does
--tls-max-proto-version are enabled. If the protocol not overlap this range, you will receive the error
list advertised by client does not overlap this range, message "unknown protocol". The available versions are:
you will receive the error message "unknown protocol". )"
#ifdef TLS1_3_VERSION
"TLSv1.3, "
#endif // TLS1_3_VERSION
"TLSv1.2, TLSv1.1, and TLSv1.0"
R"(
Default: )" Default: )"
<< DEFAULT_TLS_MAX_PROTO_VERSION << R"( << DEFAULT_TLS_MAX_PROTO_VERSION << R"(
--tls-ticket-key-file=<PATH> --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; 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, SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file,
const std::vector<uint8_t> &sct_data const std::vector<uint8_t> &sct_data
#ifdef HAVE_NEVERBLEED #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); SSL_CTX_set_options(ssl_ctx, ssl_opts | tlsconf.tls_proto_mask);
if (ssl_ctx_set_proto_versions(ssl_ctx, tlsconf.min_proto_version, if (nghttp2::ssl::ssl_ctx_set_proto_versions(
tlsconf.max_proto_version) != 0) { ssl_ctx, tlsconf.min_proto_version, tlsconf.max_proto_version) != 0) {
LOG(FATAL) << "Could not set TLS protocol version: " LOG(FATAL) << "Could not set TLS protocol version";
<< ERR_error_string(ERR_get_error(), nullptr);
DIE(); DIE();
} }
@ -953,10 +903,9 @@ SSL_CTX *create_ssl_client_context(
SSL_CTX_set_options(ssl_ctx, ssl_opts | tlsconf.tls_proto_mask); SSL_CTX_set_options(ssl_ctx, ssl_opts | tlsconf.tls_proto_mask);
if (ssl_ctx_set_proto_versions(ssl_ctx, tlsconf.min_proto_version, if (nghttp2::ssl::ssl_ctx_set_proto_versions(
tlsconf.max_proto_version) != 0) { ssl_ctx, tlsconf.min_proto_version, tlsconf.max_proto_version) != 0) {
LOG(FATAL) << "Could not set TLS protocol version: " LOG(FATAL) << "Could not set TLS protocol version";
<< ERR_error_string(ERR_get_error(), nullptr);
DIE(); DIE();
} }
@ -1742,6 +1691,11 @@ SSL_SESSION *reuse_tls_session(const TLSSessionCache &cache) {
} }
int proto_version_from_string(const StringRef &v) { 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)) { if (util::strieq_l("TLSv1.2", v)) {
return TLS1_2_VERSION; return TLS1_2_VERSION;
} }

View File

@ -83,6 +83,10 @@ const char *get_tls_protocol(SSL *ssl) {
return "SSLv2"; return "SSLv2";
case SSL3_VERSION: case SSL3_VERSION:
return "SSLv3"; return "SSLv3";
#ifdef TLS1_3_VERSION
case TLS1_3_VERSION:
return "TLSv1.3";
#endif // TLS1_3_VERSION
case TLS1_2_VERSION: case TLS1_2_VERSION:
return "TLSv1.2"; return "TLSv1.2";
case TLS1_1_VERSION: case TLS1_1_VERSION:
@ -159,6 +163,45 @@ void libssl_init() {
OpenSSL_add_all_algorithms(); 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 ssl
} // namespace nghttp2 } // namespace nghttp2

View File

@ -49,7 +49,25 @@ public:
// suites by mozilla. // suites by mozilla.
// //
// https://wiki.mozilla.org/Security/Server_Side_TLS // https://wiki.mozilla.org/Security/Server_Side_TLS
//
// Plus TLSv1.3 cipher suites if defined.
constexpr char DEFAULT_CIPHER_LIST[] = 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-" "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-"
"AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-" "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-" "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-" "SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-"
"SHA:DES-CBC3-SHA:!DSS"; "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); const char *get_tls_protocol(SSL *ssl);
struct TLSSessionInfo { struct TLSSessionInfo {
@ -91,6 +116,10 @@ bool check_http2_requirement(SSL *ssl);
// Initializes OpenSSL library // Initializes OpenSSL library
void libssl_init(); 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 ssl
} // namespace nghttp2 } // namespace nghttp2