Skip to content

Commit 5196a86

Browse files
committed
mod_ssl: Switch to using SSL_OP_NO_RENEGOTATION (where available) to
block client-initiated renegotiation with TLSv1.2 and earlier. * modules/ssl/ssl_private.h: Define modssl_reneg_state enum, modssl_set_reneg_state function. * modules/ssl/ssl_engine_io.c (bio_filter_out_write, bio_filter_in_read): #ifdef-out reneg protection if SSL_OP_NO_RENEGOTATION is defined. * modules/ssl/ssl_engine_init.c (ssl_init_ctx_protocol): Enable SSL_OP_NO_RENEGOTATION. (ssl_init_ctx_callbacks): Only enable the "info" callback if debug-level logging *or* OpenSSL doesn't support SSL_OP_NO_RENEGOTATION. * modules/ssl/ssl_engine_kernel.c (ssl_hook_Access_classic): Use modssl_set_reneg_state to set the reneg protection mode. (ssl_hook_Access_modern): Drop manipulation of the reneg mode which does nothing for TLSv1.3 already. (ssl_callback_Info): Only enable reneg protection if SSL_OP_NO_RENEGOTATION is *not* defined. * modules/ssl/ssl_util_ssl.c (modssl_set_reneg_state): New function. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1877397 13f79535-47bb-0310-9956-ffa450edef68 (cherry picked from commit b8155f3)
1 parent 4451d47 commit 5196a86

File tree

5 files changed

+74
-29
lines changed

5 files changed

+74
-29
lines changed

modules/ssl/ssl_engine_init.c

+22-1
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,13 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s,
844844
}
845845
#endif
846846

847+
#ifdef SSL_OP_NO_RENEGOTIATION
848+
/* For server-side SSL_CTX, disable renegotiation by default.. */
849+
if (!mctx->pkp) {
850+
SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION);
851+
}
852+
#endif
853+
847854
#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
848855
/* For server-side SSL_CTX, enable ignoring unexpected EOF */
849856
/* (OpenSSL 1.1.1 behavioural compatibility).. */
@@ -872,6 +879,14 @@ static void ssl_init_ctx_session_cache(server_rec *s,
872879
}
873880
}
874881

882+
#ifdef SSL_OP_NO_RENEGOTIATION
883+
/* OpenSSL-level renegotiation protection. */
884+
#define MODSSL_BLOCKS_RENEG (0)
885+
#else
886+
/* mod_ssl-level renegotiation protection. */
887+
#define MODSSL_BLOCKS_RENEG (1)
888+
#endif
889+
875890
static void ssl_init_ctx_callbacks(server_rec *s,
876891
apr_pool_t *p,
877892
apr_pool_t *ptemp,
@@ -885,7 +900,13 @@ static void ssl_init_ctx_callbacks(server_rec *s,
885900
SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH);
886901
#endif
887902

888-
SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
903+
/* The info callback is used for debug-level tracing. For OpenSSL
904+
* versions where SSL_OP_NO_RENEGOTIATION is not available, the
905+
* callback is also used to prevent use of client-initiated
906+
* renegotiation. Enable it in either case. */
907+
if (APLOGdebug(s) || MODSSL_BLOCKS_RENEG) {
908+
SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
909+
}
889910

890911
#ifdef HAVE_TLS_ALPN
891912
SSL_CTX_set_alpn_select_cb(ctx, ssl_callback_alpn_select, NULL);

modules/ssl/ssl_engine_io.c

+4
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,13 @@ static int bio_filter_out_write(BIO *bio, const char *in, int inl)
208208

209209
BIO_clear_retry_flags(bio);
210210

211+
#ifndef SSL_OP_NO_RENEGOTIATION
211212
/* Abort early if the client has initiated a renegotiation. */
212213
if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
213214
outctx->rc = APR_ECONNABORTED;
214215
return -1;
215216
}
217+
#endif
216218

217219
ap_log_cerror(APLOG_MARK, APLOG_TRACE6, 0, outctx->c,
218220
"bio_filter_out_write: %i bytes", inl);
@@ -473,11 +475,13 @@ static int bio_filter_in_read(BIO *bio, char *in, int inlen)
473475

