diff --git a/httpd-2.4.48-r1877397.patch b/httpd-2.4.48-r1877397.patch new file mode 100644 index 0000000..8b3b633 --- /dev/null +++ b/httpd-2.4.48-r1877397.patch @@ -0,0 +1,249 @@ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 699bdcd..15f68f9 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -842,6 +842,13 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + * https://github.com/openssl/openssl/issues/7178 */ + SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY); + #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; + } +@@ -863,6 +870,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, +@@ -872,7 +887,13 @@ static void ssl_init_ctx_callbacks(server_rec *s, + + SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH); + +- 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 1a0791a..5c1ad5d 100644 +--- a/modules/ssl/ssl_engine_io.c ++++ b/modules/ssl/ssl_engine_io.c +@@ -205,11 +205,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); +@@ -462,11 +464,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 f2d49ad..a38f03d 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); + + /* +@@ -2261,8 +2258,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) + { +@@ -2274,14 +2271,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; + +@@ -2306,6 +2301,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 71d658c..f9654af 100644 +--- a/modules/ssl/ssl_private.h ++++ b/modules/ssl/ssl_private.h +@@ -509,6 +509,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) +@@ -541,18 +551,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; +@@ -1145,6 +1150,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 ++} diff --git a/httpd.spec b/httpd.spec index 3d1ce56..cc84559 100644 --- a/httpd.spec +++ b/httpd.spec @@ -13,7 +13,7 @@ Summary: Apache HTTP Server Name: httpd Version: 2.4.48 -Release: 6%{?dist} +Release: 7%{?dist} URL: https://httpd.apache.org/ Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source1: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2.asc @@ -99,6 +99,8 @@ Patch62: httpd-2.4.48-r1876934.patch Patch63: httpd-2.4.48-sslprivkey.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1932442 Patch64: httpd-2.4.48-full-release.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1950011 +Patch65: httpd-2.4.48-r1877397.patch # Security fixes @@ -253,6 +255,7 @@ written in the Lua programming language. %patch62 -p1 -b .r1876934 %patch63 -p1 -b .sslprivkey %patch64 -p1 -b .full-release +%patch65 -p1 -b .r1877397 # Patch in the vendor string sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h @@ -794,6 +797,10 @@ exit $rv %{_rpmconfigdir}/macros.d/macros.httpd %changelog +* Thu Jul 01 2021 Luboš Uhliarik - 2.4.48-7 +- Resolves: #1950011 - unorderly connection close when client attempts + renegotiation + * Thu Jul 01 2021 Luboš Uhliarik - 2.4.48-6 - Resolves: #1932442 - "ServerTokens FullRelease" support