369db50dd0
Resolves: rhbz#1619389
859 lines
32 KiB
Diff
859 lines
32 KiB
Diff
|
|
Pull all changes from upstream integration branch:
|
|
|
|
svn diff -r1840105:1841219 https://svn.apache.org/repos/asf/httpd/httpd/branches/tlsv1.3-for-2.4.x
|
|
|
|
--- httpd-2.4.34/modules/ssl/mod_ssl.c.r1827912+
|
|
+++ httpd-2.4.34/modules/ssl/mod_ssl.c
|
|
@@ -93,9 +93,9 @@
|
|
SSL_CMD_SRV(FIPS, FLAG,
|
|
"Enable FIPS-140 mode "
|
|
"(`on', `off')")
|
|
- SSL_CMD_ALL(CipherSuite, TAKE1,
|
|
- "Colon-delimited list of permitted SSL Ciphers "
|
|
- "('XXX:...:XXX' - see manual)")
|
|
+ SSL_CMD_ALL(CipherSuite, TAKE12,
|
|
+ "Colon-delimited list of permitted SSL Ciphers, optional preceeded "
|
|
+ "by protocol identifier ('XXX:...:XXX' - see manual)")
|
|
SSL_CMD_SRV(CertificateFile, TAKE1,
|
|
"SSL Server Certificate file "
|
|
"('/path/to/file' - PEM or DER encoded)")
|
|
@@ -185,9 +185,9 @@
|
|
SSL_CMD_PXY(ProxyProtocol, RAW_ARGS,
|
|
"SSL Proxy: enable or disable SSL protocol flavors "
|
|
"('[+-][" SSL_PROTOCOLS "] ...' - see manual)")
|
|
- SSL_CMD_PXY(ProxyCipherSuite, TAKE1,
|
|
+ SSL_CMD_PXY(ProxyCipherSuite, TAKE12,
|
|
"SSL Proxy: colon-delimited list of permitted SSL ciphers "
|
|
- "('XXX:...:XXX' - see manual)")
|
|
+ ", optionally preceeded by protocol specifier ('XXX:...:XXX' - see manual)")
|
|
SSL_CMD_PXY(ProxyVerify, TAKE1,
|
|
"SSL Proxy: whether to verify the remote certificate "
|
|
"('on' or 'off')")
|
|
@@ -398,7 +398,7 @@
|
|
/* We must register the library in full, to ensure our configuration
|
|
* code can successfully test the SSL environment.
|
|
*/
|
|
-#if MODSSL_USE_OPENSSL_PRE_1_1_API
|
|
+#if MODSSL_USE_OPENSSL_PRE_1_1_API || defined(LIBRESSL_VERSION_NUMBER)
|
|
(void)CRYPTO_malloc_init();
|
|
#else
|
|
OPENSSL_malloc_init();
|
|
--- httpd-2.4.34/modules/ssl/ssl_engine_config.c.r1827912+
|
|
+++ httpd-2.4.34/modules/ssl/ssl_engine_config.c
|
|
@@ -136,6 +136,7 @@
|
|
mctx->auth.cipher_suite = NULL;
|
|
mctx->auth.verify_depth = UNSET;
|
|
mctx->auth.verify_mode = SSL_CVERIFY_UNSET;
|
|
+ mctx->auth.tls13_ciphers = NULL;
|
|
|
|
mctx->ocsp_mask = UNSET;
|
|
mctx->ocsp_force_default = UNSET;
|
|
@@ -280,6 +281,7 @@
|
|
cfgMergeString(auth.cipher_suite);
|
|
cfgMergeInt(auth.verify_depth);
|
|
cfgMerge(auth.verify_mode, SSL_CVERIFY_UNSET);
|
|
+ cfgMergeString(auth.tls13_ciphers);
|
|
|
|
cfgMergeInt(ocsp_mask);
|
|
cfgMergeBool(ocsp_force_default);
|
|
@@ -761,22 +763,37 @@
|
|
|
|
const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd,
|
|
void *dcfg,
|
|
- const char *arg)
|
|
+ const char *arg1, const char *arg2)
|
|
{
|
|
SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
|
|
SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
|
|
|
|
- /* always disable null and export ciphers */
|
|
- arg = apr_pstrcat(cmd->pool, arg, ":!aNULL:!eNULL:!EXP", NULL);
|
|
-
|
|
- if (cmd->path) {
|
|
- dc->szCipherSuite = arg;
|
|
+ if (arg2 == NULL) {
|
|
+ arg2 = arg1;
|
|
+ arg1 = "SSL";
|
|
}
|
|
- else {
|
|
- sc->server->auth.cipher_suite = arg;
|
|
+
|
|
+ if (!strcmp("SSL", arg1)) {
|
|
+ /* always disable null and export ciphers */
|
|
+ arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL);
|
|
+ if (cmd->path) {
|
|
+ dc->szCipherSuite = arg2;
|
|
+ }
|
|
+ else {
|
|
+ sc->server->auth.cipher_suite = arg2;
|
|
+ }
|
|
+ return NULL;
|
|
}
|
|
-
|
|
- return NULL;
|
|
+#if SSL_HAVE_PROTOCOL_TLSV1_3
|
|
+ else if (!strcmp("TLSv1.3", arg1)) {
|
|
+ if (cmd->path) {
|
|
+ return "TLSv1.3 ciphers cannot be set inside a directory context";
|
|
+ }
|
|
+ sc->server->auth.tls13_ciphers = arg2;
|
|
+ return NULL;
|
|
+ }
|
|
+#endif
|
|
+ return apr_pstrcat(cmd->pool, "procotol '", arg1, "' not supported", NULL);
|
|
}
|
|
|
|
#define SSL_FLAGS_CHECK_FILE \
|
|
@@ -1449,6 +1466,9 @@
|
|
else if (strcEQ(w, "TLSv1.2")) {
|
|
thisopt = SSL_PROTOCOL_TLSV1_2;
|
|
}
|
|
+ else if (SSL_HAVE_PROTOCOL_TLSV1_3 && strcEQ(w, "TLSv1.3")) {
|
|
+ thisopt = SSL_PROTOCOL_TLSV1_3;
|
|
+ }
|
|
#endif
|
|
else if (strcEQ(w, "all")) {
|
|
thisopt = SSL_PROTOCOL_ALL;
|
|
@@ -1510,16 +1530,28 @@
|
|
|
|
const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *cmd,
|
|
void *dcfg,
|
|
- const char *arg)
|
|
+ const char *arg1, const char *arg2)
|
|
{
|
|
SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
|
|
-
|
|
- /* always disable null and export ciphers */
|
|
- arg = apr_pstrcat(cmd->pool, arg, ":!aNULL:!eNULL:!EXP", NULL);
|
|
-
|
|
- dc->proxy->auth.cipher_suite = arg;
|
|
-
|
|
- return NULL;
|
|
+
|
|
+ if (arg2 == NULL) {
|
|
+ arg2 = arg1;
|
|
+ arg1 = "SSL";
|
|
+ }
|
|
+
|
|
+ if (!strcmp("SSL", arg1)) {
|
|
+ /* always disable null and export ciphers */
|
|
+ arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL);
|
|
+ dc->proxy->auth.cipher_suite = arg2;
|
|
+ return NULL;
|
|
+ }
|
|
+#if SSL_HAVE_PROTOCOL_TLSV1_3
|
|
+ else if (!strcmp("TLSv1.3", arg1)) {
|
|
+ dc->proxy->auth.tls13_ciphers = arg2;
|
|
+ return NULL;
|
|
+ }
|
|
+#endif
|
|
+ return apr_pstrcat(cmd->pool, "procotol '", arg1, "' not supported", NULL);
|
|
}
|
|
|
|
const char *ssl_cmd_SSLProxyVerify(cmd_parms *cmd,
|
|
--- httpd-2.4.34/modules/ssl/ssl_engine_init.c.r1827912+
|
|
+++ httpd-2.4.34/modules/ssl/ssl_engine_init.c
|
|
@@ -568,6 +568,9 @@
|
|
#ifdef HAVE_TLSV1_X
|
|
(protocol & SSL_PROTOCOL_TLSV1_1 ? "TLSv1.1, " : ""),
|
|
(protocol & SSL_PROTOCOL_TLSV1_2 ? "TLSv1.2, " : ""),
|
|
+#if SSL_HAVE_PROTOCOL_TLSV1_3
|
|
+ (protocol & SSL_PROTOCOL_TLSV1_3 ? "TLSv1.3, " : ""),
|
|
+#endif
|
|
#endif
|
|
NULL);
|
|
cp[strlen(cp)-2] = NUL;
|
|
@@ -600,6 +603,13 @@
|
|
TLSv1_2_client_method() : /* proxy */
|
|
TLSv1_2_server_method(); /* server */
|
|
}
|
|
+#if SSL_HAVE_PROTOCOL_TLSV1_3
|
|
+ else if (protocol == SSL_PROTOCOL_TLSV1_3) {
|
|
+ method = mctx->pkp ?
|
|
+ TLSv1_3_client_method() : /* proxy */
|
|
+ TLSv1_3_server_method(); /* server */
|
|
+ }
|
|
+#endif
|
|
#endif
|
|
else { /* For multiple protocols, we need a flexible method */
|
|
method = mctx->pkp ?
|
|
@@ -617,7 +627,8 @@
|
|
|
|
SSL_CTX_set_options(ctx, SSL_OP_ALL);
|
|
|
|
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
|
|
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20800000L)
|
|
/* always disable SSLv2, as per RFC 6176 */
|
|
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
|
|
|
|
@@ -639,10 +650,19 @@
|
|
if (!(protocol & SSL_PROTOCOL_TLSV1_2)) {
|
|
SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_2);
|
|
}
|
|
+#if SSL_HAVE_PROTOCOL_TLSV1_3
|
|
+ ssl_set_ctx_protocol_option(s, ctx, SSL_OP_NO_TLSv1_3,
|
|
+ protocol & SSL_PROTOCOL_TLSV1_3, "TLSv1.3");
|
|
+#endif
|
|
#endif
|
|
|
|
#else /* #if OPENSSL_VERSION_NUMBER < 0x10100000L */
|
|
/* We first determine the maximum protocol version we should provide */
|
|
+#if SSL_HAVE_PROTOCOL_TLSV1_3
|
|
+ if (SSL_HAVE_PROTOCOL_TLSV1_3 && (protocol & SSL_PROTOCOL_TLSV1_3)) {
|
|
+ prot = TLS1_3_VERSION;
|
|
+ } else
|
|
+#endif
|
|
if (protocol & SSL_PROTOCOL_TLSV1_2) {
|
|
prot = TLS1_2_VERSION;
|
|
} else if (protocol & SSL_PROTOCOL_TLSV1_1) {
|
|
@@ -664,6 +684,11 @@
|
|
|
|
/* Next we scan for the minimal protocol version we should provide,
|
|
* but we do not allow holes between max and min */
|
|
+#if SSL_HAVE_PROTOCOL_TLSV1_3
|
|
+ if (prot == TLS1_3_VERSION && protocol & SSL_PROTOCOL_TLSV1_2) {
|
|
+ prot = TLS1_2_VERSION;
|
|
+ }
|
|
+#endif
|
|
if (prot == TLS1_2_VERSION && protocol & SSL_PROTOCOL_TLSV1_1) {
|
|
prot = TLS1_1_VERSION;
|
|
}
|
|
@@ -736,6 +761,13 @@
|
|
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
|
|
#endif
|
|
|
|
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL
|
|
+ /* For OpenSSL >=1.1.1, disable auto-retry mode so it's possible
|
|
+ * to consume handshake records without blocking for app-data.
|
|
+ * https://github.com/openssl/openssl/issues/7178 */
|
|
+ SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY);
|
|
+#endif
|
|
+
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
@@ -888,7 +920,15 @@
|
|
ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
|
|
return ssl_die(s);
|
|
}
|
|
-
|
|
+#if SSL_HAVE_PROTOCOL_TLSV1_3
|
|
+ if (mctx->auth.tls13_ciphers
|
|
+ && !SSL_CTX_set_ciphersuites(ctx, mctx->auth.tls13_ciphers)) {
|
|
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO()
|
|
+ "Unable to configure permitted TLSv1.3 ciphers");
|
|
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
|
|
+ return ssl_die(s);
|
|
+ }
|
|
+#endif
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
@@ -1493,6 +1533,13 @@
|
|
X509_STORE_CTX *sctx;
|
|
X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx);
|
|
|
|
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL
|
|
+ /* For OpenSSL >=1.1.1, turn on client cert support which is
|
|
+ * otherwise turned off by default (by design).
|
|
+ * https://github.com/openssl/openssl/issues/6933 */
|
|
+ SSL_CTX_set_post_handshake_auth(mctx->ssl_ctx, 1);
|
|
+#endif
|
|
+
|
|
SSL_CTX_set_client_cert_cb(mctx->ssl_ctx,
|
|
ssl_callback_proxy_cert);
|
|
|
|
--- httpd-2.4.34/modules/ssl/ssl_engine_kernel.c.r1827912+
|
|
+++ httpd-2.4.34/modules/ssl/ssl_engine_kernel.c
|
|
@@ -188,6 +188,12 @@
|
|
|| strcmp(a1->cipher_suite, a2->cipher_suite))) {
|
|
return 0;
|
|
}
|
|
+ /* both have the same ca cipher suite string */
|
|
+ if ((a1->tls13_ciphers != a2->tls13_ciphers)
|
|
+ && (!a1->tls13_ciphers || !a2->tls13_ciphers
|
|
+ || strcmp(a1->tls13_ciphers, a2->tls13_ciphers))) {
|
|
+ return 0;
|
|
+ }
|
|
return 1;
|
|
}
|
|
|
|
@@ -424,87 +430,70 @@
|
|
}
|
|
}
|
|
|
|
-/*
|
|
- * Access Handler
|
|
- */
|
|
-int ssl_hook_Access(request_rec *r)
|
|
+static int ssl_check_post_client_verify(request_rec *r, SSLSrvConfigRec *sc,
|
|
+ SSLDirConfigRec *dc, SSLConnRec *sslconn,
|
|
+ SSL *ssl)
|
|
{
|
|
- SSLDirConfigRec *dc = myDirConfig(r);
|
|
- SSLSrvConfigRec *sc = mySrvConfig(r->server);
|
|
- SSLConnRec *sslconn = myConnConfig(r->connection);
|
|
- SSL *ssl = sslconn ? sslconn->ssl : NULL;
|
|
- server_rec *handshakeserver = sslconn ? sslconn->server : NULL;
|
|
- SSLSrvConfigRec *hssc = handshakeserver? mySrvConfig(handshakeserver) : NULL;
|
|
- SSL_CTX *ctx = NULL;
|
|
- apr_array_header_t *requires;
|
|
- ssl_require_t *ssl_requires;
|
|
- int ok, i;
|
|
- BOOL renegotiate = FALSE, renegotiate_quick = FALSE;
|
|
X509 *cert;
|
|
- X509 *peercert;
|
|
- X509_STORE *cert_store = NULL;
|
|
- X509_STORE_CTX *cert_store_ctx;
|
|
- STACK_OF(SSL_CIPHER) *cipher_list_old = NULL, *cipher_list = NULL;
|
|
- const SSL_CIPHER *cipher = NULL;
|
|
- int depth, verify_old, verify, n, is_slave = 0;
|
|
- const char *ncipher_suite;
|
|
-
|
|
- /* On a slave connection, we do not expect to have an SSLConnRec, but
|
|
- * our master connection might have one. */
|
|
- if (!(sslconn && ssl) && r->connection->master) {
|
|
- sslconn = myConnConfig(r->connection->master);
|
|
- ssl = sslconn ? sslconn->ssl : NULL;
|
|
- handshakeserver = sslconn ? sslconn->server : NULL;
|
|
- hssc = handshakeserver? mySrvConfig(handshakeserver) : NULL;
|
|
- is_slave = 1;
|
|
- }
|
|
|
|
- if (ssl) {
|
|
- /*
|
|
- * We should have handshaken here (on handshakeserver),
|
|
- * otherwise we are being redirected (ErrorDocument) from
|
|
- * a renegotiation failure below. The access is still
|
|
- * forbidden in the latter case, let ap_die() handle
|
|
- * this recursive (same) error.
|
|
- */
|
|
- if (!SSL_is_init_finished(ssl)) {
|
|
- return HTTP_FORBIDDEN;
|
|
+ /*
|
|
+ * Remember the peer certificate's DN
|
|
+ */
|
|
+ if ((cert = SSL_get_peer_certificate(ssl))) {
|
|
+ if (sslconn->client_cert) {
|
|
+ X509_free(sslconn->client_cert);
|
|
}
|
|
- ctx = SSL_get_SSL_CTX(ssl);
|
|
+ sslconn->client_cert = cert;
|
|
+ sslconn->client_dn = NULL;
|
|
}
|
|
-
|
|
+
|
|
/*
|
|
- * Support for SSLRequireSSL directive
|
|
+ * Finally check for acceptable renegotiation results
|
|
*/
|
|
- if (dc->bSSLRequired && !ssl) {
|
|
- if ((sc->enabled == SSL_ENABLED_OPTIONAL) && !is_slave) {
|
|
- /* This vhost was configured for optional SSL, just tell the
|
|
- * client that we need to upgrade.
|
|
- */
|
|
- apr_table_setn(r->err_headers_out, "Upgrade", "TLS/1.0, HTTP/1.1");
|
|
- apr_table_setn(r->err_headers_out, "Connection", "Upgrade");
|
|
+ if ((dc->nVerifyClient != SSL_CVERIFY_NONE) ||
|
|
+ (sc->server->auth.verify_mode != SSL_CVERIFY_NONE)) {
|
|
+ BOOL do_verify = ((dc->nVerifyClient == SSL_CVERIFY_REQUIRE) ||
|
|
+ (sc->server->auth.verify_mode == SSL_CVERIFY_REQUIRE));
|
|
+
|
|
+ if (do_verify && (SSL_get_verify_result(ssl) != X509_V_OK)) {
|
|
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02262)
|
|
+ "Re-negotiation handshake failed: "
|
|
+ "Client verification failed");
|
|
|
|
- return HTTP_UPGRADE_REQUIRED;
|
|
+ return HTTP_FORBIDDEN;
|
|
}
|
|
|
|
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02219)
|
|
- "access to %s failed, reason: %s",
|
|
- r->filename, "SSL connection required");
|
|
-
|
|
- /* remember forbidden access for strict require option */
|
|
- apr_table_setn(r->notes, "ssl-access-forbidden", "1");
|
|
+ if (do_verify) {
|
|
+ if (cert == NULL) {
|
|
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02263)
|
|
+ "Re-negotiation handshake failed: "
|
|
+ "Client certificate missing");
|
|
|
|
- return HTTP_FORBIDDEN;
|
|
+ return HTTP_FORBIDDEN;
|
|
+ }
|
|
+ }
|
|
}
|
|
+ return OK;
|
|
+}
|
|
|
|
- /*
|
|
- * Check to see whether SSL is in use; if it's not, then no
|
|
- * further access control checks are relevant. (the test for
|
|
- * sc->enabled is probably strictly unnecessary)
|
|
- */
|
|
- if (sc->enabled == SSL_ENABLED_FALSE || !ssl) {
|
|
- return DECLINED;
|
|
- }
|
|
+/*
|
|
+ * Access Handler, classic flavour, for SSL/TLS up to v1.2
|
|
+ * where everything can be renegotiated and no one is happy.
|
|
+ */
|
|
+static int ssl_hook_Access_classic(request_rec *r, SSLSrvConfigRec *sc, SSLDirConfigRec *dc,
|
|
+ SSLConnRec *sslconn, SSL *ssl)
|
|
+{
|
|
+ server_rec *handshakeserver = sslconn ? sslconn->server : NULL;
|
|
+ SSLSrvConfigRec *hssc = handshakeserver? mySrvConfig(handshakeserver) : NULL;
|
|
+ SSL_CTX *ctx = NULL;
|
|
+ BOOL renegotiate = FALSE, renegotiate_quick = FALSE;
|
|
+ X509 *peercert;
|
|
+ X509_STORE *cert_store = NULL;
|
|
+ X509_STORE_CTX *cert_store_ctx;
|
|
+ STACK_OF(SSL_CIPHER) *cipher_list_old = NULL, *cipher_list = NULL;
|
|
+ const SSL_CIPHER *cipher = NULL;
|
|
+ int depth, verify_old, verify, n, rc;
|
|
+ const char *ncipher_suite;
|
|
|
|
#ifdef HAVE_SRP
|
|
/*
|
|
@@ -581,7 +570,7 @@
|
|
}
|
|
|
|
/* configure new state */
|
|
- if (is_slave) {
|
|
+ if (r->connection->master) {
|
|
/* TODO: this categorically fails changed cipher suite settings
|
|
* on slave connections. We could do better by
|
|
* - create a new SSL* from our SSL_CTX and set cipher suite there,
|
|
@@ -659,7 +648,7 @@
|
|
}
|
|
|
|
if (renegotiate) {
|
|
- if (is_slave) {
|
|
+ if (r->connection->master) {
|
|
/* The request causes renegotiation on a slave connection.
|
|
* This is not allowed since we might have concurrent requests
|
|
* on this connection.
|
|
@@ -732,7 +721,7 @@
|
|
(verify & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)))
|
|
{
|
|
renegotiate = TRUE;
|
|
- if (is_slave) {
|
|
+ if (r->connection->master) {
|
|
/* The request causes renegotiation on a slave connection.
|
|
* This is not allowed since we might have concurrent requests
|
|
* on this connection.
|
|
@@ -885,6 +874,7 @@
|
|
|
|
if (renegotiate_quick) {
|
|
STACK_OF(X509) *cert_stack;
|
|
+ X509 *cert;
|
|
|
|
/* perform just a manual re-verification of the peer */
|
|
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02258)
|
|
@@ -1037,43 +1027,10 @@
|
|
}
|
|
|
|
/*
|
|
- * Remember the peer certificate's DN
|
|
- */
|
|
- if ((cert = SSL_get_peer_certificate(ssl))) {
|
|
- if (sslconn->client_cert) {
|
|
- X509_free(sslconn->client_cert);
|
|
- }
|
|
- sslconn->client_cert = cert;
|
|
- sslconn->client_dn = NULL;
|
|
- }
|
|
-
|
|
- /*
|
|
* Finally check for acceptable renegotiation results
|
|
*/
|
|
- if ((dc->nVerifyClient != SSL_CVERIFY_NONE) ||
|
|
- (sc->server->auth.verify_mode != SSL_CVERIFY_NONE)) {
|
|
- BOOL do_verify = ((dc->nVerifyClient == SSL_CVERIFY_REQUIRE) ||
|
|
- (sc->server->auth.verify_mode == SSL_CVERIFY_REQUIRE));
|
|
-
|
|
- if (do_verify && (SSL_get_verify_result(ssl) != X509_V_OK)) {
|
|
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02262)
|
|
- "Re-negotiation handshake failed: "
|
|
- "Client verification failed");
|
|
-
|
|
- return HTTP_FORBIDDEN;
|
|
- }
|
|
-
|
|
- if (do_verify) {
|
|
- if ((peercert = SSL_get_peer_certificate(ssl)) == NULL) {
|
|
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02263)
|
|
- "Re-negotiation handshake failed: "
|
|
- "Client certificate missing");
|
|
-
|
|
- return HTTP_FORBIDDEN;
|
|
- }
|
|
-
|
|
- X509_free(peercert);
|
|
- }
|
|
+ if (OK != (rc = ssl_check_post_client_verify(r, sc, dc, sslconn, ssl))) {
|
|
+ return rc;
|
|
}
|
|
|
|
/*
|
|
@@ -1096,6 +1053,215 @@
|
|
}
|
|
}
|
|
|
|
+ return DECLINED;
|
|
+}
|
|
+
|
|
+#if SSL_HAVE_PROTOCOL_TLSV1_3
|
|
+/*
|
|
+ * Access Handler, modern flavour, for SSL/TLS v1.3 and onward.
|
|
+ * Only client certificates can be requested, everything else stays.
|
|
+ */
|
|
+static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirConfigRec *dc,
|
|
+ SSLConnRec *sslconn, SSL *ssl)
|
|
+{
|
|
+ if ((dc->nVerifyClient != SSL_CVERIFY_UNSET) ||
|
|
+ (sc->server->auth.verify_mode != SSL_CVERIFY_UNSET)) {
|
|
+ int vmode_inplace, vmode_needed;
|
|
+ int change_vmode = FALSE;
|
|
+ int old_state, n, rc;
|
|
+
|
|
+ vmode_inplace = SSL_get_verify_mode(ssl);
|
|
+ vmode_needed = SSL_VERIFY_NONE;
|
|
+
|
|
+ if ((dc->nVerifyClient == SSL_CVERIFY_REQUIRE) ||
|
|
+ (sc->server->auth.verify_mode == SSL_CVERIFY_REQUIRE)) {
|
|
+ vmode_needed |= SSL_VERIFY_PEER_STRICT;
|
|
+ }
|
|
+
|
|
+ if ((dc->nVerifyClient == SSL_CVERIFY_OPTIONAL) ||
|
|
+ (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA) ||
|
|
+ (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL) ||
|
|
+ (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA))
|
|
+ {
|
|
+ vmode_needed |= SSL_VERIFY_PEER;
|
|
+ }
|
|
+
|
|
+ if (vmode_needed == SSL_VERIFY_NONE) {
|
|
+ return DECLINED;
|
|
+ }
|
|
+
|
|
+ vmode_needed |= SSL_VERIFY_CLIENT_ONCE;
|
|
+ if (vmode_inplace != vmode_needed) {
|
|
+ /* Need to change, if new setting is more restrictive than existing one */
|
|
+
|
|
+ if ((vmode_inplace == SSL_VERIFY_NONE)
|
|
+ || (!(vmode_inplace & SSL_VERIFY_PEER)
|
|
+ && (vmode_needed & SSL_VERIFY_PEER))
|
|
+ || (!(vmode_inplace & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
|
|
+ && (vmode_needed & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))) {
|
|
+ /* need to change the effective verify mode */
|
|
+ change_vmode = TRUE;
|
|
+ }
|
|
+ else {
|
|
+ /* FIXME: does this work with TLSv1.3? Is this more than re-inspecting
|
|
+ * the certificate we should already have? */
|
|
+ /*
|
|
+ * override of SSLVerifyDepth
|
|
+ *
|
|
+ * The depth checks are handled by us manually inside the
|
|
+ * verify callback function and not by OpenSSL internally
|
|
+ * (and our function is aware of both the per-server and
|
|
+ * per-directory contexts). So we cannot ask OpenSSL about
|
|
+ * the currently verify depth. Instead we remember it in our
|
|
+ * SSLConnRec attached to the SSL* of OpenSSL. We've to force
|
|
+ * the renegotiation if the reconfigured/new verify depth is
|
|
+ * less than the currently active/remembered verify depth
|
|
+ * (because this means more restriction on the certificate
|
|
+ * chain).
|
|
+ */
|
|
+ n = (sslconn->verify_depth != UNSET)?
|
|
+ sslconn->verify_depth : sc->server->auth.verify_depth;
|
|
+ /* determine the new depth */
|
|
+ sslconn->verify_depth = (dc->nVerifyDepth != UNSET)
|
|
+ ? dc->nVerifyDepth
|
|
+ : sc->server->auth.verify_depth;
|
|
+ if (sslconn->verify_depth < n) {
|
|
+ change_vmode = TRUE;
|
|
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO()
|
|
+ "Reduced client verification depth will "
|
|
+ "force renegotiation");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (change_vmode) {
|
|
+ char peekbuf[1];
|
|
+
|
|
+ if (r->connection->master) {
|
|
+ /* FIXME: modifying the SSL on a slave connection is no good.
|
|
+ * We would need to push this back to the master connection
|
|
+ * somehow.
|
|
+ */
|
|
+ apr_table_setn(r->notes, "ssl-renegotiate-forbidden", "verify-client");
|
|
+ return HTTP_FORBIDDEN;
|
|
+ }
|
|
+
|
|
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO() "verify client post handshake");
|
|
+
|
|
+ SSL_set_verify(ssl, vmode_needed, ssl_callback_SSLVerify);
|
|
+
|
|
+ if (SSL_verify_client_post_handshake(ssl) != 1) {
|
|
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10158)
|
|
+ "cannot perform post-handshake authentication");
|
|
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, r->server);
|
|
+ apr_table_setn(r->notes, "error-notes",
|
|
+ "Reason: Cannot perform Post-Handshake Authentication.<br />");
|
|
+ return HTTP_FORBIDDEN;
|
|
+ }
|
|
+
|
|
+ old_state = sslconn->reneg_state;
|
|
+ sslconn->reneg_state = RENEG_ALLOW;
|
|
+ modssl_set_app_data2(ssl, r);
|
|
+
|
|
+ SSL_do_handshake(ssl);
|
|
+ /* Need to trigger renegotiation handshake by reading.
|
|
+ * Peeking 0 bytes actually works.
|
|
+ * See: http://marc.info/?t=145493359200002&r=1&w=2
|
|
+ */
|
|
+ SSL_peek(ssl, peekbuf, 0);
|
|
+
|
|
+ sslconn->reneg_state = old_state;
|
|
+ modssl_set_app_data2(ssl, NULL);
|
|
+
|
|
+ /*
|
|
+ * Finally check for acceptable renegotiation results
|
|
+ */
|
|
+ if (OK != (rc = ssl_check_post_client_verify(r, sc, dc, sslconn, ssl))) {
|
|
+ return rc;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return DECLINED;
|
|
+}
|
|
+#endif
|
|
+
|
|
+int ssl_hook_Access(request_rec *r)
|
|
+{
|
|
+ SSLDirConfigRec *dc = myDirConfig(r);
|
|
+ SSLSrvConfigRec *sc = mySrvConfig(r->server);
|
|
+ SSLConnRec *sslconn = myConnConfig(r->connection);
|
|
+ SSL *ssl = sslconn ? sslconn->ssl : NULL;
|
|
+ apr_array_header_t *requires;
|
|
+ ssl_require_t *ssl_requires;
|
|
+ int ok, i, ret;
|
|
+
|
|
+ /* On a slave connection, we do not expect to have an SSLConnRec, but
|
|
+ * our master connection might have one. */
|
|
+ if (!(sslconn && ssl) && r->connection->master) {
|
|
+ sslconn = myConnConfig(r->connection->master);
|
|
+ ssl = sslconn ? sslconn->ssl : NULL;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * We should have handshaken here, otherwise we are being
|
|
+ * redirected (ErrorDocument) from a renegotiation failure below.
|
|
+ * The access is still forbidden in the latter case, let ap_die() handle
|
|
+ * this recursive (same) error.
|
|
+ */
|
|
+ if (ssl && !SSL_is_init_finished(ssl)) {
|
|
+ return HTTP_FORBIDDEN;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Support for SSLRequireSSL directive
|
|
+ */
|
|
+ if (dc->bSSLRequired && !ssl) {
|
|
+ if ((sc->enabled == SSL_ENABLED_OPTIONAL) && !r->connection->master) {
|
|
+ /* This vhost was configured for optional SSL, just tell the
|
|
+ * client that we need to upgrade.
|
|
+ */
|
|
+ apr_table_setn(r->err_headers_out, "Upgrade", "TLS/1.0, HTTP/1.1");
|
|
+ apr_table_setn(r->err_headers_out, "Connection", "Upgrade");
|
|
+
|
|
+ return HTTP_UPGRADE_REQUIRED;
|
|
+ }
|
|
+
|
|
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02219)
|
|
+ "access to %s failed, reason: %s",
|
|
+ r->filename, "SSL connection required");
|
|
+
|
|
+ /* remember forbidden access for strict require option */
|
|
+ apr_table_setn(r->notes, "ssl-access-forbidden", "1");
|
|
+
|
|
+ return HTTP_FORBIDDEN;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Check to see whether SSL is in use; if it's not, then no
|
|
+ * further access control checks are relevant. (the test for
|
|
+ * sc->enabled is probably strictly unnecessary)
|
|
+ */
|
|
+ if (sc->enabled == SSL_ENABLED_FALSE || !ssl) {
|
|
+ return DECLINED;
|
|
+ }
|
|
+
|
|
+#if SSL_HAVE_PROTOCOL_TLSV1_3
|
|
+ /* TLSv1.3+ is less complicated here. Branch off into a new codeline
|
|
+ * and avoid messing with the past. */
|
|
+ if (SSL_version(ssl) >= TLS1_3_VERSION) {
|
|
+ ret = ssl_hook_Access_modern(r, sc, dc, sslconn, ssl);
|
|
+ }
|
|
+ else
|
|
+#endif
|
|
+ {
|
|
+ ret = ssl_hook_Access_classic(r, sc, dc, sslconn, ssl);
|
|
+ }
|
|
+
|
|
+ if (ret != DECLINED) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
/* If we're trying to have the user name set from a client
|
|
* certificate then we need to set it here. This should be safe as
|
|
* the user name probably isn't important from an auth checking point
|
|
@@ -2080,31 +2246,43 @@
|
|
{
|
|
conn_rec *c;
|
|
server_rec *s;
|
|
- SSLConnRec *scr;
|
|
|
|
/* Retrieve the conn_rec and the associated SSLConnRec. */
|
|
if ((c = (conn_rec *)SSL_get_app_data((SSL *)ssl)) == NULL) {
|
|
return;
|
|
}
|
|
|
|
- if ((scr = myConnConfig(c)) == NULL) {
|
|
- return;
|
|
- }
|
|
+ /* With TLS 1.3 this callback may be called multiple times on the first
|
|
+ * negotiation, so the below logic to detect renegotiations can't work.
|
|
+ * Fortunately renegotiations are forbidden starting with TLS 1.3, and
|
|
+ * this is enforced by OpenSSL so there's nothing to be done here.
|
|
+ */
|
|
+#if SSL_HAVE_PROTOCOL_TLSV1_3
|
|
+ if (SSL_version(ssl) < TLS1_3_VERSION)
|
|
+#endif
|
|
+ {
|
|
+ SSLConnRec *sslconn;
|
|
+
|
|
+ if ((sslconn = myConnConfig(c)) == NULL) {
|
|
+ return;
|
|
+ }
|
|
|
|
- /* If the reneg state is to reject renegotiations, check the SSL
|
|
- * state machine and move to ABORT if a Client Hello is being
|
|
- * read. */
|
|
- if (!scr->is_proxy &&
|
|
- (where & SSL_CB_HANDSHAKE_START) &&
|
|
- scr->reneg_state == RENEG_REJECT) {
|
|
- scr->reneg_state = RENEG_ABORT;
|
|
+ /* If the reneg state is to reject renegotiations, check the SSL
|
|
+ * state machine and move to ABORT if a Client Hello is being
|
|
+ * read. */
|
|
+ if (!sslconn->is_proxy &&
|
|
+ (where & SSL_CB_HANDSHAKE_START) &&
|
|
+ sslconn->reneg_state == RENEG_REJECT) {
|
|
+ sslconn->reneg_state = RENEG_ABORT;
|
|
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02042)
|
|
"rejecting client initiated renegotiation");
|
|
- }
|
|
- /* If the first handshake is complete, change state to reject any
|
|
- * subsequent client-initiated renegotiation. */
|
|
- else if ((where & SSL_CB_HANDSHAKE_DONE) && scr->reneg_state == RENEG_INIT) {
|
|
- scr->reneg_state = RENEG_REJECT;
|
|
+ }
|
|
+ /* If the first handshake is complete, change state to reject any
|
|
+ * subsequent client-initiated renegotiation. */
|
|
+ else if ((where & SSL_CB_HANDSHAKE_DONE)
|
|
+ && sslconn->reneg_state == RENEG_INIT) {
|
|
+ sslconn->reneg_state = RENEG_REJECT;
|
|
+ }
|
|
}
|
|
|
|
s = mySrvFromConn(c);
|
|
--- httpd-2.4.34/modules/ssl/ssl_private.h.r1827912+
|
|
+++ httpd-2.4.34/modules/ssl/ssl_private.h
|
|
@@ -132,13 +132,14 @@
|
|
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, NULL)
|
|
#define SSL_CTX_set_max_proto_version(ctx, version) \
|
|
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, NULL)
|
|
-#endif
|
|
-/* LibreSSL declares OPENSSL_VERSION_NUMBER == 2.0 but does not include most
|
|
- * changes from OpenSSL >= 1.1 (new functions, macros, deprecations, ...), so
|
|
- * we have to work around this...
|
|
+#elif LIBRESSL_VERSION_NUMBER < 0x2070000f
|
|
+/* LibreSSL before 2.7 declares OPENSSL_VERSION_NUMBER == 2.0 but does not
|
|
+ * include most changes from OpenSSL >= 1.1 (new functions, macros,
|
|
+ * deprecations, ...), so we have to work around this...
|
|
*/
|
|
#define MODSSL_USE_OPENSSL_PRE_1_1_API (1)
|
|
-#else
|
|
+#endif /* LIBRESSL_VERSION_NUMBER < 0x2060000f */
|
|
+#else /* defined(LIBRESSL_VERSION_NUMBER) */
|
|
#define MODSSL_USE_OPENSSL_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
|
|
#endif
|
|
|
|
@@ -238,7 +239,8 @@
|
|
void free_bio_methods(void);
|
|
#endif
|
|
|
|
-#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
|
|
+#if OPENSSL_VERSION_NUMBER < 0x10002000L || \
|
|
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000f)
|
|
#define X509_STORE_CTX_get0_store(x) (x->ctx)
|
|
#endif
|
|
|
|
@@ -372,8 +374,17 @@
|
|
#ifdef HAVE_TLSV1_X
|
|
#define SSL_PROTOCOL_TLSV1_1 (1<<3)
|
|
#define SSL_PROTOCOL_TLSV1_2 (1<<4)
|
|
+#define SSL_PROTOCOL_TLSV1_3 (1<<5)
|
|
+
|
|
+#ifdef SSL_OP_NO_TLSv1_3
|
|
+#define SSL_HAVE_PROTOCOL_TLSV1_3 (1)
|
|
+#define SSL_PROTOCOL_ALL (SSL_PROTOCOL_BASIC| \
|
|
+ SSL_PROTOCOL_TLSV1_1|SSL_PROTOCOL_TLSV1_2|SSL_PROTOCOL_TLSV1_3)
|
|
+#else
|
|
+#define SSL_HAVE_PROTOCOL_TLSV1_3 (0)
|
|
#define SSL_PROTOCOL_ALL (SSL_PROTOCOL_BASIC| \
|
|
SSL_PROTOCOL_TLSV1_1|SSL_PROTOCOL_TLSV1_2)
|
|
+#endif
|
|
#else
|
|
#define SSL_PROTOCOL_ALL (SSL_PROTOCOL_BASIC)
|
|
#endif
|
|
@@ -646,6 +657,11 @@
|
|
/** for client or downstream server authentication */
|
|
int verify_depth;
|
|
ssl_verify_t verify_mode;
|
|
+
|
|
+ /** TLSv1.3 has its separate cipher list, separate from the
|
|
+ settings for older TLS protocol versions. Since which one takes
|
|
+ effect is a matter of negotiation, we need separate settings */
|
|
+ const char *tls13_ciphers;
|
|
} modssl_auth_ctx_t;
|
|
|
|
#ifdef HAVE_TLS_SESSION_TICKETS
|
|
@@ -801,7 +817,7 @@
|
|
const char *ssl_cmd_SSLCryptoDevice(cmd_parms *, void *, const char *);
|
|
const char *ssl_cmd_SSLRandomSeed(cmd_parms *, void *, const char *, const char *, const char *);
|
|
const char *ssl_cmd_SSLEngine(cmd_parms *, void *, const char *);
|
|
-const char *ssl_cmd_SSLCipherSuite(cmd_parms *, void *, const char *);
|
|
+const char *ssl_cmd_SSLCipherSuite(cmd_parms *, void *, const char *, const char *);
|
|
const char *ssl_cmd_SSLCertificateFile(cmd_parms *, void *, const char *);
|
|
const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *, void *, const char *);
|
|
const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *, void *, const char *);
|
|
@@ -830,7 +846,7 @@
|
|
|
|
const char *ssl_cmd_SSLProxyEngine(cmd_parms *cmd, void *dcfg, int flag);
|
|
const char *ssl_cmd_SSLProxyProtocol(cmd_parms *, void *, const char *);
|
|
-const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *, void *, const char *);
|
|
+const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *, void *, const char *, const char *);
|
|
const char *ssl_cmd_SSLProxyVerify(cmd_parms *, void *, const char *);
|
|
const char *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *, void *, const char *);
|
|
const char *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *, void *, const char *);
|