This is an automated email from the ASF dual-hosted git repository.

jfclere pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat-native.git


The following commit(s) were added to refs/heads/main by this push:
     new d1885c2  fix an issue similar to 
https://bz.apache.org/bugzilla/show_bug.cgi?id=55707 note it affects only the 
Apr connector it seems.
     new 1e87871  Merge pull request #10 from jfclere/ASFBZ55707
d1885c2 is described below

commit d1885c202d987f3898ba72b7fc084413f0bdb1f9
Author: Jean-Frederic Clere <jfcl...@gmail.com>
AuthorDate: Thu Jul 15 10:07:23 2021 +0200

    fix an issue similar to https://bz.apache.org/bugzilla/show_bug.cgi?id=55707
    note it affects only the Apr connector it seems.
---
 native/src/sslcontext.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 108 insertions(+)

diff --git a/native/src/sslcontext.c b/native/src/sslcontext.c
index 6c8d18b..483446d 100644
--- a/native/src/sslcontext.c
+++ b/native/src/sslcontext.c
@@ -130,6 +130,104 @@ int ssl_callback_ServerNameIndication(SSL *ssl, int *al, 
tcn_ssl_ctxt_t *c)
     return SSL_TLSEXT_ERR_OK;
 }
 
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+/*
+ * This callback function is called when the ClientHello is received.
+ */
+int ssl_callback_ClientHello(SSL *ssl, int *al, void *arg)
+{
+    JavaVM *javavm = tcn_get_java_vm();
+    JNIEnv *env;
+    char *servername = NULL;
+    const unsigned char *pos;
+    size_t len, remaining;
+    tcn_ssl_ctxt_t *c = (tcn_ssl_ctxt_t *) arg;
+ 
+    (*javavm)->AttachCurrentThread(javavm, (void **)&env, NULL);
+    // Continue only if the static method exists
+    if (sni_java_callback == NULL) {
+        return SSL_CLIENT_HELLO_SUCCESS;
+    }
+
+    /* 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:
+    if (servername != NULL) {
+        jstring hostname;
+        jlong original_ssl_context, new_ssl_context;
+        tcn_ssl_ctxt_t *new_c;
+
+        hostname = (*env)->NewStringUTF(env, servername);
+        original_ssl_context = P2J(c);
+        new_ssl_context = (*env)->CallStaticLongMethod(env,
+                                                   ssl_context_class,
+                                                   sni_java_callback,
+                                                   original_ssl_context,
+                                                   hostname);
+        (*env)->DeleteLocalRef(env, hostname);
+        if (new_ssl_context != 0 && new_ssl_context != original_ssl_context) {
+            SSL_CTX *ctx;
+            new_c = J2P(new_ssl_context, tcn_ssl_ctxt_t *);
+            ctx = SSL_set_SSL_CTX(ssl, new_c->ctx);
+
+            /* Copied from httpd (modules/ssl/ssl_engine_kernel.c) */
+            SSL_set_options(ssl, SSL_CTX_get_options(ctx));
+            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));
+            if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) ||
+                (SSL_num_renegotiations(ssl) == 0)) {
+                SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ctx), 
SSL_CTX_get_verify_callback(ctx));
+            }
+            if (SSL_num_renegotiations(ssl) == 0) {
+                SSL_set_session_id_context(ssl,  &(c->context_id[0]), sizeof 
c->context_id);
+            }
+        }
+ 
+    }
+    return SSL_CLIENT_HELLO_SUCCESS;
+}
+#endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */
+
 /* Initialize server context */
 TCN_IMPLEMENT_CALL(jlong, SSLContext, make)(TCN_STDARGS, jlong pool,
                                             jint protocol, jint mode)
@@ -368,6 +466,16 @@ TCN_IMPLEMENT_CALL(jlong, SSLContext, make)(TCN_STDARGS, 
jlong pool,
     SSL_CTX_set_tlsext_servername_callback(c->ctx, 
ssl_callback_ServerNameIndication);
     SSL_CTX_set_tlsext_servername_arg(c->ctx, c);
 
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+    /*
+     * 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(c->ctx, ssl_callback_ClientHello, c);
+#endif
+
     /*
      * Let us cleanup the ssl context when the pool is destroyed
      */

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to