From cc0a8e3f81c3d8dd311d3bc6f45317b74d4d5347 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Feb 16 2017 17:35:51 +0000 Subject: TLSv1.3 support (WIP) Starting with NSS 3.28, TLS 1.3 support is available in upstream. TLS 1.3 needs both a new configuration constant and a set of new ciphers. The latest version of TLS does not have any cipher suites in common with TLS 1.2 and older. The patch is based on initial work by Franziskus. NSS 3.28 in Fedora has TLS 1.3 disabled, https://pagure.io/mod_nss/issue/27#comment-143043 Closes: https://pagure.io/mod_nss/issue/27 Signed-off-by: Christian Heimes --- diff --git a/Makefile.am b/Makefile.am index c57cd09..b3e8451 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,7 +22,7 @@ libmodnss_la_LDFLAGS = -module -avoid-version ## Set the includes and libraries needed AM_CPPFLAGS = -I@apache_inc@ @nspr_inc@ @nss_inc@ @apr_inc@ -LIBS = @nspr_lib@ @nss_lib@ -lssl3 -lsmime3 -lnss3 -lplc4 -lplds4 -lnspr4 +LIBS = @nspr_lib@ @nss_lib@ -lssl3 -lsmime3 -lnss3 -lplc4 -lplds4 -lnspr4 -lnssutil3 EXTRA_CPPFLAGS=@extra_cppflags@ install-libLTLIBRARIES: libmodnss.la diff --git a/mod_nss.h b/mod_nss.h index 8643e88..7904ac6 100644 --- a/mod_nss.h +++ b/mod_nss.h @@ -175,6 +175,13 @@ ap_set_module_config(c->conn_config, &nss_module, val) typedef int nss_opt_t; /* + * TLS 1.3 is available since NSS 3.28 + */ +#if (((NSS_VMAJOR == 3) && (NSS_VMINOR >= 28)) || (NSS_VMAJOR > 3)) + #define NSS_SUPPORTS_TLS_1_3 1 +#endif + +/* * Define the SSL requirement structure */ typedef struct { diff --git a/mod_nss.spec b/mod_nss.spec index 3cc88db..1cf1551 100644 --- a/mod_nss.spec +++ b/mod_nss.spec @@ -26,7 +26,7 @@ Group: System Environment/Daemons URL: http://directory.fedora.redhat.com/ Source: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-root -BuildPreReq: httpd-devel,apr-devel +BuildRequires: httpd-devel,apr-devel,nss-devel,flex,byacc # Without Autoreq: 0, rpmbuild finds all sorts of crazy # dependencies that we don't care about, and refuses to install Autoreq: 0 @@ -56,7 +56,7 @@ fi # configure requires nspr, nss, ldapsdk, adminutil # if can't find apxs, use --with-apxs=/path/to/apxs -./configure --with-apr-config --with-nspr-inc=%{nsprincdir} --with-nspr-lib=%{nsprlibdir} --with-nss-inc=%{nssincdir} --with-nss-lib=%{nsslibdir} +./configure --with-apr-config --with-nspr-inc=%{nsprincdir} --with-nspr-lib=%{nsprlibdir} --with-nss-inc=%{nssincdir} --with-nss-lib=%{nsslibdir} --enable-ecc CFLAGS="$flag $mycflags" make %install diff --git a/nss_engine_cipher.c b/nss_engine_cipher.c index 4ec01f4..e56fcb6 100644 --- a/nss_engine_cipher.c +++ b/nss_engine_cipher.c @@ -123,6 +123,15 @@ cipher_properties ciphers_def[] = {"ecdhe_ecdsa_chacha20_poly1305_sha_256", TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, "ECDHE-ECDSA-CHACHA20-POLY1305", SSL_kEECDH|SSL_aECDSA|SSL_CHACHA20POLY1305|SSL_AEAD, TLSV1_2, SSL_HIGH, 256, 256}, {"dhe_rsa_chacha20_poly1305_sha_256", TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, "DHE-RSA-CHACHA20-POLY1305", SSL_kEDH|SSL_aRSA|SSL_CHACHA20POLY1305|SSL_AEAD, TLSV1_2, SSL_HIGH, 256, 256}, #endif +#ifdef NSS_SUPPORTS_TLS_1_3 + /* Special TLS 1.3 cipher suites that really just specify AEAD + * TLS 1.3 ciphers don't specify key exchange and authentication. + */ + {"aes_128_gcm_sha_256", TLS_AES_128_GCM_SHA256, "TLS13-AES-128-GCM-SHA256", SSL_AES128GCM|SSL_AEAD, TLSV1_3, SSL_HIGH, 128, 128, NULL}, + /* OpenSSL has not agreed on names for AES 256 and ChaCha20 TLS 1.3 ciphers yet */ + {"aes_256_gcm_sha_384", TLS_AES_256_GCM_SHA384, "TLS13-AES-256-GCM-SHA384", SSL_AES256GCM|SSL_AEAD, TLSV1_3, SSL_HIGH, 256, 256, NULL}, + {"chacha20_poly1305_sha_256", TLS_CHACHA20_POLY1305_SHA256, "TLS13-CHACHA20-POLY1305", SSL_CHACHA20POLY1305|SSL_AEAD, TLSV1_3, SSL_HIGH, 256, 256}, +#endif }; #define CIPHERNUM sizeof(ciphers_def) / sizeof(cipher_properties) @@ -170,11 +179,11 @@ int nss_parse_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum rv = parse_nss_ciphers(s, ciphers, cipher_list); } else { rv = parse_openssl_ciphers(s, ciphers, cipher_list); - if (rv == 0 && 0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2)) { + if (rv == 0 && 0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2|TLSV1_3)) { rv = parse_nss_ciphers(s, ciphers, cipher_list); } } - if (0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2)) { + if (0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2|TLSV1_3)) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "no cipher match"); } @@ -406,6 +415,8 @@ static int parse_openssl_ciphers(server_rec *s, char *ciphers, PRBool cipher_lis protocol |= TLSV1; } else if (!strcmp(cipher, "TLSv1.2")) { protocol |= TLSV1_2; + } else if (!strcmp(cipher, "TLSv1.3")) { + protocol |= TLSV1_3; } else if (!strcmp(cipher, "HIGH")) { strength |= SSL_HIGH; } else if (!strcmp(cipher, "MEDIUM")) { @@ -493,7 +504,7 @@ static int parse_openssl_ciphers(server_rec *s, char *ciphers, PRBool cipher_lis cipher = ciphers; } - if (found && 0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2)) + if (found && 0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2|TLSV1_3)) return 1; /* no matching ciphers */ return 0; } diff --git a/nss_engine_cipher.h b/nss_engine_cipher.h index bb6e3ad..f1d26cb 100644 --- a/nss_engine_cipher.h +++ b/nss_engine_cipher.h @@ -86,6 +86,7 @@ typedef struct #define SSLV3 0x00000002L #define TLSV1 SSLV3 #define TLSV1_2 0x00000004L +#define TLSV1_3 0x00000005L /* the table itself is defined in nss_engine_cipher.c */ #if 0 diff --git a/nss_engine_init.c b/nss_engine_init.c index 2ffff53..5833318 100644 --- a/nss_engine_init.c +++ b/nss_engine_init.c @@ -744,6 +744,9 @@ static void nss_init_ctx_protocol(server_rec *s, modnss_ctx_t *mctx) { int ssl3, tls, tls1_1, tls1_2; +#ifdef NSS_SUPPORTS_TLS_1_3 + int tls1_3 = 0; +#endif char *protocol_marker = NULL; char *lprotocols = NULL; SECStatus stat; @@ -766,16 +769,27 @@ static void nss_init_ctx_protocol(server_rec *s, } if (mctx->auth.protocols == NULL) { +#ifdef NSS_SUPPORTS_TLS_1_3 + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "%s value not set; using: TLSv1.0, TLSv1.1, TLSv1.2, and TLSv1.3", + protocol_marker); + tls = tls1_1 = tls1_2 = tls1_3 = 1; +#else ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "%s value not set; using: TLSv1.0, TLSv1.1 and TLSv1.2", + "%s value not set; using: TLSv1.0, TLSv1.1, and TLSv1.2", protocol_marker); tls = tls1_1 = tls1_2 = 1; +#endif } else { lprotocols = strdup(mctx->auth.protocols); ap_str_tolower(lprotocols); if (strstr(lprotocols, "all") != NULL) { +#ifdef NSS_SUPPORTS_TLS_1_3 + ssl3 = tls = tls1_1 = tls1_2 = tls1_3 = 1; +#else ssl3 = tls = tls1_1 = tls1_2 = 1; +#endif } else { char *protocol_list = NULL; char *saveptr = NULL; @@ -823,6 +837,13 @@ static void nss_init_ctx_protocol(server_rec *s, "%s: Enabling TLSv1.2", protocol_marker); tls1_2 = 1; +#ifdef NSS_SUPPORTS_TLS_1_3 + } else if (strcmp(token, "tlsv1.3") == 0) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "%s: Enabling TLSv1.3", + protocol_marker); + tls1_3 = 1; +#endif } else { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "%s: Unknown protocol '%s' not supported", @@ -837,12 +858,21 @@ static void nss_init_ctx_protocol(server_rec *s, * if FIPS mode is enabled with no TLS protocols, * enable ALL TLS protocols. */ +#ifdef NSS_SUPPORTS_TLS_1_3 + if ((mctx->sc->fips) && (tls == 0) && (tls1_1 == 0) && (tls1_2 == 0) && (tls1_3 == 0)) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "%s: FIPS mode no valid protocols set, enabling TLSv1.0, TLSv1.1, TLSv1.2 and TLSv1.3", + protocol_marker); + tls = tls1_1 = tls1_2 = tls1_3 = 1; + } +#else if ((mctx->sc->fips) && (tls == 0) && (tls1_1 == 0) && (tls1_2 == 0)) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, - "%s: FIPS mode no valid protocols set, enabling TLSv1.0, TLSv1.1 and TLSv1.2", + "%s: FIPS mode no valid protocols set, enabling TLSv1.0, TLSv1.1, and TLSv1.2", protocol_marker); tls = tls1_1 = tls1_2 = 1; } +#endif } stat = SSL_OptionSet(mctx->model, SSL_ENABLE_SSL2, PR_FALSE); @@ -869,7 +899,7 @@ static void nss_init_ctx_protocol(server_rec *s, if (stat == SECSuccess) { /* Set minimum protocol version (lowest -> highest) * - * SSL 3.0 -> TLS 1.0 -> TLS 1.1 -> TLS 1.2 + * SSL 3.0 -> TLS 1.0 -> TLS 1.1 -> TLS 1.2 -> TLS 1.3 */ if (ssl3 == 1) { enabledVersions.min = SSL_LIBRARY_VERSION_3_0; @@ -891,6 +921,13 @@ static void nss_init_ctx_protocol(server_rec *s, ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: [TLS 1.2] (minimum)", protocol_marker); +#ifdef NSS_SUPPORTS_TLS_1_3 + } else if (tls1_3 == 1) { + enabledVersions.min = SSL_LIBRARY_VERSION_TLS_1_3; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "%s: [TLS 1.3] (minimum)", + protocol_marker); +#endif } else { /* Set default minimum protocol version to SSL 3.0 */ enabledVersions.min = SSL_LIBRARY_VERSION_3_0; @@ -901,9 +938,18 @@ static void nss_init_ctx_protocol(server_rec *s, /* Set maximum protocol version (highest -> lowest) * - * TLS 1.2 -> TLS 1.1 -> TLS 1.0 -> SSL 3.0 + * TLS 1.3 -> TLS 1.2 -> TLS 1.1 -> TLS 1.0 -> SSL 3.0 */ +#ifdef NSS_SUPPORTS_TLS_1_3 + if (tls1_3 == 1) { + enabledVersions.max = SSL_LIBRARY_VERSION_TLS_1_3; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "%s: [TLS 1.3] (maximum)", + protocol_marker); + } else if (tls1_2 == 1) { +#else if (tls1_2 == 1) { +#endif enabledVersions.max = SSL_LIBRARY_VERSION_TLS_1_2; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: [TLS 1.2] (maximum)", @@ -938,12 +984,19 @@ static void nss_init_ctx_protocol(server_rec *s, ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "%s: SSL/TLS protocol initialization failed.", protocol_marker); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Enabled versions: min 0x%04x, max 0x%04x", + enabledVersions.min, enabledVersions.max); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } mctx->ssl3 = ssl3; +#ifdef NSS_SUPPORTS_TLS_1_3 + mctx->tls = tls || tls1_1 || tls1_2 || tls1_3; +#else mctx->tls = tls || tls1_1 || tls1_2; +#endif ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%sabling TLS Session Tickets", mctx->sc->session_tickets == PR_TRUE ? "En" : "Dis"); diff --git a/nss_engine_vars.c b/nss_engine_vars.c index d434646..c7ea372 100644 --- a/nss_engine_vars.c +++ b/nss_engine_vars.c @@ -775,6 +775,11 @@ static char *nss_var_lookup_protocol_version(apr_pool_t *p, conn_rec *c) case SSL_LIBRARY_VERSION_TLS_1_2: result = "TLSv1.2"; break; +#ifdef NSS_SUPPORTS_TLS_1_3 + case SSL_LIBRARY_VERSION_TLS_1_3: + result = "TLSv1.3"; + break; +#endif } } }