You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2021/11/18 10:16:52 UTC

[tomcat] branch main updated: Improve memory management

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

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


The following commit(s) were added to refs/heads/main by this push:
     new 590877b  Improve memory management
590877b is described below

commit 590877b9b7063973606013614c6eff609df925a5
Author: remm <re...@apache.org>
AuthorDate: Thu Nov 18 11:16:34 2021 +0100

    Improve memory management
    
    Switch to an implicit scope for the context, and remove the cleaner (as
    the scope is the cleaner).
    Although not being able to use bound method handles is frustrating, this
    is overall more realistic and sustainable.
    Verify correct behavior with heap dump and the SSLHostConfig reload
    command.
    Document problems with hardcoded defines with jextract (this is a good
    idea in most cases, but not always). Will examine if there is a
    workaround.
---
 .../util/net/openssl/panama/OpenSSLContext.java    | 393 +++++++++------------
 .../util/net/openssl/panama/OpenSSLEngine.java     |  30 +-
 .../openssl/panama/OpenSSLLifecycleListener.java   |   1 +
 .../net/openssl/panama/LocalStrings.properties     |   3 +-
 4 files changed, 187 insertions(+), 240 deletions(-)

diff --git a/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java b/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java
index 612a0fe..14957c9 100644
--- a/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java
+++ b/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java
@@ -30,8 +30,6 @@ import java.io.File;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
-import java.lang.ref.Cleaner;
-import java.lang.ref.Cleaner.Cleanable;
 import java.nio.charset.StandardCharsets;
 import java.security.PrivateKey;
 import java.security.SecureRandom;
@@ -43,6 +41,7 @@ import java.util.Arrays;
 import java.util.Base64;
 import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
 
 import javax.net.ssl.KeyManager;
 import javax.net.ssl.SSLEngine;