474476
BIO_clear_retry_flags(bio);
475477

478+
#ifndef SSL_OP_NO_RENEGOTIATION
476479
/* Abort early if the client has initiated a renegotiation. */
477480
if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
478481
inctx->rc = APR_ECONNABORTED;
479482
return -1;
480483
}
484+
#endif
481485

482486
if (!inctx->bb) {
483487
inctx->rc = APR_EOF;

modules/ssl/ssl_engine_kernel.c

+12-16
Original file line numberDiff line numberDiff line change
@@ -992,7 +992,7 @@ static int ssl_hook_Access_classic(request_rec *r, SSLSrvConfigRec *sc, SSLDirCo
992992

993993
/* Toggle the renegotiation state to allow the new
994994
* handshake to proceed. */
995-
sslconn->reneg_state = RENEG_ALLOW;
995+
modssl_set_reneg_state(sslconn, RENEG_ALLOW);
996996

997997
SSL_renegotiate(ssl);
998998
SSL_do_handshake(ssl);
@@ -1019,7 +1019,7 @@ static int ssl_hook_Access_classic(request_rec *r, SSLSrvConfigRec *sc, SSLDirCo
10191019
*/
10201020
SSL_peek(ssl, peekbuf, 0);
10211021

1022-
sslconn->reneg_state = RENEG_REJECT;
1022+
modssl_set_reneg_state(sslconn, RENEG_REJECT);
10231023

10241024
if (!SSL_is_init_finished(ssl)) {
10251025
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
10781078
(sc->server->auth.verify_mode != SSL_CVERIFY_UNSET)) {
10791079
int vmode_inplace, vmode_needed;
10801080
int change_vmode = FALSE;
1081-
int old_state, n, rc;
1081+
int n, rc;
10821082

10831083
vmode_inplace = SSL_get_verify_mode(ssl);
10841084
vmode_needed = SSL_VERIFY_NONE;
@@ -1180,8 +1180,6 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon
11801180
return HTTP_FORBIDDEN;
11811181
}
11821182

1183-
old_state = sslconn->reneg_state;
1184-
sslconn->reneg_state = RENEG_ALLOW;
11851183
modssl_set_app_data2(ssl, r);
11861184

11871185
SSL_do_handshake(ssl);
@@ -1191,7 +1189,6 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon
11911189
*/
11921190
SSL_peek(ssl, peekbuf, 0);
11931191

1194-
sslconn->reneg_state = old_state;
11951192
modssl_set_app_data2(ssl, NULL);
11961193

11971194
/*
@@ -2263,8 +2260,8 @@ static void log_tracing_state(const SSL *ssl, conn_rec *c,
22632260
/*
22642261
* This callback function is executed while OpenSSL processes the SSL
22652262
* handshake and does SSL record layer stuff. It's used to trap
2266-
* client-initiated renegotiations, and for dumping everything to the
2267-
* log.
2263+
* client-initiated renegotiations (where SSL_OP_NO_RENEGOTATION is
2264+
* not available), and for dumping everything to the log.
22682265
*/
22692266
void ssl_callback_Info(const SSL *ssl, int where, int rc)
22702267
{
@@ -2276,14 +2273,12 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc)
22762273
return;
22772274
}
22782275

2279-
/* With TLS 1.3 this callback may be called multiple times on the first
2280-
* negotiation, so the below logic to detect renegotiations can't work.
2281-
* Fortunately renegotiations are forbidden starting with TLS 1.3, and
2282-
* this is enforced by OpenSSL so there's nothing to be done here.
2283-
*/
2284-
#if SSL_HAVE_PROTOCOL_TLSV1_3
2285-
if (SSL_version(ssl) < TLS1_3_VERSION)
2286-
#endif
2276+
#ifndef SSL_OP_NO_RENEGOTATION
2277+
/* With OpenSSL < 1.1.1 (implying TLS v1.2 or earlier), this
2278+
* callback is used to block client-initiated renegotiation. With
2279+
* TLSv1.3 it is unnecessary since renegotiation is forbidden at
2280+
* protocol level. Otherwise (TLSv1.2 with OpenSSL >=1.1.1),
2281+
* SSL_OP_NO_RENEGOTATION is used to block renegotiation. */
22872282
{
22882283
SSLConnRec *sslconn;
22892284

@@ -2308,6 +2303,7 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc)
23082303
sslconn->reneg_state = RENEG_REJECT;
23092304
}
23102305
}
2306+
#endif
23112307

