You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
249 lines
9.1 KiB
249 lines
9.1 KiB
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c |
|
index 211ebff..c8cb1af 100644 |
|
--- a/modules/ssl/ssl_engine_init.c |
|
+++ b/modules/ssl/ssl_engine_init.c |
|
@@ -871,6 +871,13 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, |
|
SSL_CTX_set_keylog_callback(ctx, modssl_callback_keylog); |
|
} |
|
#endif |
|
+ |
|
+#ifdef SSL_OP_NO_RENEGOTIATION |
|
+ /* For server-side SSL_CTX, disable renegotiation by default.. */ |
|
+ if (!mctx->pkp) { |
|
+ SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); |
|
+ } |
|
+#endif |
|
|
|
return APR_SUCCESS; |
|
} |
|
@@ -892,6 +899,14 @@ static void ssl_init_ctx_session_cache(server_rec *s, |
|
} |
|
} |
|
|
|
+#ifdef SSL_OP_NO_RENEGOTIATION |
|
+/* OpenSSL-level renegotiation protection. */ |
|
+#define MODSSL_BLOCKS_RENEG (0) |
|
+#else |
|
+/* mod_ssl-level renegotiation protection. */ |
|
+#define MODSSL_BLOCKS_RENEG (1) |
|
+#endif |
|
+ |
|
static void ssl_init_ctx_callbacks(server_rec *s, |
|
apr_pool_t *p, |
|
apr_pool_t *ptemp, |
|
@@ -905,7 +920,13 @@ static void ssl_init_ctx_callbacks(server_rec *s, |
|
SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH); |
|
#endif |
|
|
|
- SSL_CTX_set_info_callback(ctx, ssl_callback_Info); |
|
+ /* The info callback is used for debug-level tracing. For OpenSSL |
|
+ * versions where SSL_OP_NO_RENEGOTIATION is not available, the |
|
+ * callback is also used to prevent use of client-initiated |
|
+ * renegotiation. Enable it in either case. */ |
|
+ if (APLOGdebug(s) || MODSSL_BLOCKS_RENEG) { |
|
+ SSL_CTX_set_info_callback(ctx, ssl_callback_Info); |
|
+ } |
|
|
|
#ifdef HAVE_TLS_ALPN |
|
SSL_CTX_set_alpn_select_cb(ctx, ssl_callback_alpn_select, NULL); |
|
diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c |
|
index 79b9a70..3a0c22a 100644 |
|
--- a/modules/ssl/ssl_engine_io.c |
|
+++ b/modules/ssl/ssl_engine_io.c |
|
@@ -209,11 +209,13 @@ static int bio_filter_out_write(BIO *bio, const char *in, int inl) |
|
|
|
BIO_clear_retry_flags(bio); |
|
|
|
+#ifndef SSL_OP_NO_RENEGOTIATION |
|
/* Abort early if the client has initiated a renegotiation. */ |
|
if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) { |
|
outctx->rc = APR_ECONNABORTED; |
|
return -1; |
|
} |
|
+#endif |
|
|
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE6, 0, outctx->c, |
|
"bio_filter_out_write: %i bytes", inl); |
|
@@ -474,11 +476,13 @@ static int bio_filter_in_read(BIO *bio, char *in, int inlen) |
|
|
|
BIO_clear_retry_flags(bio); |
|
|
|
+#ifndef SSL_OP_NO_RENEGOTIATION |
|
/* Abort early if the client has initiated a renegotiation. */ |
|
if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) { |
|
inctx->rc = APR_ECONNABORTED; |
|
return -1; |
|
} |
|
+#endif |
|
|
|
if (!inctx->bb) { |
|
inctx->rc = APR_EOF; |
|
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c |
|
index 591f6ae..8416864 100644 |
|
--- a/modules/ssl/ssl_engine_kernel.c |
|
+++ b/modules/ssl/ssl_engine_kernel.c |
|
@@ -992,7 +992,7 @@ static int ssl_hook_Access_classic(request_rec *r, SSLSrvConfigRec *sc, SSLDirCo |
|
|
|
/* Toggle the renegotiation state to allow the new |
|
* handshake to proceed. */ |
|
- sslconn->reneg_state = RENEG_ALLOW; |
|
+ modssl_set_reneg_state(sslconn, RENEG_ALLOW); |
|
|
|
SSL_renegotiate(ssl); |
|
SSL_do_handshake(ssl); |
|
@@ -1019,7 +1019,7 @@ static int ssl_hook_Access_classic(request_rec *r, SSLSrvConfigRec *sc, SSLDirCo |
|
*/ |
|
SSL_peek(ssl, peekbuf, 0); |
|
|
|
- sslconn->reneg_state = RENEG_REJECT; |
|
+ modssl_set_reneg_state(sslconn, RENEG_REJECT); |
|
|
|
if (!SSL_is_init_finished(ssl)) { |
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02261) |
|
@@ -1078,7 +1078,7 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon |
|
(sc->server->auth.verify_mode != SSL_CVERIFY_UNSET)) { |
|
int vmode_inplace, vmode_needed; |
|
int change_vmode = FALSE; |
|
- int old_state, n, rc; |
|
+ int n, rc; |
|
|
|
vmode_inplace = SSL_get_verify_mode(ssl); |
|
vmode_needed = SSL_VERIFY_NONE; |
|
@@ -1180,8 +1180,6 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon |
|
return HTTP_FORBIDDEN; |
|
} |
|
|
|
- old_state = sslconn->reneg_state; |
|
- sslconn->reneg_state = RENEG_ALLOW; |
|
modssl_set_app_data2(ssl, r); |
|
|
|
SSL_do_handshake(ssl); |
|
@@ -1191,7 +1189,6 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon |
|
*/ |
|
SSL_peek(ssl, peekbuf, 0); |
|
|
|
- sslconn->reneg_state = old_state; |
|
modssl_set_app_data2(ssl, NULL); |
|
|
|
/* |
|
@@ -2263,8 +2260,8 @@ static void log_tracing_state(const SSL *ssl, conn_rec *c, |
|
/* |
|
* This callback function is executed while OpenSSL processes the SSL |
|
* handshake and does SSL record layer stuff. It's used to trap |
|
- * client-initiated renegotiations, and for dumping everything to the |
|
- * log. |
|
+ * client-initiated renegotiations (where SSL_OP_NO_RENEGOTIATION is |
|
+ * not available), and for dumping everything to the log. |
|
*/ |
|
void ssl_callback_Info(const SSL *ssl, int where, int rc) |
|
{ |
|
@@ -2276,14 +2273,12 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc) |
|
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 |
|
+#ifndef SSL_OP_NO_RENEGOTIATION |
|
+ /* With OpenSSL < 1.1.1 (implying TLS v1.2 or earlier), this |
|
+ * callback is used to block client-initiated renegotiation. With |
|
+ * TLSv1.3 it is unnecessary since renegotiation is forbidden at |
|
+ * protocol level. Otherwise (TLSv1.2 with OpenSSL >=1.1.1), |
|
+ * SSL_OP_NO_RENEGOTIATION is used to block renegotiation. */ |
|
{ |
|
SSLConnRec *sslconn; |
|
|
|
@@ -2308,6 +2303,7 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc) |
|
sslconn->reneg_state = RENEG_REJECT; |
|
} |
|
} |
|
+#endif |
|
|
|
s = mySrvFromConn(c); |
|
if (s && APLOGdebug(s)) { |
|
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h |
|
index a329d99..7666c31 100644 |
|
--- a/modules/ssl/ssl_private.h |
|
+++ b/modules/ssl/ssl_private.h |
|
@@ -512,6 +512,16 @@ typedef struct { |
|
apr_time_t source_mtime; |
|
} ssl_asn1_t; |
|
|
|
+typedef enum { |
|
+ RENEG_INIT = 0, /* Before initial handshake */ |
|
+ RENEG_REJECT, /* After initial handshake; any client-initiated |
|
+ * renegotiation should be rejected */ |
|
+ RENEG_ALLOW, /* A server-initiated renegotiation is taking |
|
+ * place (as dictated by configuration) */ |
|
+ RENEG_ABORT /* Renegotiation initiated by client, abort the |
|
+ * connection */ |
|
+} modssl_reneg_state; |
|
+ |
|
/** |
|
* Define the mod_ssl per-module configuration structure |
|
* (i.e. the global configuration for each httpd process) |
|
@@ -543,18 +553,13 @@ typedef struct { |
|
NON_SSL_SET_ERROR_MSG /* Need to set the error message */ |
|
} non_ssl_request; |
|
|
|
- /* Track the handshake/renegotiation state for the connection so |
|
- * that all client-initiated renegotiations can be rejected, as a |
|
- * partial fix for CVE-2009-3555. */ |
|
- enum { |
|
- RENEG_INIT = 0, /* Before initial handshake */ |
|
- RENEG_REJECT, /* After initial handshake; any client-initiated |
|
- * renegotiation should be rejected */ |
|
- RENEG_ALLOW, /* A server-initiated renegotiation is taking |
|
- * place (as dictated by configuration) */ |
|
- RENEG_ABORT /* Renegotiation initiated by client, abort the |
|
- * connection */ |
|
- } reneg_state; |
|
+#ifndef SSL_OP_NO_RENEGOTIATION |
|
+ /* For OpenSSL < 1.1.1, track the handshake/renegotiation state |
|
+ * for the connection to block client-initiated renegotiations. |
|
+ * For OpenSSL >=1.1.1, the SSL_OP_NO_RENEGOTIATION flag is used in |
|
+ * the SSL * options state with equivalent effect. */ |
|
+ modssl_reneg_state reneg_state; |
|
+#endif |
|
|
|
server_rec *server; |
|
SSLDirConfigRec *dc; |
|
@@ -1158,6 +1163,9 @@ int ssl_is_challenge(conn_rec *c, const char *servername, |
|
* the configured ENGINE. */ |
|
int modssl_is_engine_id(const char *name); |
|
|
|
+/* Set the renegotation state for connection. */ |
|
+void modssl_set_reneg_state(SSLConnRec *sslconn, modssl_reneg_state state); |
|
+ |
|
#endif /* SSL_PRIVATE_H */ |
|
/** @} */ |
|
|
|
diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c |
|
index 38079a9..dafb833 100644 |
|
--- a/modules/ssl/ssl_util_ssl.c |
|
+++ b/modules/ssl/ssl_util_ssl.c |
|
@@ -589,3 +589,19 @@ cleanup: |
|
} |
|
return rv; |
|
} |
|
+ |
|
+void modssl_set_reneg_state(SSLConnRec *sslconn, modssl_reneg_state state) |
|
+{ |
|
+#ifdef SSL_OP_NO_RENEGOTIATION |
|
+ switch (state) { |
|
+ case RENEG_ALLOW: |
|
+ SSL_clear_options(sslconn->ssl, SSL_OP_NO_RENEGOTIATION); |
|
+ break; |
|
+ default: |
|
+ SSL_set_options(sslconn->ssl, SSL_OP_NO_RENEGOTIATION); |
|
+ break; |
|
+ } |
|
+#else |
|
+ sslconn->reneg_state = state; |
|
+#endif |
|
+}
|
|
|