@@ -132,13 +131,13 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
     static {
         MethodHandles.Lookup lookup = MethodHandles.lookup();
         try {
-            openSSLCallbackVerifyHandle = lookup.findVirtual(OpenSSLContext.class, "openSSLCallbackVerify",
+            openSSLCallbackVerifyHandle = lookup.findStatic(OpenSSLContext.class, "openSSLCallbackVerify",
                     MethodType.methodType(int.class, int.class, MemoryAddress.class));
-            openSSLCallbackPasswordHandle = lookup.findVirtual(OpenSSLContext.class, "openSSLCallbackPassword",
+            openSSLCallbackPasswordHandle = lookup.findStatic(OpenSSLContext.class, "openSSLCallbackPassword",
                     MethodType.methodType(int.class, MemoryAddress.class, int.class, int.class, MemoryAddress.class));
-            openSSLCallbackCertVerifyHandle = lookup.findVirtual(OpenSSLContext.class, "openSSLCallbackCertVerify",
+            openSSLCallbackCertVerifyHandle = lookup.findStatic(OpenSSLContext.class, "openSSLCallbackCertVerify",
                     MethodType.methodType(int.class, MemoryAddress.class, MemoryAddress.class));
-            openSSLCallbackAlpnSelectProtoHandle = lookup.findVirtual(OpenSSLContext.class, "openSSLCallbackAlpnSelectProto",
+            openSSLCallbackAlpnSelectProtoHandle = lookup.findStatic(OpenSSLContext.class, "openSSLCallbackAlpnSelectProto",
                     MethodType.methodType(int.class, MemoryAddress.class, MemoryAddress.class,
                             MemoryAddress.class, MemoryAddress.class, int.class, MemoryAddress.class));
             openSSLCallbackTmpDHHandle = lookup.findStatic(OpenSSLContext.class, "openSSLCallbackTmpDH",
@@ -208,17 +207,11 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
         dhParameters[5] = new DHParam(dh, 0);
     }
 
-    private static final Cleaner cleaner = Cleaner.create();
-
     private final SSLHostConfig sslHostConfig;
     private final SSLHostConfigCertificate certificate;
     private final boolean alpn;
-    private final List<byte[]> negotiableProtocols;
-
-    private int certificateVerifyMode = -1;
 
     private OpenSSLSessionContext sessionContext;
-    private X509TrustManager x509TrustManager;
     private String enabledProtocol;
     private boolean initialized = false;
 
@@ -227,8 +220,14 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
     // Password callback
     private final MemoryAddress openSSLCallbackPassword;
 
-    private final OpenSSLState state;
-    private final Cleanable cleanable;
+    private static final ConcurrentHashMap<Long, ContextState> states = new ConcurrentHashMap<>();
+
+    static ContextState getState(MemoryAddress ctx) {
+        return states.get(Long.valueOf(ctx.toRawLongValue()));
+    }
+
+    private final ContextState state;
+    private final ResourceScope scope;
 
     private static String[] getCiphers(MemoryAddress sslCtx) {
         MemoryAddress sk = SSL_CTX_get_ciphers(sslCtx);
@@ -259,10 +258,11 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
 
         this.sslHostConfig = certificate.getSSLHostConfig();
         this.certificate = certificate;
-        ResourceScope scope = ResourceScope.newSharedScope();
+        scope = ResourceScope.newImplicitScope();
 
-        MemoryAddress ctx = MemoryAddress.NULL;
-        MemoryAddress cctx = MemoryAddress.NULL;
+        MemoryAddress sslCtx = MemoryAddress.NULL;
+        MemoryAddress confCtx = MemoryAddress.NULL;
+        List<byte[]> negotiableProtocolsBytes = null;
         boolean success = false;
         try {
             // Create OpenSSLConfCmd context if used
@@ -273,14 +273,14 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                     if (log.isDebugEnabled()) {
                         log.debug(sm.getString("openssl.makeConf"));
                     }
-                    cctx = SSL_CONF_CTX_new();
+                    confCtx = SSL_CONF_CTX_new();
                     long errCode = ERR_get_error();
                     if (errCode != 0) {
                         var buf = allocator.allocateArray(CLinker.C_CHAR, new byte[128]);
                         ERR_error_string(errCode, buf);
                         log.error(sm.getString("openssl.errorLoadingCertificate", CLinker.toJavaString(buf)));
                     }
-                    SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE() |
+                    SSL_CONF_CTX_set_flags(confCtx, SSL_CONF_FLAG_FILE() |
                             SSL_CONF_FLAG_SERVER() |
                             SSL_CONF_FLAG_CERTIFICATE() |
                             SSL_CONF_FLAG_SHOW_ERRORS());
@@ -290,7 +290,7 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
             }
 
             // SSL protocol
-            ctx = SSL_CTX_new(TLS_server_method());
+            sslCtx = SSL_CTX_new(TLS_server_method());
 
             int protocol = SSL_PROTOCOL_NONE;
             for (String enabledProtocol : sslHostConfig.getEnabledProtocols()) {
@@ -330,9 +330,9 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
             } else if ((protocol & SSL_PROTOCOL_SSLV3) > 0) {
                 prot = SSL3_VERSION();
             }
-            // # define SSL_CTX_set_max_proto_version(ctx, version) \
-            //          SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, NULL)
-            SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION(), prot, MemoryAddress.NULL);
+            // # define SSL_CTX_set_max_proto_version(sslCtx, version) \
+            //          SSL_CTX_ctrl(sslCtx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, NULL)
+            SSL_CTX_ctrl(sslCtx, SSL_CTRL_SET_MAX_PROTO_VERSION(), prot, MemoryAddress.NULL);
             if (prot == TLS1_3_VERSION() && (protocol & SSL_PROTOCOL_TLSV1_2) > 0) {
                 prot = TLS1_2_VERSION();
             }
@@ -345,32 +345,32 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
             if (prot == TLS1_VERSION() && (protocol & SSL_PROTOCOL_SSLV3) > 0) {
                 prot = SSL3_VERSION();
             }
-            //# define SSL_CTX_set_min_proto_version(ctx, version) \
-            //         SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, NULL)
-            SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION(), prot, MemoryAddress.NULL);
+            //# define SSL_CTX_set_min_proto_version(sslCtx, version) \
+            //         SSL_CTX_ctrl(sslCtx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, NULL)
+            SSL_CTX_ctrl(sslCtx, SSL_CTRL_SET_MIN_PROTO_VERSION(), prot, MemoryAddress.NULL);
 
             // Disable compression, usually unsafe
-            SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION());
+            SSL_CTX_set_options(sslCtx, SSL_OP_NO_COMPRESSION());
 
             // Disallow a session from being resumed during a renegotiation,
             // so that an acceptable cipher suite can be negotiated.
-            SSL_CTX_set_options(ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION());
+            SSL_CTX_set_options(sslCtx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION());
 
-            SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE());
-            SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE());
+            SSL_CTX_set_options(sslCtx, SSL_OP_SINGLE_DH_USE());
+            SSL_CTX_set_options(sslCtx, SSL_OP_SINGLE_ECDH_USE());
 
             // Default session context id and cache size
-            // # define SSL_CTX_sess_set_cache_size(ctx,t) \
-            //          SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_SIZE,t,NULL)
-            SSL_CTX_ctrl(ctx, SSL_CTRL_SET_SESS_CACHE_SIZE(), 256, MemoryAddress.NULL);
+            // # define SSL_CTX_sess_set_cache_size(sslCtx,t) \
+            //          SSL_CTX_ctrl(sslCtx,SSL_CTRL_SET_SESS_CACHE_SIZE,t,NULL)
+            SSL_CTX_ctrl(sslCtx, SSL_CTRL_SET_SESS_CACHE_SIZE(), 256, MemoryAddress.NULL);
 
             // Session cache is disabled by default
-            // # define SSL_CTX_set_session_cache_mode(ctx,m) \
-            //          SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL)
-            SSL_CTX_ctrl(ctx, SSL_CTRL_SET_SESS_CACHE_MODE(), SSL_SESS_CACHE_OFF(), MemoryAddress.NULL);
+            // # define SSL_CTX_set_session_cache_mode(sslCtx,m) \
+            //          SSL_CTX_ctrl(sslCtx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL)
+            SSL_CTX_ctrl(sslCtx, SSL_CTRL_SET_SESS_CACHE_MODE(), SSL_SESS_CACHE_OFF(), MemoryAddress.NULL);
 
             // Longer session timeout
-            SSL_CTX_set_timeout(ctx, 14400);
+            SSL_CTX_set_timeout(sslCtx, 14400);
 
             // From SSLContext.make, possibly set ssl_callback_ServerNameIndication
             // From SSLContext.make, possibly set ssl_callback_ClientHello
@@ -378,26 +378,24 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
 
             // Set int pem_password_cb(char *buf, int size, int rwflag, void *u) callback
             openSSLCallbackPassword =
-                    CLinker.getInstance().upcallStub(openSSLCallbackPasswordHandle.bindTo(this),
+                    CLinker.getInstance().upcallStub(openSSLCallbackPasswordHandle,
                     openSSLCallbackPasswordFunctionDescriptor, scope);
-            SSL_CTX_set_default_passwd_cb(ctx, openSSLCallbackPassword);
+            SSL_CTX_set_default_passwd_cb(sslCtx, openSSLCallbackPassword);
 
             alpn = (negotiableProtocols != null && negotiableProtocols.size() > 0);
             if (alpn) {
-                this.negotiableProtocols = new ArrayList<>(negotiableProtocols.size() + 1);
+                negotiableProtocolsBytes = new ArrayList<>(negotiableProtocols.size() + 1);
                 for (String negotiableProtocol : negotiableProtocols) {
-                    this.negotiableProtocols.add(negotiableProtocol.getBytes(StandardCharsets.ISO_8859_1));
+                    negotiableProtocolsBytes.add(negotiableProtocol.getBytes(StandardCharsets.ISO_8859_1));
                 }
-                this.negotiableProtocols.add(HTTP_11_PROTOCOL);
-            } else {
-                this.negotiableProtocols = null;
+                negotiableProtocolsBytes.add(HTTP_11_PROTOCOL);
             }
 
             success = true;
         } catch(Exception e) {
             throw new SSLException(sm.getString("openssl.errorSSLCtxInit"), e);
         } finally {
-            state = new OpenSSLState(scope, cctx, ctx);
+            state = new ContextState(sslCtx, confCtx, negotiableProtocolsBytes);
             /*
              * When an SSLHostConfig is replaced at runtime, it is not possible to
              * call destroy() on the associated OpenSSLContext since it is likely
@@ -406,10 +404,11 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
              * OpenSSLSessionContext) to ensure that the OpenSSLContext remains
              * ineligible for GC while those connections are alive. Once those
              * connections complete, the OpenSSLContext will become eligible for GC
-             * and this method will ensure that the associated native resources are
-             * cleaned up.
+             * and the implicit scope will ensure that the associated native
+             * resources are cleaned up.
              */
-            cleanable = cleaner.register(this, state);
+            states.put(Long.valueOf(sslCtx.address().toRawLongValue()), state);
+            scope.addCloseAction(state);
 
             if (!success) {
                 destroy();
@@ -430,7 +429,7 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
 
     @Override
     public synchronized void destroy() {
-        cleanable.clean();
+        states.remove(Long.valueOf(state.sslCtx.address().toRawLongValue()));
     }
 
 
@@ -453,12 +452,12 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                 log.debug(sm.getString("opensslconf.checkCommand", name, value));
             }
             try (var scope = ResourceScope.newConfinedScope()) {
-                // rc = SSLConf.check(cctx, name, value);
+                // rc = SSLConf.check(confCtx, name, value);
                 if (name.equals("NO_OCSP_CHECK")) {
                     rc = 1;
                 } else {
                     var allocator = SegmentAllocator.ofScope(scope);
-                    int code = SSL_CONF_cmd_value_type(state.cctx, CLinker.toCString(name, scope));
+                    int code = SSL_CONF_cmd_value_type(state.confCtx, CLinker.toCString(name, scope));
                     rc = 1;
                     long errCode = ERR_get_error();
                     if (errCode != 0) {
@@ -510,8 +509,8 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
 
     private boolean applyConf(OpenSSLConf conf) throws Exception {
         boolean result = true;
-        // SSLConf.assign(cctx, ctx);
-        SSL_CONF_CTX_set_ssl_ctx(state.cctx, state.ctx);
+        // SSLConf.assign(confCtx, sslCtx);
+        SSL_CONF_CTX_set_ssl_ctx(state.confCtx, state.sslCtx);
         OpenSSLConfCmd cmd;
         String name;
         String value;
@@ -529,13 +528,13 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                 log.debug(sm.getString("opensslconf.applyCommand", name, value));
             }
             try (var scope = ResourceScope.newConfinedScope()) {
-                // rc = SSLConf.apply(cctx, name, value);
+                // rc = SSLConf.apply(confCtx, name, value);
                 if (name.equals("NO_OCSP_CHECK")) {
                     noOcspCheck = Boolean.valueOf(value);
                     rc = 1;
                 } else {
                     var allocator = SegmentAllocator.ofScope(scope);
-                    rc = SSL_CONF_cmd(state.cctx, CLinker.toCString(name, scope),
+                    rc = SSL_CONF_cmd(state.confCtx, CLinker.toCString(name, scope),
                             CLinker.toCString(value, scope));
                     long errCode = ERR_get_error();
                     if (rc <= 0 || errCode != 0) {
@@ -558,8 +557,8 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                         Integer.toString(rc)));
             }
         }
-        // rc = SSLConf.finish(cctx);
-        rc = SSL_CONF_CTX_finish(state.cctx);
+        // rc = SSLConf.finish(confCtx);
+        rc = SSL_CONF_CTX_finish(state.confCtx);
         if (rc <= 0) {
             log.error(sm.getString("opensslconf.finishFailed", Integer.toString(rc)));
             result = false;
@@ -589,35 +588,35 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
         }
         try {
             if (sslHostConfig.getInsecureRenegotiation()) {
-                SSL_CTX_set_options(state.ctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION());
+                SSL_CTX_set_options(state.sslCtx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION());
             } else {
-                SSL_CTX_clear_options(state.ctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION());
+                SSL_CTX_clear_options(state.sslCtx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION());
             }
 
             // Use server's preference order for ciphers (rather than
             // client's)
             if (sslHostConfig.getHonorCipherOrder()) {
-                SSL_CTX_set_options(state.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE());
+                SSL_CTX_set_options(state.sslCtx, SSL_OP_CIPHER_SERVER_PREFERENCE());
             } else {
-                SSL_CTX_clear_options(state.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE());
+                SSL_CTX_clear_options(state.sslCtx, SSL_OP_CIPHER_SERVER_PREFERENCE());
             }
 
             // Disable compression if requested
             if (sslHostConfig.getDisableCompression()) {
-                SSL_CTX_set_options(state.ctx, SSL_OP_NO_COMPRESSION());
+                SSL_CTX_set_options(state.sslCtx, SSL_OP_NO_COMPRESSION());
             } else {
-                SSL_CTX_clear_options(state.ctx, SSL_OP_NO_COMPRESSION());
+                SSL_CTX_clear_options(state.sslCtx, SSL_OP_NO_COMPRESSION());
             }
 
             // Disable TLS Session Tickets (RFC4507) to protect perfect forward secrecy
             if (sslHostConfig.getDisableSessionTickets()) {
-                SSL_CTX_set_options(state.ctx, SSL_OP_NO_TICKET());
+                SSL_CTX_set_options(state.sslCtx, SSL_OP_NO_TICKET());
             } else {
-                SSL_CTX_clear_options(state.ctx, SSL_OP_NO_TICKET());
+                SSL_CTX_clear_options(state.sslCtx, SSL_OP_NO_TICKET());
             }
 
             // List the ciphers that the client is permitted to negotiate
-            if (SSL_CTX_set_cipher_list(state.ctx, CLinker.toCString(sslHostConfig.getCiphers(), state.scope)) <= 0) {
+            if (SSL_CTX_set_cipher_list(state.sslCtx, CLinker.toCString(sslHostConfig.getCiphers(), scope)) <= 0) {
                 log.warn(sm.getString("engine.failedCipherSuite", sslHostConfig.getCiphers()));
             }
 
@@ -643,44 +642,43 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                 value = SSL_VERIFY_FAIL_IF_NO_PEER_CERT();
                 break;
             }
-            certificateVerifyMode = value;
 
             // SSLContext.setVerify(state.ctx, value, sslHostConfig.getCertificateVerificationDepth());
-            if (SSL_CTX_set_default_verify_paths(state.ctx) > 0) {
-                var store = SSL_CTX_get_cert_store(state.ctx);
+            if (SSL_CTX_set_default_verify_paths(state.sslCtx) > 0) {
+                var store = SSL_CTX_get_cert_store(state.sslCtx);
                 X509_STORE_set_flags(store, 0);
             }
 
             // Set int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) callback
             MemoryAddress openSSLCallbackVerify =
-                    CLinker.getInstance().upcallStub(openSSLCallbackVerifyHandle.bindTo(this),
-                    openSSLCallbackVerifyFunctionDescriptor, state.scope);
+                    CLinker.getInstance().upcallStub(openSSLCallbackVerifyHandle,
+                    openSSLCallbackVerifyFunctionDescriptor, scope);
             // Leave this just in case but in Tomcat this is always set again by the engine
-            SSL_CTX_set_verify(state.ctx, value, openSSLCallbackVerify);
+            SSL_CTX_set_verify(state.sslCtx, value, openSSLCallbackVerify);
 
             // Trust and certificate verification
             try (var scope = ResourceScope.newConfinedScope()) {
                 var allocator = SegmentAllocator.ofScope(scope);
                 if (tms != null) {
                     // Client certificate verification based on custom trust managers
-                    x509TrustManager = chooseTrustManager(tms);
+                    state.x509TrustManager = chooseTrustManager(tms);
                     MemoryAddress openSSLCallbackCertVerify =
-                            CLinker.getInstance().upcallStub(openSSLCallbackCertVerifyHandle.bindTo(this),
-                            openSSLCallbackCertVerifyFunctionDescriptor, state.scope);
-                    SSL_CTX_set_cert_verify_callback(state.ctx, openSSLCallbackCertVerify, MemoryAddress.NULL);
+                            CLinker.getInstance().upcallStub(openSSLCallbackCertVerifyHandle,
+                            openSSLCallbackCertVerifyFunctionDescriptor, this.scope);
+                    SSL_CTX_set_cert_verify_callback(state.sslCtx, openSSLCallbackCertVerify, state.sslCtx);
 
                     // Pass along the DER encoded certificates of the accepted client
                     // certificate issuers, so that their subjects can be presented
                     // by the server during the handshake to allow the client choosing
                     // an acceptable certificate
-                    for (X509Certificate caCert : x509TrustManager.getAcceptedIssuers()) {
+                    for (X509Certificate caCert : state.x509TrustManager.getAcceptedIssuers()) {
                         //SSLContext.addClientCACertificateRaw(state.ctx, caCert.getEncoded());
                         var rawCACertificate = allocator.allocateArray(CLinker.C_CHAR, caCert.getEncoded());
                         var rawCACertificatePointer = allocator.allocate(CLinker.C_POINTER, rawCACertificate);
                         var x509CACert = d2i_X509(MemoryAddress.NULL, rawCACertificatePointer, rawCACertificate.byteSize());
                         if (MemoryAddress.NULL.equals(x509CACert)) {
                             logLastError(allocator, "openssl.errorLoadingCertificate");
-                        } else if (SSL_CTX_add_client_CA(state.ctx, x509CACert) <= 0) {
+                        } else if (SSL_CTX_add_client_CA(state.sslCtx, x509CACert) <= 0) {
                             logLastError(allocator, "openssl.errorAddingCertificate");
                         } else if (log.isDebugEnabled()) {
                             log.debug(sm.getString("openssl.addedClientCaCert", caCert.toString()));
@@ -695,16 +693,16 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                             ? CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificateFile()), scope) : null;
                     MemorySegment caCertificatePathNative = sslHostConfig.getCaCertificatePath() != null
                             ? CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificatePath()), scope) : null;
-                    if (SSL_CTX_load_verify_locations(state.ctx,
+                    if (SSL_CTX_load_verify_locations(state.sslCtx,
                             caCertificateFileNative == null ? MemoryAddress.NULL : caCertificateFileNative,
                             caCertificatePathNative == null ? MemoryAddress.NULL : caCertificatePathNative) <= 0) {
                         logLastError(allocator, "openssl.errorConfiguringLocations");
                     } else {
-                        var caCerts = SSL_CTX_get_client_CA_list(state.ctx);
+                        var caCerts = SSL_CTX_get_client_CA_list(state.sslCtx);
                         if (MemoryAddress.NULL.equals(caCerts)) {
                             caCerts = SSL_load_client_CA_file(caCertificateFileNative);
                             if (!MemoryAddress.NULL.equals(caCerts)) {
-                                SSL_CTX_set_client_CA_list(state.ctx, caCerts);
+                                SSL_CTX_set_client_CA_list(state.sslCtx, caCerts);
                             }
                         } else {
                             if (SSL_add_file_cert_subjects_to_stack(caCerts, caCertificateFileNative) <= 0) {
@@ -718,20 +716,20 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                 }
             }
 
-            if (negotiableProtocols != null && negotiableProtocols.size() > 0) {
+            if (state.negotiableProtocols != null && state.negotiableProtocols.size() > 0) {
                 // int openSSLCallbackAlpnSelectProto(MemoryAddress ssl, MemoryAddress out, MemoryAddress outlen,
                 //        MemoryAddress in, int inlen, MemoryAddress arg
                 MemoryAddress openSSLCallbackAlpnSelectProto =
-                        CLinker.getInstance().upcallStub(openSSLCallbackAlpnSelectProtoHandle.bindTo(this),
-                        openSSLCallbackAlpnSelectProtoFunctionDescriptor, state.scope);
-                SSL_CTX_set_alpn_select_cb(state.ctx, openSSLCallbackAlpnSelectProto, MemoryAddress.NULL);
+                        CLinker.getInstance().upcallStub(openSSLCallbackAlpnSelectProtoHandle,
+                        openSSLCallbackAlpnSelectProtoFunctionDescriptor, scope);
+                SSL_CTX_set_alpn_select_cb(state.sslCtx, openSSLCallbackAlpnSelectProto, state.sslCtx);
                 // Skip NPN (annoying and likely not useful anymore)
                 //SSLContext.setNpnProtos(state.ctx, protocolsArray, SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE);
             }
 
             // Apply OpenSSLConfCmd if used
             OpenSSLConf openSslConf = sslHostConfig.getOpenSslConf();
-            if (openSslConf != null && !MemoryAddress.NULL.equals(state.cctx)) {
+            if (openSslConf != null && !MemoryAddress.NULL.equals(state.confCtx)) {
                 // Check OpenSSLConfCmd if used
                 if (log.isDebugEnabled()) {
                     log.debug(sm.getString("openssl.checkConf"));
@@ -756,7 +754,7 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                     throw new SSLException(sm.getString("openssl.errApplyConf"), e);
                 }
                 // Reconfigure the enabled protocols
-                long opts = SSL_CTX_get_options(state.ctx);
+                long opts = SSL_CTX_get_options(state.sslCtx);
                 List<String> enabled = new ArrayList<>();
                 // Seems like there is no way to explicitly disable SSLv2Hello
                 // in OpenSSL so it is always enabled
@@ -782,7 +780,7 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                 sslHostConfig.setEnabledProtocols(
                         enabled.toArray(new String[0]));
                 // Reconfigure the enabled ciphers
-                sslHostConfig.setEnabledCiphers(getCiphers(state.ctx));
+                sslHostConfig.setEnabledCiphers(getCiphers(state.sslCtx));
             }
 
             sessionContext = new OpenSSLSessionContext(this);
@@ -790,7 +788,7 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
             // this is set so always set it in case an app is configured to
             // require it
             sessionContext.setSessionIdContext(DEFAULT_SESSION_ID_CONTEXT);
-            sslHostConfig.setOpenSslContext(state.ctx.toRawLongValue());
+            sslHostConfig.setOpenSslContext(state.sslCtx.toRawLongValue());
             initialized = true;
         } catch (Exception e) {
             log.warn(sm.getString("openssl.errorSSLCtxInit"), e);
@@ -800,7 +798,7 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
 
 
     public MemoryAddress getSSLContext() {
-        return state.ctx;
+        return state.sslCtx;
     }
 
     // DH *(*tmp_dh_callback)(SSL *ssl, int is_export, int keylength)
@@ -833,13 +831,18 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
 
     // int SSL_callback_alpn_select_proto(SSL* ssl, const unsigned char **out, unsigned char *outlen,
     //        const unsigned char *in, unsigned int inlen, void *arg)
-    public int openSSLCallbackAlpnSelectProto(MemoryAddress ssl, MemoryAddress out, MemoryAddress outlen,
+    public static int openSSLCallbackAlpnSelectProto(MemoryAddress ssl, MemoryAddress out, MemoryAddress outlen,
             MemoryAddress in, int inlen, MemoryAddress arg) {
+        ContextState state = getState(arg);
+        if (state == null) {
+            log.warn(sm.getString("context.noSSL", Long.valueOf(arg.toRawLongValue())));
+            return SSL_TLSEXT_ERR_NOACK();
+        }
         // It would be better to read byte by byte as the ALPN data is very small
         // However, the Java 17 API forces use of a scope later on, so create one for everything
         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
             byte[] advertisedBytes = in.asSegment(inlen, scope).toByteArray();
-            for (byte[] negotiableProtocolBytes : negotiableProtocols) {
+            for (byte[] negotiableProtocolBytes : state.negotiableProtocols) {
                 for (int i = 0; i <= advertisedBytes.length - negotiableProtocolBytes.length; i++) {
                     if (advertisedBytes[i] == negotiableProtocolBytes[0]) {
                         for (int j = 0; j < negotiableProtocolBytes.length; j++) {
@@ -863,86 +866,20 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
         }
     }
 
-    public synchronized int openSSLCallbackVerify(int preverify_ok, MemoryAddress /*X509_STORE_CTX*/ x509ctx) {
-        if (log.isDebugEnabled()) {
-            log.debug("Verification with mode [" + certificateVerifyMode + "]");
-        }
-        MemoryAddress ssl = X509_STORE_CTX_get_ex_data(x509ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
-        int ok = preverify_ok;
-        int errnum = X509_STORE_CTX_get_error(x509ctx);
-        int errdepth = X509_STORE_CTX_get_error_depth(x509ctx);
-        if (certificateVerifyMode == -1 /*SSL_CVERIFY_UNSET*/
-                || certificateVerifyMode == SSL_VERIFY_NONE()) {
-            return 1;
-        }
-        /*SSL_VERIFY_ERROR_IS_OPTIONAL(errnum) -> ((errnum == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
-                || (errnum == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)
-                || (errnum == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
-                || (errnum == X509_V_ERR_CERT_UNTRUSTED)
-                || (errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))*/
-        boolean verifyErrorIsOptional = (errnum == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT())
-                || (errnum == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN())
-                || (errnum == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY())
-                || (errnum == X509_V_ERR_CERT_UNTRUSTED())
-                || (errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE());
-        if (verifyErrorIsOptional && (certificateVerifyMode == OPTIONAL_NO_CA)) {
-            ok = 1;
-            SSL_set_verify_result(ssl, X509_V_OK());
-        }
-        /*
-         * Expired certificates vs. "expired" CRLs: by default, OpenSSL
-         * turns X509_V_ERR_CRL_HAS_EXPIRED into a "certificate_expired(45)"
-         * SSL alert, but that's not really the message we should convey to the
-         * peer (at the very least, it's confusing, and in many cases, it's also
-         * inaccurate, as the certificate itself may very well not have expired
-         * yet). We set the X509_STORE_CTX error to something which OpenSSL's
-         * s3_both.c:ssl_verify_alarm_type() maps to SSL_AD_CERTIFICATE_UNKNOWN,
-         * i.e. the peer will receive a "certificate_unknown(46)" alert.
-         * We do not touch errnum, though, so that later on we will still log
-         * the "real" error, as returned by OpenSSL.
-         */
-        if (ok == 0 && errnum == X509_V_ERR_CRL_HAS_EXPIRED()) {
-            X509_STORE_CTX_set_error(x509ctx, -1);
-        }
-
-        // OCSP
-        if (!noOcspCheck && (ok > 0)) {
-            /* If there was an optional verification error, it's not
-             * possible to perform OCSP validation since the issuer may be
-             * missing/untrusted.  Fail in that case.
-             */
-            if (verifyErrorIsOptional) {
-                if (certificateVerifyMode != OPTIONAL_NO_CA) {
-                    X509_STORE_CTX_set_error(x509ctx, X509_V_ERR_APPLICATION_VERIFICATION());
-                    errnum = X509_V_ERR_APPLICATION_VERIFICATION();
-                    ok = 0;
-                }
-            } else {
-                int ocspResponse = OpenSSLEngine.processOCSP(x509ctx);
-                if (ocspResponse == V_OCSP_CERTSTATUS_REVOKED()) {
-                    ok = 0;
-                    errnum = X509_STORE_CTX_get_error(x509ctx);
-                } else if (ocspResponse == V_OCSP_CERTSTATUS_UNKNOWN()) {
-                    errnum = X509_STORE_CTX_get_error(x509ctx);
-                    if (errnum <= 0) {
-                        ok = 0;
-                    }
-                }
-            }
-        }
-
-        if (errdepth > sslHostConfig.getCertificateVerificationDepth()) {
-            // Certificate Verification: Certificate Chain too long
-            ok = 0;
-        }
-        return ok;
+    public static int openSSLCallbackVerify(int preverify_ok, MemoryAddress /*X509_STORE_CTX*/ x509ctx) {
+        return OpenSSLEngine.openSSLCallbackVerify(preverify_ok, x509ctx);
     }
 
 
-    public int openSSLCallbackCertVerify(MemoryAddress /*X509_STORE_CTX*/ x509_ctx, MemoryAddress param) {
+    public static int openSSLCallbackCertVerify(MemoryAddress /*X509_STORE_CTX*/ x509_ctx, MemoryAddress param) {
         if (log.isDebugEnabled()) {
             log.debug("Certificate verification");
         }
+        ContextState state = getState(param);
+        if (state == null) {
+            log.warn(sm.getString("context.noSSL", Long.valueOf(param.toRawLongValue())));
+            return 0;
+        }
         MemoryAddress ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
         MemoryAddress /*STACK_OF(X509)*/ sk = X509_STORE_CTX_get0_untrusted(x509_ctx);
         int len = OPENSSL_sk_num(sk);
@@ -959,14 +896,14 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                 }
                 MemoryAddress buf = MemoryAccess.getAddress(bufPointer);
                 certificateChain[i] = buf.asSegment(length, scope).toByteArray();
-                CRYPTO_free(buf, OPENSSL_FILE(), OPENSSL_LINE()); // OPENSSL_free macro
+                CRYPTO_free(buf, MemoryAddress.NULL, 0); // OPENSSL_free macro
             }
             MemoryAddress cipher = SSL_get_current_cipher(ssl);
             String authMethod = (MemoryAddress.NULL.equals(cipher)) ? "UNKNOWN"
                     : getCipherAuthenticationMethod(SSL_CIPHER_get_auth_nid(cipher), SSL_CIPHER_get_kx_nid(cipher));
             X509Certificate[] peerCerts = certificates(certificateChain);
             try {
-                x509TrustManager.checkClientTrusted(peerCerts, authMethod);
+                state.x509TrustManager.checkClientTrusted(peerCerts, authMethod);
                 return 1;
             } catch (Exception e) {
                 log.debug(sm.getString("openssl.certificateVerificationFailed"), e);
@@ -1058,23 +995,26 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
         }
     }
 
-    private String callbackPassword = null;
+    private static ThreadLocal<String> callbackPasswordTheadLocal = new ThreadLocal<>();
 
-    public int openSSLCallbackPassword(MemoryAddress /*char **/ buf, int bufsiz, int verify, MemoryAddress /*void **/ cb) {
+    public static int openSSLCallbackPassword(MemoryAddress /*char **/ buf, int bufsiz, int verify, MemoryAddress /*void **/ cb) {
         if (log.isDebugEnabled()) {
             log.debug("Return password for certificate");
         }
-        try (var scope = ResourceScope.newConfinedScope()) {
-            MemorySegment callbackPasswordNative = CLinker.toCString(callbackPassword, scope);
-            if (callbackPasswordNative.byteSize() > bufsiz) {
-                // The password is too long
-                log.error(sm.getString("openssl.passwordTooLong"));
-            } else {
-                MemorySegment bufSegment = buf.asSegment(bufsiz, scope);
-                bufSegment.copyFrom(callbackPasswordNative);
-                return (int) callbackPasswordNative.byteSize();
+        String callbackPassword = callbackPasswordTheadLocal.get();
+        if (callbackPassword != null && callbackPassword.length() > 0) {
+            try (var scope = ResourceScope.newConfinedScope()) {
+                MemorySegment callbackPasswordNative = CLinker.toCString(callbackPassword, scope);
+                if (callbackPasswordNative.byteSize() > bufsiz) {
+                    // The password is too long
+                    log.error(sm.getString("openssl.passwordTooLong"));
+                } else {
+                    MemorySegment bufSegment = buf.asSegment(bufsiz, scope);
+                    bufSegment.copyFrom(callbackPasswordNative);
+                    return (int) callbackPasswordNative.byteSize();
+                }
             }
-        }        
+        }
         return 0;
     }
 
@@ -1086,8 +1026,6 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
             // Load Server key and certificate
             if (certificate.getCertificateFile() != null) {
                 // Set certificate
-                // Make the password available for the callback
-                callbackPassword = certificate.getCertificateKeyPassword();
                 //SSLContext.setCertificate(state.ctx,
                 //        SSLHostConfig.adjustRelativePath(certificate.getCertificateFile()),
                 //        SSLHostConfig.adjustRelativePath(certificate.getCertificateKeyFile()),
@@ -1116,6 +1054,7 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                     }
                     MemoryAddress passwordAddress = MemoryAddress.NULL;
                     int passwordLength = 0;
+                    String callbackPassword = certificate.getCertificateKeyPassword();
                     if (callbackPassword != null && callbackPassword.length() > 0) {
                         MemorySegment password = CLinker.toCString(callbackPassword, scope);
                         passwordAddress = password.address();
@@ -1149,7 +1088,12 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                     }
                     key = MemoryAddress.NULL;
                     for (int i = 0; i < 3; i++) {
-                        key = PEM_read_bio_PrivateKey(bio, MemoryAddress.NULL, openSSLCallbackPassword, MemoryAddress.NULL);
+                        try {
+                            callbackPasswordTheadLocal.set(certificate.getCertificateKeyPassword());
+                            key = PEM_read_bio_PrivateKey(bio, MemoryAddress.NULL, openSSLCallbackPassword, MemoryAddress.NULL);
+                        } finally {
+                            callbackPasswordTheadLocal.set(null);
+                        }
                         if (!MemoryAddress.NULL.equals(key)) {
                             break;
                         }
@@ -1173,7 +1117,12 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                         log.error(sm.getString("openssl.errorLoadingCertificate", certificate.getCertificateFile()));
                         return;
                     }
-                    cert = PEM_read_bio_X509_AUX(bio, MemoryAddress.NULL, openSSLCallbackPassword, MemoryAddress.NULL);
+                    try {
+                        callbackPasswordTheadLocal.set(certificate.getCertificateKeyPassword());
+                        cert = PEM_read_bio_X509_AUX(bio, MemoryAddress.NULL, openSSLCallbackPassword, MemoryAddress.NULL);
+                    } finally {
+                        callbackPasswordTheadLocal.set(null);
+                    }
                     if (MemoryAddress.NULL.equals(cert) &&
                             // Missing ERR_GET_REASON(ERR_peek_last_error())
                             /*int ERR_GET_REASON(unsigned long errcode) {
@@ -1197,15 +1146,15 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                         return;
                     }
                 }
-                if (SSL_CTX_use_certificate(state.ctx, cert) <= 0) {
+                if (SSL_CTX_use_certificate(state.sslCtx, cert) <= 0) {
                     logLastError(allocator, "openssl.errorLoadingCertificate");
                     return;
                 }
-                if (SSL_CTX_use_PrivateKey(state.ctx, key) <= 0) {
+                if (SSL_CTX_use_PrivateKey(state.sslCtx, key) <= 0) {
                     logLastError(allocator, "openssl.errorLoadingPrivateKey");
                     return;
                 }
-                if (SSL_CTX_check_private_key(state.ctx) <= 0) {
+                if (SSL_CTX_check_private_key(state.sslCtx) <= 0) {
                     logLastError(allocator, "openssl.errorPrivateKeyCheck");
                     return;
                 }
@@ -1214,10 +1163,10 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                     bio = BIO_new_file(certificateFileNative, CLinker.toCString("r", scope));
                     var dh = PEM_read_bio_DHparams(bio, MemoryAddress.NULL, MemoryAddress.NULL, MemoryAddress.NULL);
                     BIO_free(bio);
-                    // #  define SSL_CTX_set_tmp_dh(ctx,dh) \
-                    //           SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH,0,(char *)(dh))
+                    // #  define SSL_CTX_set_tmp_dh(sslCtx,dh) \
+                    //           SSL_CTX_ctrl(sslCtx,SSL_CTRL_SET_TMP_DH,0,(char *)(dh))
                     if (!MemoryAddress.NULL.equals(dh)) {
-                        SSL_CTX_ctrl(state.ctx, SSL_CTRL_SET_TMP_DH(), 0, dh);
+                        SSL_CTX_ctrl(state.sslCtx, SSL_CTRL_SET_TMP_DH(), 0, dh);
                         DH_free(dh);
                     }
                 }
@@ -1228,24 +1177,23 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                 if (!MemoryAddress.NULL.equals(ecparams)) {
                     int nid = EC_GROUP_get_curve_name(ecparams);
                     var eckey = EC_KEY_new_by_curve_name(nid);
-                    // #  define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \
-                    //           SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)(ecdh))
-                    SSL_CTX_ctrl(state.ctx, SSL_CTRL_SET_TMP_ECDH(), 0, eckey);
+                    // #  define SSL_CTX_set_tmp_ecdh(sslCtx,ecdh) \
+                    //           SSL_CTX_ctrl(sslCtx,SSL_CTRL_SET_TMP_ECDH,0,(char *)(ecdh))
+                    SSL_CTX_ctrl(state.sslCtx, SSL_CTRL_SET_TMP_ECDH(), 0, eckey);
                     EC_KEY_free(eckey);
                     EC_GROUP_free(ecparams);
                 }
                 // Set callback for DH parameters
                 MemoryAddress openSSLCallbackTmpDH = CLinker.getInstance().upcallStub(openSSLCallbackTmpDHHandle,
-                        openSSLCallbackTmpDHFunctionDescriptor, state.scope);
-                SSL_CTX_set_tmp_dh_callback(state.ctx, openSSLCallbackTmpDH);
-                callbackPassword = null;
+                        openSSLCallbackTmpDHFunctionDescriptor, scope);
+                SSL_CTX_set_tmp_dh_callback(state.sslCtx, openSSLCallbackTmpDH);
                 // Set certificate chain file
                 if (certificate.getCertificateChainFile() != null) {
                     var certificateChainFileNative =
                             CLinker.toCString(SSLHostConfig.adjustRelativePath(certificate.getCertificateChainFile()), scope);
                     // SSLContext.setCertificateChainFile(state.ctx,
                     //        SSLHostConfig.adjustRelativePath(certificate.getCertificateChainFile()), false);
-                    if (SSL_CTX_use_certificate_chain_file(state.ctx, certificateChainFileNative) <= 0) {
+                    if (SSL_CTX_use_certificate_chain_file(state.sslCtx, certificateChainFileNative) <= 0) {
                         log.error(sm.getString("openssl.errorLoadingCertificate", certificate.getCertificateChainFile()));
                     }
                 }
@@ -1255,7 +1203,7 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                 //                sslHostConfig.getCertificateRevocationListFile()),
                 //        SSLHostConfig.adjustRelativePath(
                 //                sslHostConfig.getCertificateRevocationListPath()));
-                MemoryAddress certificateStore = (state.ctx);
+                MemoryAddress certificateStore = (state.sslCtx);
                 if (sslHostConfig.getCertificateRevocationListFile() != null) {
                     MemoryAddress x509Lookup = X509_STORE_add_lookup(certificateStore, X509_LOOKUP_file());
                     var certificateRevocationListFileNative =
@@ -1311,22 +1259,22 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                     logLastError(allocator, "openssl.errorLoadingPrivateKey");
                     return;
                 }
-                if (SSL_CTX_use_certificate(state.ctx, x509cert) <= 0) {
+                if (SSL_CTX_use_certificate(state.sslCtx, x509cert) <= 0) {
                     logLastError(allocator, "openssl.errorLoadingCertificate");
                     return;
                 }
-                if (SSL_CTX_use_PrivateKey(state.ctx, privateKeyAddress) <= 0) {
+                if (SSL_CTX_use_PrivateKey(state.sslCtx, privateKeyAddress) <= 0) {
                     logLastError(allocator, "openssl.errorLoadingPrivateKey");
                     return;
                 }
-                if (SSL_CTX_check_private_key(state.ctx) <= 0) {
+                if (SSL_CTX_check_private_key(state.sslCtx) <= 0) {
                     logLastError(allocator, "openssl.errorPrivateKeyCheck");
                     return;
                 }
                 // Set callback for DH parameters
                 MemoryAddress openSSLCallbackTmpDH = CLinker.getInstance().upcallStub(openSSLCallbackTmpDHHandle,
-                        openSSLCallbackTmpDHFunctionDescriptor, state.scope);
-                SSL_CTX_set_tmp_dh_callback(state.ctx, openSSLCallbackTmpDH);
+                        openSSLCallbackTmpDHFunctionDescriptor, scope);
+                SSL_CTX_set_tmp_dh_callback(state.sslCtx, openSSLCallbackTmpDH);
                 for (int i = 1; i < chain.length; i++) {
                     //SSLContext.addChainCertificateRaw(state.ctx, chain[i].getEncoded());
                     var rawCertificateChain = allocator.allocateArray(CLinker.C_CHAR, chain[i].getEncoded());
@@ -1336,8 +1284,8 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
                         logLastError(allocator, "openssl.errorLoadingCertificate");
                         return;
                     }
-                    // # define SSL_CTX_add0_chain_cert(ctx,x509) SSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN_CERT,0,(char *)(x509))
-                    if (SSL_CTX_ctrl(state.ctx, SSL_CTRL_CHAIN_CERT(), 0, x509certChain) <= 0) {
+                    // # define SSL_CTX_add0_chain_cert(sslCtx,x509) SSL_CTX_ctrl(sslCtx,SSL_CTRL_CHAIN_CERT,0,(char *)(x509))
+                    if (SSL_CTX_ctrl(state.sslCtx, SSL_CTRL_CHAIN_CERT(), 0, x509certChain) <= 0) {
                         logLastError(allocator, "openssl.errorAddingCertificate");
                         return;
                     }
@@ -1424,7 +1372,7 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
 
     @Override
     public synchronized SSLEngine createSSLEngine() {
-        return new OpenSSLEngine(cleaner, state.ctx, defaultProtocol, false, sessionContext,
+        return new OpenSSLEngine(state.sslCtx, defaultProtocol, false, sessionContext,
                 alpn, initialized,
                 sslHostConfig.getCertificateVerificationDepth(),
                 sslHostConfig.getCertificateVerification() == CertificateVerification.OPTIONAL_NO_CA,
@@ -1462,36 +1410,33 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
     @Override
     public X509Certificate[] getAcceptedIssuers() {
         X509Certificate[] acceptedCerts = null;
-        if (x509TrustManager != null) {
-            acceptedCerts = x509TrustManager.getAcceptedIssuers();
+        if (state.x509TrustManager != null) {
+            acceptedCerts = state.x509TrustManager.getAcceptedIssuers();
         }
         return acceptedCerts;
     }
 
 
-    private static class OpenSSLState implements Runnable {
+    private static class ContextState implements Runnable {
 
-        final ResourceScope scope;
         // SSL context
-        final MemoryAddress ctx;
+        private final MemoryAddress sslCtx;
         // OpenSSLConfCmd context
-        final MemoryAddress cctx;
-
-        private OpenSSLState(ResourceScope scope, MemoryAddress cctx, MemoryAddress ctx) {
-            this.scope = scope;
-            this.cctx = cctx;
-            this.ctx = ctx;
+        private final MemoryAddress confCtx;
+        private final List<byte[]> negotiableProtocols;
+        private X509TrustManager x509TrustManager = null;
+
+        private ContextState(MemoryAddress sslCtx, MemoryAddress confCtx, List<byte[]> negotiableProtocols) {
+            this.sslCtx = sslCtx;
+            this.confCtx = confCtx;
+            this.negotiableProtocols = negotiableProtocols;
         }
 
         @Override
         public void run() {
-            try {
-                SSL_CTX_free(ctx);
-                if (!MemoryAddress.NULL.equals(cctx)) {
-                    SSL_CONF_CTX_free(cctx);
-                }
-            } finally {
-                scope.close();
+            SSL_CTX_free(sslCtx);
+            if (!MemoryAddress.NULL.equals(confCtx)) {
+                SSL_CONF_CTX_free(confCtx);
             }
         }
     }
diff --git a/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLEngine.java b/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLEngine.java
index eb9f074..4fb17a4 100644
--- a/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLEngine.java
+++ b/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLEngine.java
@@ -21,7 +21,6 @@ import java.io.InputStream;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
-import java.lang.ref.Cleaner;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -178,9 +177,12 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
 
     private static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL";
 
-    private static final ConcurrentHashMap<Long, OpenSSLState> states = new ConcurrentHashMap<>();
+    private static final ConcurrentHashMap<Long, EngineState> states = new ConcurrentHashMap<>();
+    private static EngineState getState(MemoryAddress ssl) {
+        return states.get(Long.valueOf(ssl.toRawLongValue()));
+    }
 
-    private final OpenSSLState state;
+    private final EngineState state;
     private final ResourceScope scope;
 
     private enum Accepted { NOT, IMPLICIT, EXPLICIT }
@@ -222,8 +224,6 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
     /**
      * Creates a new instance
      *
-     * @param cleaner   Used to clean up references to instances before they are
-     *                  garbage collected
      * @param sslCtx an OpenSSL {@code SSL_CTX} object
      * @param fallbackApplicationProtocol the fallback application protocol
      * @param clientMode {@code true} if this is used for clients, {@code false}
@@ -238,7 +238,7 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
      * @param certificateVerificationOptionalNoCA Skip CA verification in
      *   optional mode
      */
-    OpenSSLEngine(Cleaner cleaner, MemoryAddress sslCtx, String fallbackApplicationProtocol,
+    OpenSSLEngine(MemoryAddress sslCtx, String fallbackApplicationProtocol,
             boolean clientMode, OpenSSLSessionContext sessionContext, boolean alpn,
             boolean initialized, int certificateVerificationDepth,
             boolean certificateVerificationOptionalNoCA, boolean noOcspCheck) {
@@ -265,7 +265,9 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
         var internalBIO = MemoryAccess.getAddress(internalBIOPointer);
         var networkBIO = MemoryAccess.getAddress(networkBIOPointer);
         SSL_set_bio(ssl, internalBIO, internalBIO);
-        state = new OpenSSLState(scope, ssl, networkBIO, certificateVerificationDepth, noOcspCheck);
+        state = new EngineState(ssl, networkBIO, certificateVerificationDepth, noOcspCheck);
+        states.put(Long.valueOf(ssl.address().toRawLongValue()), state);
+        scope.addCloseAction(state);
         this.fallbackApplicationProtocol = fallbackApplicationProtocol;
         this.clientMode = clientMode;
         this.sessionContext = sessionContext;
@@ -975,7 +977,7 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
         MemoryAddress buf = MemoryAccess.getAddress(bufPointer);
         byte[] certificate = buf.asSegment(length, scope).toByteArray();
         X509_free(x509);
-        CRYPTO_free(buf, OPENSSL_FILE(), OPENSSL_LINE()); // OPENSSL_free macro
+        CRYPTO_free(buf, MemoryAddress.NULL, 0); // OPENSSL_free macro
         return certificate;
     }
 
@@ -998,7 +1000,7 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
             MemoryAddress buf = MemoryAccess.getAddress(bufPointer);
             byte[] certificate = buf.asSegment(length, scope).toByteArray();
             certificateChain[i] = certificate;
-            CRYPTO_free(buf, OPENSSL_FILE(), OPENSSL_LINE()); // OPENSSL_free macro
+            CRYPTO_free(buf, MemoryAddress.NULL, 0); // OPENSSL_free macro
         }
         return certificateChain;
     }
@@ -1273,7 +1275,7 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
     }
 
     public static void openSSLCallbackInfo(MemoryAddress ssl, int where, int ret) {
-        OpenSSLState state = states.get(Long.valueOf(ssl.toRawLongValue()));
+        EngineState state = getState(ssl);
         if (state == null) {
             logger.warn(sm.getString("engine.noSSL", Long.valueOf(ssl.toRawLongValue())));
             return;
@@ -1285,7 +1287,7 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
 
     public static int openSSLCallbackVerify(int preverify_ok, MemoryAddress /*X509_STORE_CTX*/ x509ctx) {
         MemoryAddress ssl = X509_STORE_CTX_get_ex_data(x509ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
-        OpenSSLState state = states.get(Long.valueOf(ssl.toRawLongValue()));
+        EngineState state = getState(ssl);
         if (state == null) {
             logger.warn(sm.getString("engine.noSSL", Long.valueOf(ssl.toRawLongValue())));
             return 0;
@@ -1854,7 +1856,7 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
 
     }
 
-    private static class OpenSSLState implements Runnable {
+    private static class EngineState implements Runnable {
 
         // FIXME: MemorySegment is supposed to be used but creates GC roots to the implicit scope
         private final MemoryAddress ssl;
@@ -1866,10 +1868,8 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
         private int certificateVerifyMode = 0;
         private int handshakeCount = 0;
 
-        private OpenSSLState(ResourceScope scope, MemoryAddress ssl, MemoryAddress networkBIO,
+        private EngineState(MemoryAddress ssl, MemoryAddress networkBIO,
                 int certificateVerificationDepth, boolean noOcspCheck) {
-            states.put(Long.valueOf(ssl.address().toRawLongValue()), this);
-            scope.addCloseAction(this);
             this.ssl = ssl;
             this.networkBIO = networkBIO;
             this.certificateVerificationDepth = certificateVerificationDepth;
diff --git a/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLifecycleListener.java b/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLifecycleListener.java
index 17699ff..fa6336b 100644
--- a/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLifecycleListener.java
+++ b/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLifecycleListener.java
@@ -265,6 +265,7 @@ public class OpenSSLLifecycleListener implements LifecycleListener {
             }
         }
 
+        // FIXME: OPENSSL_VERSION_TEXT is actually hardcoded by jextract so this is not useful
         log.info(sm.getString("listener.initializedOpenSSL", new String(OPENSSL_VERSION_TEXT().toByteArray())));
         OpenSSLStatus.setAvailable(true);
     }
diff --git a/modules/openssl-java17/src/main/resources/org/apache/tomcat/util/net/openssl/panama/LocalStrings.properties b/modules/openssl-java17/src/main/resources/org/apache/tomcat/util/net/openssl/panama/LocalStrings.properties
index d236292..a2827a5 100644
--- a/modules/openssl-java17/src/main/resources/org/apache/tomcat/util/net/openssl/panama/LocalStrings.properties
+++ b/modules/openssl-java17/src/main/resources/org/apache/tomcat/util/net/openssl/panama/LocalStrings.properties
@@ -24,7 +24,7 @@ engine.invalidBufferArray=offset: [{0}], length: [{1}] (expected: offset <= offs
 engine.invalidDestinationBuffersState=The state of the destination buffers changed concurrently while unwrapping bytes
 engine.invalidOCSPURL=The OCSP URL is invalid: [{0}]
 engine.noRestrictSessionCreation=OpenSslEngine does not permit restricting the engine to only resuming existing sessions
-engine.noSSL=No SSL sound for address [{0}]
+engine.noSSL=No SSL found for address [{0}]
 engine.noSSLContext=No SSL context
 engine.noSession=SSL session ID not available
 engine.nullBuffer=Null buffer
@@ -59,6 +59,7 @@ openssl.errorSSLCtxInit=Error initializing SSL context
 openssl.keyManagerMissing=No key manager found
 openssl.makeConf=Creating OpenSSLConf context
 openssl.noCACerts=No CA certificates were configured
+openssl.noSSL=No SSL context found for address [{0}]
 openssl.nonJsseCertificate=The certificate [{0}] or its private key [{1}] could not be processed using a JSSE key manager and will be given directly to OpenSSL
 openssl.nonJsseChain=The certificate chain [{0}] was not specified or was not valid and JSSE requires a valid certificate chain so attempting to use OpenSSL directly
 openssl.passwordTooLong=The certificate password is too long

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