23122308
s = mySrvFromConn(c);
23132309
if (s && APLOGdebug(s)) {

modules/ssl/ssl_private.h

+20-12
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,16 @@ typedef struct {
549549
apr_time_t source_mtime;
550550
} ssl_asn1_t;
551551

552+
typedef enum {
553+
RENEG_INIT = 0, /* Before initial handshake */
554+
RENEG_REJECT, /* After initial handshake; any client-initiated
555+
* renegotiation should be rejected */
556+
RENEG_ALLOW, /* A server-initiated renegotiation is taking
557+
* place (as dictated by configuration) */
558+
RENEG_ABORT /* Renegotiation initiated by client, abort the
559+
* connection */
560+
} modssl_reneg_state;
561+
552562
/**
553563
* Define the mod_ssl per-module configuration structure
554564
* (i.e. the global configuration for each httpd process)
@@ -580,18 +590,13 @@ typedef struct {
580590
NON_SSL_SET_ERROR_MSG /* Need to set the error message */
581591
} non_ssl_request;
582592

583-
/* Track the handshake/renegotiation state for the connection so
584-
* that all client-initiated renegotiations can be rejected, as a
585-
* partial fix for CVE-2009-3555. */
586-
enum {
587-
RENEG_INIT = 0, /* Before initial handshake */
588-
RENEG_REJECT, /* After initial handshake; any client-initiated
589-
* renegotiation should be rejected */
590-
RENEG_ALLOW, /* A server-initiated renegotiation is taking
591-
* place (as dictated by configuration) */
592-
RENEG_ABORT /* Renegotiation initiated by client, abort the
593-
* connection */
594-
} reneg_state;
593+
#ifndef SSL_OP_NO_RENEGOTATION
594+
/* For OpenSSL < 1.1.1, track the handshake/renegotiation state
595+
* for the connection to block client-initiated renegotiations.
596+
* For OpenSSL >=1.1.1, the SSL_OP_NO_RENEGOTATION flag is used in
597+
* the SSL * options state with equivalent effect. */
598+
modssl_reneg_state reneg_state;
599+
#endif
595600

596601
server_rec *server;
597602
SSLDirConfigRec *dc;
@@ -1198,6 +1203,9 @@ int ssl_is_challenge(conn_rec *c, const char *servername,
11981203
* the configured ENGINE. */
11991204
int modssl_is_engine_id(const char *name);
12001205

1206+
/* Set the renegotation state for connection. */
1207+
void modssl_set_reneg_state(SSLConnRec *sslconn, modssl_reneg_state state);
1208+
12011209
#endif /* SSL_PRIVATE_H */
12021210
/** @} */
12031211

modules/ssl/ssl_util_ssl.c

+16
Original file line numberDiff line numberDiff line change
@@ -612,3 +612,19 @@ apr_status_t modssl_cert_get_pem(apr_pool_t *p,
612612
}
613613
return rv;
614614
}
615+
616+
void modssl_set_reneg_state(SSLConnRec *sslconn, modssl_reneg_state state)
617+
{
618+
#ifdef SSL_OP_NO_RENEGOTATION
619+
switch (state) {
620+
case RENEG_ALLOW:
621+
SSL_clear_options(sslconn->ssl, SSL_OP_NO_RENEGOTATION);
622+
break;
623+
default:
624+
SSL_set_options(sslconn->ssl, SSL_OP_NO_RENEGOTATION);
625+
break;
626+
}
627+
#else
628+
sslconn->reneg_state = state;
629+
#endif
630+
}

0 commit comments

Comments
 (0)