Hi,
On Mon, Oct 21, 2019 at 4:21 PM Aleksandar Ivanisevic
<[email protected]> wrote:
>
> could you please copy the list or me, as I would be also interested.
That's http://svn.apache.org/r1868645 on trunk. It applies cleanly to
latest 2.4 version, just in case the corresponding patch is attached
here.
Regards,
Yann.
Index: modules/ssl/ssl_engine_init.c
===================================================================
--- modules/ssl/ssl_engine_init.c (revision 1868679)
+++ modules/ssl/ssl_engine_init.c (working copy)
@@ -497,8 +497,11 @@ static apr_status_t ssl_init_ctx_tls_extensions(se
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01893)
"Configuring TLS extension handling");
+#if OPENSSL_VERSION_NUMBER < 0x10101000L || defined(LIBRESSL_VERSION_NUMBER)
/*
- * Server name indication (SNI)
+ * The Server Name Indication (SNI) provided by the ClientHello can be
+ * used to select the right (name-based-)vhost and its SSL configuration
+ * before the handshake takes place.
*/
if (!SSL_CTX_set_tlsext_servername_callback(mctx->ssl_ctx,
ssl_callback_ServerNameIndication) ||
@@ -509,6 +512,15 @@ static apr_status_t ssl_init_ctx_tls_extensions(se
ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
return ssl_die(s);
}
+#else
+ /*
+ * The ClientHello callback also allows to retrieve the SNI, but since it
+ * runs at the earliest possible connection stage we can even set the TLS
+ * protocol version(s) according to the selected (name-based-)vhost, which
+ * is not possible at the SNI callback stage (due to OpenSSL internals).
+ */
+ SSL_CTX_set_client_hello_cb(mctx->ssl_ctx, ssl_callback_ClientHello, NULL);
+#endif
#ifdef HAVE_OCSP_STAPLING
/*
@@ -678,7 +690,7 @@ static apr_status_t ssl_init_ctx_protocol(server_r
#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)) {
+ if (protocol & SSL_PROTOCOL_TLSV1_3) {
prot = TLS1_3_VERSION;
} else
#endif
Index: modules/ssl/ssl_engine_kernel.c
===================================================================
--- modules/ssl/ssl_engine_kernel.c (revision 1868679)
+++ modules/ssl/ssl_engine_kernel.c (working copy)
@@ -2328,9 +2328,8 @@ static apr_status_t set_challenge_creds(conn_rec *
* This function sets the virtual host from an extended
* client hello with a server name indication extension ("SNI", cf. RFC 6066).
*/
-static apr_status_t init_vhost(conn_rec *c, SSL *ssl)
+static apr_status_t init_vhost(conn_rec *c, SSL *ssl, const char *servername)
{
- const char *servername;
X509 *cert;
EVP_PKEY *key;
@@ -2342,7 +2341,9 @@ static apr_status_t set_challenge_creds(conn_rec *
return APR_SUCCESS;
}
- servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ if (!servername) {
+ servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ }
if (servername) {
if (ap_vhost_iterate_given_conn(c, ssl_find_vhost,
(void *)servername)) {
@@ -2392,6 +2393,7 @@ static apr_status_t set_challenge_creds(conn_rec *
return APR_NOTFOUND;
}
+#if OPENSSL_VERSION_NUMBER < 0x10101000L || defined(LIBRESSL_VERSION_NUMBER)
/*
* This callback function is executed when OpenSSL encounters an extended
* client hello with a server name indication extension ("SNI", cf. RFC 6066).
@@ -2399,11 +2401,70 @@ static apr_status_t set_challenge_creds(conn_rec *
int ssl_callback_ServerNameIndication(SSL *ssl, int *al, modssl_ctx_t *mctx)
{
conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
- apr_status_t status = init_vhost(c, ssl);
+ apr_status_t status = init_vhost(c, ssl, NULL);
return (status == APR_SUCCESS)? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_NOACK;
}
+#else /* OPENSSL_VERSION_NUMBER < 0x10101000L */
+/*
+ * This callback function when the ClientHello is received.
+ */
+int ssl_callback_ClientHello(SSL *ssl, int *al, void *arg)
+{
+ char *servername = NULL;
+ conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
+ const unsigned char *pos;
+ size_t len, remaining;
+ (void)arg;
+
+ /* We can't use SSL_get_servername() at this earliest OpenSSL connection
+ * stage, and there is no SSL_client_hello_get0_servername() provided as
+ * of OpenSSL 1.1.1. So the code below, that extracts the SNI from the
+ * ClientHello's TLS extensions, is taken from some test code in OpenSSL,
+ * i.e. client_hello_select_server_ctx() in "test/handshake_helper.c".
+ */
+ /*
+ * The server_name extension was given too much extensibility when it
+ * was written, so parsing the normal case is a bit complex.
+ */
+ if (!SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &pos,
+ &remaining)
+ || remaining <= 2)
+ goto give_up;
+
+ /* Extract the length of the supplied list of names. */
+ len = (*(pos++) << 8);
+ len += *(pos++);
+ if (len + 2 != remaining)
+ goto give_up;
+ remaining = len;
+
+ /*
+ * The list in practice only has a single element, so we only consider
+ * the first one.
+ */
+ if (remaining <= 3 || *pos++ != TLSEXT_NAMETYPE_host_name)
+ goto give_up;
+ remaining--;
+
+ /* Now we can finally pull out the byte array with the actual hostname. */
+ len = (*(pos++) << 8);
+ len += *(pos++);
+ if (len + 2 != remaining)
+ goto give_up;
+
+ /* Use the SNI to switch to the relevant vhost, should it differ from
+ * c->base_server.
+ */
+ servername = apr_pstrmemdup(c->pool, (const char *)pos, len);
+
+give_up:
+ init_vhost(c, ssl, servername);
+ return SSL_CLIENT_HELLO_SUCCESS;
+}
+#endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */
+
/*
* Find a (name-based) SSL virtual host where either the ServerName
* or one of the ServerAliases matches the supplied name (to be used
@@ -2423,6 +2484,7 @@ static int ssl_find_vhost(void *servername, conn_r
if (found && (ssl = sslcon->ssl) &&
(sc = mySrvConfig(s))) {
SSL_CTX *ctx = SSL_set_SSL_CTX(ssl, sc->server->ssl_ctx);
+
/*
* SSL_set_SSL_CTX() only deals with the server cert,
* so we need to duplicate a few additional settings
@@ -2429,6 +2491,12 @@ static int ssl_find_vhost(void *servername, conn_r
* from the ctx by hand
*/
SSL_set_options(ssl, SSL_CTX_get_options(ctx));
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L \
+ && (!defined(LIBRESSL_VERSION_NUMBER) \
+ || LIBRESSL_VERSION_NUMBER >= 0x20800000L)
+ SSL_set_min_proto_version(ssl, SSL_CTX_get_min_proto_version(ctx));
+ SSL_set_max_proto_version(ssl, SSL_CTX_get_max_proto_version(ctx));
+#endif
if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) ||
(SSL_num_renegotiations(ssl) == 0)) {
/*
@@ -2625,7 +2693,7 @@ int ssl_callback_alpn_select(SSL *ssl,
* they callback the SNI. We need to make sure that we know which vhost
* we are dealing with so we respect the correct protocols.
*/
- init_vhost(c, ssl);
+ init_vhost(c, ssl, NULL);
proposed = ap_select_protocol(c, NULL, sslconn->server, client_protos);
if (!proposed) {
Index: modules/ssl/ssl_private.h
===================================================================
--- modules/ssl/ssl_private.h (revision 1868679)
+++ modules/ssl/ssl_private.h (working copy)
@@ -926,8 +926,12 @@ SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL
void ssl_callback_DelSessionCacheEntry(SSL_CTX *, SSL_SESSION *);
void ssl_callback_Info(const SSL *, int, int);
#ifdef HAVE_TLSEXT
+#if OPENSSL_VERSION_NUMBER < 0x10101000L || defined(LIBRESSL_VERSION_NUMBER)
int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *);
+#else
+int ssl_callback_ClientHello(SSL *, int *, void *);
#endif
+#endif
#ifdef HAVE_TLS_SESSION_TICKETS
int ssl_callback_SessionTicket(SSL *, unsigned char *, unsigned char *,
EVP_CIPHER_CTX *, HMAC_CTX *, int);
Index: .
===================================================================
--- . (revision 1868679)
+++ . (working copy)
Property changes on: .
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /httpd/httpd/trunk:r1868645
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]