diff --git a/rhel-150714.patch b/rhel-150714.patch
deleted file mode 100644
index ec1eabb..0000000
--- a/rhel-150714.patch
+++ /dev/null
@@ -1,3954 +0,0 @@
-diff --git a/java/org/apache/tomcat/util/net/openssl/OpenSSLStatus.java b/java/org/apache/tomcat/util/net/openssl/OpenSSLStatus.java
-index 1ad7d3dc84..749813bc38 100644
---- a/java/org/apache/tomcat/util/net/openssl/OpenSSLStatus.java
-+++ b/java/org/apache/tomcat/util/net/openssl/OpenSSLStatus.java
-@@ -38,9 +38,10 @@ public class OpenSSLStatus {
- private static volatile boolean useOpenSSL = true;
- private static volatile boolean instanceCreated = false;
- private static volatile long version = 0;
-+ private static volatile int majorVersion = 0;
-+ private static volatile int minorVersion = 0;
- private static volatile Name name = Name.UNKNOWN;
-
--
- public static boolean isLibraryInitialized() {
- return libraryInitialized;
- }
-@@ -95,6 +96,34 @@ public class OpenSSLStatus {
- OpenSSLStatus.version = version;
- }
-
-+ /**
-+ * @return the majorVersion
-+ */
-+ public static int getMajorVersion() {
-+ return majorVersion;
-+ }
-+
-+ /**
-+ * @param majorVersion the majorVersion to set
-+ */
-+ public static void setMajorVersion(int majorVersion) {
-+ OpenSSLStatus.majorVersion = majorVersion;
-+ }
-+
-+ /**
-+ * @return the minorVersion
-+ */
-+ public static int getMinorVersion() {
-+ return minorVersion;
-+ }
-+
-+ /**
-+ * @param minorVersion the minorVersion to set
-+ */
-+ public static void setMinorVersion(int minorVersion) {
-+ OpenSSLStatus.minorVersion = minorVersion;
-+ }
-+
- /**
- * @return the library name
- */
-@@ -116,4 +145,18 @@ public class OpenSSLStatus {
- return Name.OPENSSL3.equals(name);
- }
-
-+ /**
-+ * @return true if running with BoringSSL
-+ */
-+ public static boolean isBoringSSL() {
-+ return Name.BORINGSSL.equals(name);
-+ }
-+
-+ /**
-+ * @return true if running with LibreSSL < 3.5
-+ */
-+ public static boolean isLibreSSLPre35() {
-+ return Name.LIBRESSL.equals(name) && ((majorVersion == 3 && minorVersion < 5) || majorVersion < 3);
-+ }
-+
- }
-diff --git a/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLEngine.java b/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLEngine.java
-index bfb9b6f20a..960fa0459f 100644
---- a/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLEngine.java
-+++ b/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLEngine.java
-@@ -59,6 +59,7 @@ import org.apache.tomcat.util.buf.Asn1Parser;
- import org.apache.tomcat.util.http.Method;
- import org.apache.tomcat.util.net.Constants;
- import org.apache.tomcat.util.net.SSLUtil;
-+import org.apache.tomcat.util.net.openssl.OpenSSLStatus;
- import org.apache.tomcat.util.net.openssl.ciphers.OpenSSLCipherConfigurationParser;
- import org.apache.tomcat.util.openssl.SSL_CTX_set_verify$callback;
- import org.apache.tomcat.util.openssl.SSL_set_info_callback$cb;
-@@ -68,7 +69,7 @@ import org.apache.tomcat.util.openssl.openssl_h_Compatibility;
- import org.apache.tomcat.util.res.StringManager;
-
- /**
-- * Implements a {@link SSLEngine} using OpenSSL BIO
-+ * Implements a {@link SSLEngine} using OpenSSL BIO
- * abstractions.
- */
- public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolInfo {
-@@ -137,7 +138,7 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
- private volatile boolean destroyed;
-
- // Use an invalid cipherSuite until the handshake is completed
-- // See https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SSLEngine.html#getSession()
-+ // See https://docs.oracle.com/en/java/javase/21/docs/api/java.base/javax/net/ssl/SSLEngine.html#getSession()
- private volatile String version;
- private volatile String cipher;
- private volatile String applicationProtocol;
-@@ -1076,7 +1077,7 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
- case NONE -> SSL_VERIFY_NONE();
- case REQUIRE -> SSL_VERIFY_FAIL_IF_NO_PEER_CERT();
- case OPTIONAL ->
-- certificateVerificationOptionalNoCA ? OpenSSLContext.OPTIONAL_NO_CA : SSL_VERIFY_PEER();
-+ certificateVerificationOptionalNoCA ? OpenSSLContext.OPTIONAL_NO_CA : SSL_VERIFY_PEER();
- };
- // Set int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) callback
- int value = switch (mode) {
-@@ -1138,6 +1139,9 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
- ok = 1;
- openssl_h_Compatibility.SSL_set_verify_result(state.ssl, X509_V_OK());
- }
-+ if (ok == 0 && errnum == X509_V_ERR_UNABLE_TO_GET_CRL()) {
-+ ok = 1;
-+ }
- /*
- * 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
-@@ -1168,9 +1172,10 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
- if (ocspResponse == V_OCSP_CERTSTATUS_REVOKED()) {
- ok = 0;
- errnum = X509_STORE_CTX_get_error(x509ctx);
-+ X509_STORE_CTX_set_error(x509ctx, X509_V_ERR_CERT_REVOKED());
- } else if (ocspResponse == V_OCSP_CERTSTATUS_UNKNOWN()) {
- errnum = X509_STORE_CTX_get_error(x509ctx);
-- if (errnum <= 0) {
-+ if (errnum != X509_V_ERR_UNABLE_TO_GET_CRL() && (errnum == X509_V_ERR_APPLICATION_VERIFICATION() || errnum != 0)) {
- ok = 0;
- }
- }
-@@ -1196,46 +1201,53 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
- // don't do OCSP checking for valid self-issued certs
- X509_STORE_CTX_set_error(x509ctx, X509_V_OK());
- } else {
-- // If we can't get the issuer, we cannot perform OCSP verification
-- MemorySegment issuer = X509_STORE_CTX_get0_current_issuer(x509ctx);
-- if (!MemorySegment.NULL.equals(issuer)) {
-- // sslutils.c ssl_ocsp_request(x509, issuer, x509ctx);
-- int nid = X509_get_ext_by_NID(x509, NID_info_access(), -1);
-- if (nid >= 0) {
-- try (var localArenal = Arena.ofConfined()) {
-- MemorySegment ext = X509_get_ext(x509, nid);
-- MemorySegment os = X509_EXTENSION_get_data(ext);
-- int length = ASN1_STRING_length(os);
-- MemorySegment data = ASN1_STRING_get0_data(os);
-- // ocsp_urls = decode_OCSP_url(os);
-- byte[] asn1String =
-- data.reinterpret(length, localArenal, null).toArray(ValueLayout.JAVA_BYTE);
-- Asn1Parser parser = new Asn1Parser(asn1String);
-- // Parse the byte sequence
-- ArrayList urls = new ArrayList<>();
-- try {
-- parseOCSPURLs(parser, urls);
-- } catch (Exception e) {
-- log.error(sm.getString("engine.ocspParseError"), e);
-- }
-- if (!urls.isEmpty()) {
-- // Use OpenSSL to build OCSP request
-- for (String urlString : urls) {
-- try {
-- URL url = (new URI(urlString)).toURL();
-- ocspResponse = processOCSPRequest(url, issuer, x509, x509ctx, localArenal);
-- if (log.isDebugEnabled()) {
-- log.debug(sm.getString("engine.ocspResponse", urlString,
-- Integer.toString(ocspResponse)));
-+ try (var localArena = Arena.ofConfined()) {
-+ // If we can't get the issuer, we cannot perform OCSP verification
-+ MemorySegment x509IssuerPointer = localArena.allocateFrom(ValueLayout.ADDRESS, MemorySegment.NULL);
-+ int res = X509_STORE_CTX_get1_issuer(x509IssuerPointer, x509ctx, x509);
-+ if (res > 0) {
-+ MemorySegment issuer = MemorySegment.NULL;
-+ try {
-+ issuer = x509IssuerPointer.get(ValueLayout.ADDRESS, 0);
-+ // sslutils.c ssl_ocsp_request(x509, issuer, x509ctx);
-+ int nid = X509_get_ext_by_NID(x509, NID_info_access(), -1);
-+ if (nid >= 0) {
-+ MemorySegment ext = X509_get_ext(x509, nid);
-+ MemorySegment os = X509_EXTENSION_get_data(ext);
-+ int length = ASN1_STRING_length(os);
-+ MemorySegment data = ASN1_STRING_get0_data(os);
-+ // ocsp_urls = decode_OCSP_url(os);
-+ byte[] asn1String =
-+ data.reinterpret(length, localArena, null).toArray(ValueLayout.JAVA_BYTE);
-+ Asn1Parser parser = new Asn1Parser(asn1String);
-+ // Parse the byte sequence
-+ ArrayList urls = new ArrayList<>();
-+ try {
-+ parseOCSPURLs(parser, urls);
-+ } catch (Exception e) {
-+ log.error(sm.getString("engine.ocspParseError"), e);
-+ }
-+ if (!urls.isEmpty()) {
-+ // Use OpenSSL to build OCSP request
-+ for (String urlString : urls) {
-+ try {
-+ URL url = (new URI(urlString)).toURL();
-+ ocspResponse = processOCSPRequest(url, issuer, x509, x509ctx, localArena);
-+ if (log.isDebugEnabled()) {
-+ log.debug(sm.getString("engine.ocspResponse", urlString,
-+ Integer.toString(ocspResponse)));
-+ }
-+ } catch (MalformedURLException | URISyntaxException e) {
-+ log.warn(sm.getString("engine.invalidOCSPURL", urlString));
-+ }
-+ if (ocspResponse != V_OCSP_CERTSTATUS_UNKNOWN()) {
-+ break;
- }
-- } catch (MalformedURLException | URISyntaxException e) {
-- log.warn(sm.getString("engine.invalidOCSPURL", urlString));
-- }
-- if (ocspResponse != V_OCSP_CERTSTATUS_UNKNOWN()) {
-- break;
- }
- }
- }
-+ } finally {
-+ X509_free(issuer);
- }
- }
- }
-@@ -1275,6 +1287,9 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
-
- private static int processOCSPRequest(URL url, MemorySegment issuer, MemorySegment x509,
- MemorySegment /* X509_STORE_CTX */ x509ctx, Arena localArena) {
-+ if (OpenSSLStatus.Name.BORINGSSL.equals(OpenSSLStatus.getName())) {
-+ return V_OCSP_CERTSTATUS_UNKNOWN();
-+ }
- MemorySegment ocspRequest = MemorySegment.NULL;
- MemorySegment ocspResponse = MemorySegment.NULL;
- MemorySegment id;
-@@ -1574,7 +1589,7 @@ public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolIn
- }
-
- private Principal principal(Certificate[] certs) {
-- return ((java.security.cert.X509Certificate) certs[0]).getIssuerX500Principal();
-+ return ((java.security.cert.X509Certificate) certs[0]).getSubjectX500Principal();
- }
-
- @Override
-diff --git a/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLibrary.java b/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLibrary.java
-index 7272db9cf2..c1bb2cb664 100644
---- a/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLibrary.java
-+++ b/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLibrary.java
-@@ -178,6 +178,8 @@ public class OpenSSLLibrary {
- initLibrary();
-
- OpenSSLStatus.setVersion(OpenSSL_version_num());
-+ OpenSSLStatus.setMajorVersion(openssl_h_Compatibility.MAJOR);
-+ OpenSSLStatus.setMinorVersion(openssl_h_Compatibility.MINOR);
- if (openssl_h_Compatibility.OPENSSL3) {
- OpenSSLStatus.setName(OpenSSLStatus.Name.OPENSSL3);
- } else if (openssl_h_Compatibility.OPENSSL) {
-diff --git a/java/org/apache/tomcat/util/openssl/openssl_h.java b/java/org/apache/tomcat/util/openssl/openssl_h.java
-index 0c2465b633..cbd8a5a0d4 100644
---- a/java/org/apache/tomcat/util/openssl/openssl_h.java
-+++ b/java/org/apache/tomcat/util/openssl/openssl_h.java
-@@ -196,6 +196,16 @@ public class openssl_h {
- return X509_V_OK;
- }
-
-+ private static final int X509_V_ERR_UNABLE_TO_GET_CRL = (int) 3L;
-+
-+ /**
-+ * {@snippet lang = c : * #define X509_V_ERR_UNABLE_TO_GET_CRL 3
-+ * }
-+ */
-+ public static int X509_V_ERR_UNABLE_TO_GET_CRL() {
-+ return X509_V_ERR_UNABLE_TO_GET_CRL;
-+ }
-+
- private static final int X509_V_ERR_CRL_HAS_EXPIRED = (int) 12L;
-
- /**
-@@ -246,6 +256,16 @@ public class openssl_h {
- return X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE;
- }
-
-+ private static final int X509_V_ERR_CERT_REVOKED = (int) 23L;
-+
-+ /**
-+ * {@snippet lang = c : * #define X509_V_ERR_CERT_REVOKED 23
-+ * }
-+ */
-+ public static int X509_V_ERR_CERT_REVOKED() {
-+ return X509_V_ERR_CERT_REVOKED;
-+ }
-+
- private static final int X509_V_ERR_CERT_UNTRUSTED = (int) 27L;
-
- /**
-@@ -266,6 +286,46 @@ public class openssl_h {
- return X509_V_ERR_APPLICATION_VERIFICATION;
- }
-
-+ private static final int X509_V_ERR_OCSP_RESP_INVALID = (int) 96L;
-+
-+ /**
-+ * {@snippet lang = c : * #define X509_V_ERR_OCSP_RESP_INVALID 96
-+ * }
-+ */
-+ public static int X509_V_ERR_OCSP_RESP_INVALID() {
-+ return X509_V_ERR_OCSP_RESP_INVALID;
-+ }
-+
-+ private static final int X509_V_ERR_OCSP_SIGNATURE_FAILURE = (int) 97L;
-+
-+ /**
-+ * {@snippet lang = c : * #define X509_V_ERR_OCSP_SIGNATURE_FAILURE 97
-+ * }
-+ */
-+ public static int X509_V_ERR_OCSP_SIGNATURE_FAILURE() {
-+ return X509_V_ERR_OCSP_SIGNATURE_FAILURE;
-+ }
-+
-+ private static final int X509_V_ERR_OCSP_NOT_YET_VALID = (int) 98L;
-+
-+ /**
-+ * {@snippet lang = c : * #define X509_V_ERR_OCSP_NOT_YET_VALID 98
-+ * }
-+ */
-+ public static int X509_V_ERR_OCSP_NOT_YET_VALID() {
-+ return X509_V_ERR_OCSP_NOT_YET_VALID;
-+ }
-+
-+ private static final int X509_V_ERR_OCSP_HAS_EXPIRED = (int) 99L;
-+
-+ /**
-+ * {@snippet lang = c : * #define X509_V_ERR_OCSP_HAS_EXPIRED 99
-+ * }
-+ */
-+ public static int X509_V_ERR_OCSP_HAS_EXPIRED() {
-+ return X509_V_ERR_OCSP_HAS_EXPIRED;
-+ }
-+
- private static final int X509_V_FLAG_CRL_CHECK = (int) 4L;
-
- /**
-@@ -3071,6 +3131,66 @@ public class openssl_h {
- }
- }
-
-+ private static class X509_STORE_CTX_get0_store {
-+ public static final FunctionDescriptor DESC = FunctionDescriptor.of(
-+ openssl_h.C_POINTER,
-+ openssl_h.C_POINTER
-+ );
-+
-+ public static final MemorySegment ADDR = openssl_h.findOrThrow("X509_STORE_CTX_get0_store");
-+
-+ public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
-+ }
-+
-+ /**
-+ * Function descriptor for:
-+ * {@snippet lang=c :
-+ * X509_STORE *X509_STORE_CTX_get0_store(const X509_STORE_CTX *ctx)
-+ * }
-+ */
-+ public static FunctionDescriptor X509_STORE_CTX_get0_store$descriptor() {
-+ return X509_STORE_CTX_get0_store.DESC;
-+ }
-+
-+ /**
-+ * Downcall method handle for:
-+ * {@snippet lang=c :
-+ * X509_STORE *X509_STORE_CTX_get0_store(const X509_STORE_CTX *ctx)
-+ * }
-+ */
-+ public static MethodHandle X509_STORE_CTX_get0_store$handle() {
-+ return X509_STORE_CTX_get0_store.HANDLE;
-+ }
-+
-+ /**
-+ * Address for:
-+ * {@snippet lang=c :
-+ * X509_STORE *X509_STORE_CTX_get0_store(const X509_STORE_CTX *ctx)
-+ * }
-+ */
-+ public static MemorySegment X509_STORE_CTX_get0_store$address() {
-+ return X509_STORE_CTX_get0_store.ADDR;
-+ }
-+
-+ /**
-+ * {@snippet lang=c :
-+ * X509_STORE *X509_STORE_CTX_get0_store(const X509_STORE_CTX *ctx)
-+ * }
-+ */
-+ public static MemorySegment X509_STORE_CTX_get0_store(MemorySegment ctx) {
-+ var mh$ = X509_STORE_CTX_get0_store.HANDLE;
-+ try {
-+ if (TRACE_DOWNCALLS) {
-+ traceDowncall("X509_STORE_CTX_get0_store", ctx);
-+ }
-+ return (MemorySegment)mh$.invokeExact(ctx);
-+ } catch (Error | RuntimeException ex) {
-+ throw ex;
-+ } catch (Throwable ex$) {
-+ throw new AssertionError("should not reach here", ex$);
-+ }
-+ }
-+
- private static class X509_STORE_CTX_get0_untrusted {
- public static final FunctionDescriptor DESC = FunctionDescriptor.of(openssl_h.C_POINTER, openssl_h.C_POINTER);
-
-@@ -3584,52 +3704,52 @@ public class openssl_h {
- }
- }
-
-- private static class X509_STORE_CTX_get0_current_issuer {
-- public static final FunctionDescriptor DESC = FunctionDescriptor.of(openssl_h.C_POINTER, openssl_h.C_POINTER);
-+ private static class X509_STORE_CTX_get1_issuer {
-+ public static final FunctionDescriptor DESC = FunctionDescriptor.of(openssl_h.C_INT, openssl_h.C_POINTER, openssl_h.C_POINTER, openssl_h.C_POINTER);
-
-- public static final MemorySegment ADDR = openssl_h.findOrThrow("X509_STORE_CTX_get0_current_issuer");
-+ public static final MemorySegment ADDR = openssl_h.findOrThrow("X509_STORE_CTX_get1_issuer");
-
- public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
- }
-
- /**
- * Function descriptor for:
-- * {@snippet lang = c : * X509 *X509_STORE_CTX_get0_current_issuer(const X509_STORE_CTX *ctx)
-+ * {@snippet lang = c : * int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
- * }
- */
-- public static FunctionDescriptor X509_STORE_CTX_get0_current_issuer$descriptor() {
-- return X509_STORE_CTX_get0_current_issuer.DESC;
-+ public static FunctionDescriptor X509_STORE_CTX_get1_issuer$descriptor() {
-+ return X509_STORE_CTX_get1_issuer.DESC;
- }
-
- /**
- * Downcall method handle for:
-- * {@snippet lang = c : * X509 *X509_STORE_CTX_get0_current_issuer(const X509_STORE_CTX *ctx)
-+ * {@snippet lang = c : * int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
- * }
- */
-- public static MethodHandle X509_STORE_CTX_get0_current_issuer$handle() {
-- return X509_STORE_CTX_get0_current_issuer.HANDLE;
-+ public static MethodHandle X509_STORE_CTX_get1_issuer$handle() {
-+ return X509_STORE_CTX_get1_issuer.HANDLE;
- }
-
- /**
- * Address for:
-- * {@snippet lang = c : * X509 *X509_STORE_CTX_get0_current_issuer(const X509_STORE_CTX *ctx)
-+ * {@snippet lang = c : * int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
- * }
- */
-- public static MemorySegment X509_STORE_CTX_get0_current_issuer$address() {
-- return X509_STORE_CTX_get0_current_issuer.ADDR;
-+ public static MemorySegment X509_STORE_CTX_get1_issuer$address() {
-+ return X509_STORE_CTX_get1_issuer.ADDR;
- }
-
- /**
-- * {@snippet lang = c : * X509 *X509_STORE_CTX_get0_current_issuer(const X509_STORE_CTX *ctx)
-+ * {@snippet lang = c : * int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
- * }
- */
-- public static MemorySegment X509_STORE_CTX_get0_current_issuer(MemorySegment ctx) {
-- var mh$ = X509_STORE_CTX_get0_current_issuer.HANDLE;
-+ public static int X509_STORE_CTX_get1_issuer(MemorySegment issuer, MemorySegment ctx, MemorySegment x) {
-+ var mh$ = X509_STORE_CTX_get1_issuer.HANDLE;
- try {
- if (TRACE_DOWNCALLS) {
-- traceDowncall("X509_STORE_CTX_get0_current_issuer", ctx);
-+ traceDowncall("X509_STORE_CTX_get1_issuer", issuer, ctx, x);
- }
-- return (MemorySegment) mh$.invokeExact(ctx);
-+ return (int) mh$.invokeExact(issuer, ctx, x);
- } catch (Throwable ex$) {
- throw new AssertionError("should not reach here", ex$);
- }
-@@ -8771,6 +8891,315 @@ public class openssl_h {
- }
- }
-
-+ private static class OCSP_resp_get0_certs {
-+ public static final FunctionDescriptor DESC = FunctionDescriptor.of(
-+ openssl_h.C_POINTER,
-+ openssl_h.C_POINTER
-+ );
-+
-+ public static final MemorySegment ADDR = openssl_h.findOrThrow("OCSP_resp_get0_certs");
-+
-+ public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
-+ }
-+
-+ /**
-+ * Function descriptor for:
-+ * {@snippet lang=c :
-+ * const struct stack_st_X509 *OCSP_resp_get0_certs(const OCSP_BASICRESP *bs)
-+ * }
-+ */
-+ public static FunctionDescriptor OCSP_resp_get0_certs$descriptor() {
-+ return OCSP_resp_get0_certs.DESC;
-+ }
-+
-+ /**
-+ * Downcall method handle for:
-+ * {@snippet lang=c :
-+ * const struct stack_st_X509 *OCSP_resp_get0_certs(const OCSP_BASICRESP *bs)
-+ * }
-+ */
-+ public static MethodHandle OCSP_resp_get0_certs$handle() {
-+ return OCSP_resp_get0_certs.HANDLE;
-+ }
-+
-+ /**
-+ * Address for:
-+ * {@snippet lang=c :
-+ * const struct stack_st_X509 *OCSP_resp_get0_certs(const OCSP_BASICRESP *bs)
-+ * }
-+ */
-+ public static MemorySegment OCSP_resp_get0_certs$address() {
-+ return OCSP_resp_get0_certs.ADDR;
-+ }
-+
-+ /**
-+ * {@snippet lang=c :
-+ * const struct stack_st_X509 *OCSP_resp_get0_certs(const OCSP_BASICRESP *bs)
-+ * }
-+ */
-+ public static MemorySegment OCSP_resp_get0_certs(MemorySegment bs) {
-+ var mh$ = OCSP_resp_get0_certs.HANDLE;
-+ try {
-+ if (TRACE_DOWNCALLS) {
-+ traceDowncall("OCSP_resp_get0_certs", bs);
-+ }
-+ return (MemorySegment)mh$.invokeExact(bs);
-+ } catch (Error | RuntimeException ex) {
-+ throw ex;
-+ } catch (Throwable ex$) {
-+ throw new AssertionError("should not reach here", ex$);
-+ }
-+ }
-+
-+ private static class OCSP_basic_verify {
-+ public static final FunctionDescriptor DESC = FunctionDescriptor.of(
-+ openssl_h.C_INT,
-+ openssl_h.C_POINTER,
-+ openssl_h.C_POINTER,
-+ openssl_h.C_POINTER,
-+ openssl_h.C_LONG
-+ );
-+
-+ public static final MemorySegment ADDR = openssl_h.findOrThrow("OCSP_basic_verify");
-+
-+ public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
-+ }
-+
-+ /**
-+ * Function descriptor for:
-+ * {@snippet lang=c :
-+ * int OCSP_basic_verify(OCSP_BASICRESP *bs, struct stack_st_X509 *certs, X509_STORE *st, unsigned long flags)
-+ * }
-+ */
-+ public static FunctionDescriptor OCSP_basic_verify$descriptor() {
-+ return OCSP_basic_verify.DESC;
-+ }
-+
-+ /**
-+ * Downcall method handle for:
-+ * {@snippet lang=c :
-+ * int OCSP_basic_verify(OCSP_BASICRESP *bs, struct stack_st_X509 *certs, X509_STORE *st, unsigned long flags)
-+ * }
-+ */
-+ public static MethodHandle OCSP_basic_verify$handle() {
-+ return OCSP_basic_verify.HANDLE;
-+ }
-+
-+ /**
-+ * Address for:
-+ * {@snippet lang=c :
-+ * int OCSP_basic_verify(OCSP_BASICRESP *bs, struct stack_st_X509 *certs, X509_STORE *st, unsigned long flags)
-+ * }
-+ */
-+ public static MemorySegment OCSP_basic_verify$address() {
-+ return OCSP_basic_verify.ADDR;
-+ }
-+
-+ /**
-+ * {@snippet lang=c :
-+ * int OCSP_basic_verify(OCSP_BASICRESP *bs, struct stack_st_X509 *certs, X509_STORE *st, unsigned long flags)
-+ * }
-+ */
-+ public static int OCSP_basic_verify(MemorySegment bs, MemorySegment certs, MemorySegment st, long flags) {
-+ var mh$ = OCSP_basic_verify.HANDLE;
-+ try {
-+ if (TRACE_DOWNCALLS) {
-+ traceDowncall("OCSP_basic_verify", bs, certs, st, flags);
-+ }
-+ return (int)mh$.invokeExact(bs, certs, st, flags);
-+ } catch (Error | RuntimeException ex) {
-+ throw ex;
-+ } catch (Throwable ex$) {
-+ throw new AssertionError("should not reach here", ex$);
-+ }
-+ }
-+
-+ private static class OCSP_check_validity {
-+ public static final FunctionDescriptor DESC = FunctionDescriptor.of(
-+ openssl_h.C_INT,
-+ openssl_h.C_POINTER,
-+ openssl_h.C_POINTER,
-+ openssl_h.C_LONG,
-+ openssl_h.C_LONG
-+ );
-+
-+ public static final MemorySegment ADDR = openssl_h.findOrThrow("OCSP_check_validity");
-+
-+ public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
-+ }
-+
-+ /**
-+ * Function descriptor for:
-+ * {@snippet lang=c :
-+ * int OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, ASN1_GENERALIZEDTIME *nextupd, long sec, long maxsec)
-+ * }
-+ */
-+ public static FunctionDescriptor OCSP_check_validity$descriptor() {
-+ return OCSP_check_validity.DESC;
-+ }
-+
-+ /**
-+ * Downcall method handle for:
-+ * {@snippet lang=c :
-+ * int OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, ASN1_GENERALIZEDTIME *nextupd, long sec, long maxsec)
-+ * }
-+ */
-+ public static MethodHandle OCSP_check_validity$handle() {
-+ return OCSP_check_validity.HANDLE;
-+ }
-+
-+ /**
-+ * Address for:
-+ * {@snippet lang=c :
-+ * int OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, ASN1_GENERALIZEDTIME *nextupd, long sec, long maxsec)
-+ * }
-+ */
-+ public static MemorySegment OCSP_check_validity$address() {
-+ return OCSP_check_validity.ADDR;
-+ }
-+
-+ /**
-+ * {@snippet lang=c :
-+ * int OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, ASN1_GENERALIZEDTIME *nextupd, long sec, long maxsec)
-+ * }
-+ */
-+ public static int OCSP_check_validity(MemorySegment thisupd, MemorySegment nextupd, long sec, long maxsec) {
-+ var mh$ = OCSP_check_validity.HANDLE;
-+ try {
-+ if (TRACE_DOWNCALLS) {
-+ traceDowncall("OCSP_check_validity", thisupd, nextupd, sec, maxsec);
-+ }
-+ return (int)mh$.invokeExact(thisupd, nextupd, sec, maxsec);
-+ } catch (Error | RuntimeException ex) {
-+ throw ex;
-+ } catch (Throwable ex$) {
-+ throw new AssertionError("should not reach here", ex$);
-+ }
-+ }
-+
-+ private static class OCSP_request_add1_nonce {
-+ public static final FunctionDescriptor DESC = FunctionDescriptor.of(
-+ openssl_h.C_INT,
-+ openssl_h.C_POINTER,
-+ ValueLayout.JAVA_CHAR,
-+ openssl_h.C_INT
-+ );
-+
-+ public static final MemorySegment ADDR = openssl_h.findOrThrow("OCSP_request_add1_nonce");
-+
-+ public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
-+ }
-+
-+ /**
-+ * Function descriptor for:
-+ * {@snippet lang=c :
-+ * int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len)
-+ * }
-+ */
-+ public static FunctionDescriptor OCSP_request_add1_nonce$descriptor() {
-+ return OCSP_request_add1_nonce.DESC;
-+ }
-+
-+ /**
-+ * Downcall method handle for:
-+ * {@snippet lang=c :
-+ * int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len)
-+ * }
-+ */
-+ public static MethodHandle OCSP_request_add1_nonce$handle() {
-+ return OCSP_request_add1_nonce.HANDLE;
-+ }
-+
-+ /**
-+ * Address for:
-+ * {@snippet lang=c :
-+ * int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len)
-+ * }
-+ */
-+ public static MemorySegment OCSP_request_add1_nonce$address() {
-+ return OCSP_request_add1_nonce.ADDR;
-+ }
-+
-+ /**
-+ * {@snippet lang=c :
-+ * int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len)
-+ * }
-+ */
-+ public static int OCSP_request_add1_nonce(MemorySegment req, char val, int len) {
-+ var mh$ = OCSP_request_add1_nonce.HANDLE;
-+ try {
-+ if (TRACE_DOWNCALLS) {
-+ traceDowncall("OCSP_request_add1_nonce", req, val, len);
-+ }
-+ return (int)mh$.invokeExact(req, val, len);
-+ } catch (Error | RuntimeException ex) {
-+ throw ex;
-+ } catch (Throwable ex$) {
-+ throw new AssertionError("should not reach here", ex$);
-+ }
-+ }
-+
-+ private static class OCSP_check_nonce {
-+ public static final FunctionDescriptor DESC = FunctionDescriptor.of(
-+ openssl_h.C_INT,
-+ openssl_h.C_POINTER,
-+ openssl_h.C_POINTER
-+ );
-+
-+ public static final MemorySegment ADDR = openssl_h.findOrThrow("OCSP_check_nonce");
-+
-+ public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
-+ }
-+
-+ /**
-+ * Function descriptor for:
-+ * {@snippet lang=c :
-+ * int OCSP_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs)
-+ * }
-+ */
-+ public static FunctionDescriptor OCSP_check_nonce$descriptor() {
-+ return OCSP_check_nonce.DESC;
-+ }
-+
-+ /**
-+ * Downcall method handle for:
-+ * {@snippet lang=c :
-+ * int OCSP_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs)
-+ * }
-+ */
-+ public static MethodHandle OCSP_check_nonce$handle() {
-+ return OCSP_check_nonce.HANDLE;
-+ }
-+
-+ /**
-+ * Address for:
-+ * {@snippet lang=c :
-+ * int OCSP_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs)
-+ * }
-+ */
-+ public static MemorySegment OCSP_check_nonce$address() {
-+ return OCSP_check_nonce.ADDR;
-+ }
-+
-+ /**
-+ * {@snippet lang=c :
-+ * int OCSP_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs)
-+ * }
-+ */
-+ public static int OCSP_check_nonce(MemorySegment req, MemorySegment bs) {
-+ var mh$ = OCSP_check_nonce.HANDLE;
-+ try {
-+ if (TRACE_DOWNCALLS) {
-+ traceDowncall("OCSP_check_nonce", req, bs);
-+ }
-+ return (int)mh$.invokeExact(req, bs);
-+ } catch (Error | RuntimeException ex) {
-+ throw ex;
-+ } catch (Throwable ex$) {
-+ throw new AssertionError("should not reach here", ex$);
-+ }
-+ }
-+
- private static class OCSP_cert_to_id {
- public static final FunctionDescriptor DESC = FunctionDescriptor.of(openssl_h.C_POINTER, openssl_h.C_POINTER,
- openssl_h.C_POINTER, openssl_h.C_POINTER);
-diff --git a/java/org/apache/tomcat/util/openssl/openssl_h_Compatibility.java b/java/org/apache/tomcat/util/openssl/openssl_h_Compatibility.java
-index 5f513182d1..e75528da40 100644
---- a/java/org/apache/tomcat/util/openssl/openssl_h_Compatibility.java
-+++ b/java/org/apache/tomcat/util/openssl/openssl_h_Compatibility.java
-@@ -33,16 +33,45 @@ public class openssl_h_Compatibility {
- public static final boolean OPENSSL3;
- public static final boolean BORINGSSL;
- public static final boolean LIBRESSL;
-+
-+ public static final int MAJOR;
-+ public static final int MINOR;
-+
- static {
- String versionString = OpenSSL_version(0).getString(0);
- OPENSSL = versionString.contains("OpenSSL");
- OPENSSL3 = OPENSSL && OpenSSL_version_num() >= 0x3000000fL;
- BORINGSSL = versionString.contains("BoringSSL");
- LIBRESSL = versionString.contains("LibreSSL");
-+ int majorVersion = 0;
-+ int minorVersion = 0;
-+ try {
-+ String[] blocks = versionString.split("\\s");
-+ if (blocks.length >= 2) {
-+ versionString = blocks[1];
-+ }
-+ String[] versionNumberStrings = versionString.split("\\.");
-+ if (versionNumberStrings.length >= 2) {
-+ majorVersion = Integer.parseInt(versionNumberStrings[0]);
-+ minorVersion = Integer.parseInt(versionNumberStrings[1]);
-+ }
-+ } catch (Exception e) {
-+ // Ignore, default to 0
-+ } finally {
-+ MAJOR = majorVersion;
-+ MINOR = minorVersion;
-+ }
-+ }
-+
-+ public static boolean isLibreSSLPre35() {
-+ return LIBRESSL && ((MAJOR == 3 && MINOR < 5) || MAJOR < 3);
- }
-
- // OpenSSL 1.1 FIPS_mode
- public static int FIPS_mode() {
-+ if (isLibreSSLPre35()) {
-+ return 0;
-+ }
- class Holder {
- static final String NAME = "FIPS_mode";
- static final FunctionDescriptor DESC = FunctionDescriptor.of(JAVA_INT);
-@@ -61,6 +90,9 @@ public class openssl_h_Compatibility {
-
- // OpenSSL 1.1 FIPS_mode_set
- public static int FIPS_mode_set(int r) {
-+ if (isLibreSSLPre35()) {
-+ return 0;
-+ }
- class Holder {
- static final String NAME = "FIPS_mode_set";
- static final FunctionDescriptor DESC = FunctionDescriptor.of(JAVA_INT, JAVA_INT);
-diff --git a/res/openssl/openssl-tomcat.conf b/res/openssl/openssl-tomcat.conf
-index 892f3b84af..337e7a831e 100644
---- a/res/openssl/openssl-tomcat.conf
-+++ b/res/openssl/openssl-tomcat.conf
-@@ -16,7 +16,7 @@
- -t org.apache.tomcat.util.openssl
- -lssl
- # Configure include path
---I /usr/lib/gcc/x86_64-redhat-linux/14/include
-+-I /usr/lib/gcc/x86_64-redhat-linux/15/include
- --output ../../java
-
- #### Extracted from: /usr/include/openssl/asn1.h
-@@ -108,12 +108,17 @@
- --include-function OCSP_REQUEST_free # header: /usr/include/openssl/ocsp.h
- --include-function OCSP_REQUEST_new # header: /usr/include/openssl/ocsp.h
- --include-function OCSP_RESPONSE_free # header: /usr/include/openssl/ocsp.h
-+--include-function OCSP_basic_verify # header: /usr/include/openssl/ocsp.h
- --include-function OCSP_cert_to_id # header: /usr/include/openssl/ocsp.h
-+--include-function OCSP_check_validity # header: /usr/include/openssl/ocsp.h
-+--include-function OCSP_check_nonce # header: /usr/include/openssl/ocsp.h
- --include-function OCSP_request_add0_id # header: /usr/include/openssl/ocsp.h
-+--include-function OCSP_request_add1_nonce # header: /usr/include/openssl/ocsp.h
- --include-function OCSP_response_get1_basic # header: /usr/include/openssl/ocsp.h
- --include-function OCSP_response_status # header: /usr/include/openssl/ocsp.h
- --include-function OCSP_resp_find # header: /usr/include/openssl/ocsp.h
- --include-function OCSP_resp_get0 # header: /usr/include/openssl/ocsp.h
-+--include-function OCSP_resp_get0_certs # header: /usr/include/openssl/ocsp.h
- --include-function OCSP_single_get0_status # header: /usr/include/openssl/ocsp.h
- --include-function d2i_OCSP_RESPONSE # header: /usr/include/openssl/ocsp.h
- --include-function i2d_OCSP_REQUEST # header: /usr/include/openssl/ocsp.h
-@@ -342,20 +347,26 @@
- --include-function X509_STORE_CTX_get_error # header: /usr/include/openssl/x509_vfy.h
- --include-function X509_STORE_CTX_get_error_depth # header: /usr/include/openssl/x509_vfy.h
- --include-function X509_STORE_CTX_get_ex_data # header: /usr/include/openssl/x509_vfy.h
----include-function X509_STORE_CTX_get0_current_issuer # header: /usr/include/openssl/x509_vfy.h
-+--include-function X509_STORE_CTX_get0_store # header: /usr/include/openssl/x509_vfy.h
- --include-function X509_STORE_CTX_get0_untrusted # header: /usr/include/openssl/x509_vfy.h
-+--include-function X509_STORE_CTX_get1_issuer # header: /usr/include/openssl/x509_vfy.h
- --include-function X509_STORE_CTX_set_error # header: /usr/include/openssl/x509_vfy.h
- --include-function X509_STORE_set_flags # header: /usr/include/openssl/x509_vfy.h
- --include-constant X509_L_ADD_DIR # header: /usr/include/openssl/x509_vfy.h
- --include-constant X509_L_FILE_LOAD # header: /usr/include/openssl/x509_vfy.h
----include-constant X509_V_ERR_APPLICATION_VERIFICATION # header: /usr/include/openssl/x509_vfy.h
----include-constant X509_V_ERR_CERT_UNTRUSTED # header: /usr/include/openssl/x509_vfy.h
-+--include-constant X509_V_OK # header: /usr/include/openssl/x509_vfy.h
-+--include-constant X509_V_ERR_UNABLE_TO_GET_CRL # header: /usr/include/openssl/x509_vfy.h
- --include-constant X509_V_ERR_CRL_HAS_EXPIRED # header: /usr/include/openssl/x509_vfy.h
- --include-constant X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT # header: /usr/include/openssl/x509_vfy.h
- --include-constant X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN # header: /usr/include/openssl/x509_vfy.h
- --include-constant X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY # header: /usr/include/openssl/x509_vfy.h
- --include-constant X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE # header: /usr/include/openssl/x509_vfy.h
-+--include-constant X509_V_ERR_CERT_REVOKED # header: /usr/include/openssl/x509_vfy.h
-+--include-constant X509_V_ERR_CERT_UNTRUSTED # header: /usr/include/openssl/x509_vfy.h
-+--include-constant X509_V_ERR_APPLICATION_VERIFICATION # header: /usr/include/openssl/x509_vfy.h
-+--include-constant X509_V_ERR_OCSP_RESP_INVALID # header: /usr/include/openssl/x509_vfy.h
-+--include-constant X509_V_ERR_OCSP_SIGNATURE_FAILURE # header: /usr/include/openssl/x509_vfy.h
-+--include-constant X509_V_ERR_OCSP_NOT_YET_VALID # header: /usr/include/openssl/x509_vfy.h
-+--include-constant X509_V_ERR_OCSP_HAS_EXPIRED # header: /usr/include/openssl/x509_vfy.h
- --include-constant X509_V_FLAG_CRL_CHECK # header: /usr/include/openssl/x509_vfy.h
- --include-constant X509_V_FLAG_CRL_CHECK_ALL # header: /usr/include/openssl/x509_vfy.h
----include-constant X509_V_OK # header: /usr/include/openssl/x509_vfy.h
--
-diff --git a/test/org/apache/tomcat/security/TestSecurity2017Ocsp.java b/test/org/apache/tomcat/security/TestSecurity2017Ocsp.java
-new file mode 100644
-index 0000000000..2187396985
---- /dev/null
-+++ b/test/org/apache/tomcat/security/TestSecurity2017Ocsp.java
-@@ -0,0 +1,107 @@
-+/*
-+ * Licensed to the Apache Software Foundation (ASF) under one or more
-+ * contributor license agreements. See the NOTICE file distributed with
-+ * this work for additional information regarding copyright ownership.
-+ * The ASF licenses this file to You under the Apache License, Version 2.0
-+ * (the "License"); you may not use this file except in compliance with
-+ * the License. You may obtain a copy of the License at
-+ *
-+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+package org.apache.tomcat.security;
-+
-+import java.io.IOException;
-+
-+import javax.net.ssl.SSLHandshakeException;
-+import javax.servlet.http.HttpServletResponse;
-+
-+import org.junit.AfterClass;
-+import org.junit.Assert;
-+import org.junit.Assume;
-+import org.junit.BeforeClass;
-+import org.junit.Test;
-+import org.junit.runner.RunWith;
-+import org.junit.runners.Parameterized;
-+
-+import org.apache.catalina.Context;
-+import org.apache.catalina.startup.Tomcat;
-+import org.apache.tomcat.util.buf.ByteChunk;
-+import org.apache.tomcat.util.net.SSLHostConfig;
-+import org.apache.tomcat.util.net.TesterSupport;
-+import org.apache.tomcat.util.net.TesterSupport.SimpleServlet;
-+import org.apache.tomcat.util.net.ocsp.OcspBaseTest;
-+import org.apache.tomcat.util.net.ocsp.TesterOcspResponder;
-+import org.apache.tomcat.util.net.openssl.OpenSSLStatus;
-+
-+@RunWith(Parameterized.class)
-+public class TestSecurity2017Ocsp extends OcspBaseTest {
-+
-+ private static TesterOcspResponder ocspResponder;
-+
-+ @BeforeClass
-+ public static void startOcspResponder() {
-+ ocspResponder = new TesterOcspResponder();
-+ try {
-+ ocspResponder.start();
-+ } catch (IOException ioe) {
-+ ocspResponder = null;
-+ }
-+ }
-+
-+
-+ @AfterClass
-+ public static void stopOcspResponder() {
-+ if (ocspResponder != null) {
-+ ocspResponder.stop();
-+ ocspResponder = null;
-+ }
-+ }
-+
-+
-+ /*
-+ * In addition to testing Tomcat Native (where the CVE occurred), this also tests JSSE and OpenSSl via FFM.
-+ */
-+ @Test(expected=SSLHandshakeException.class)
-+ public void testCVE_2017_15698() throws Exception {
-+ if ("OpenSSL-FFM".equals(connectorName)) {
-+ Assume.assumeFalse(OpenSSLStatus.isBoringSSL() || OpenSSLStatus.isLibreSSLPre35());
-+ }
-+ Assume.assumeNotNull(ocspResponder);
-+
-+ Tomcat tomcat = getTomcatInstance();
-+
-+ // No file system docBase required
-+ Context ctx = tomcat.addContext("", null);
-+
-+ Tomcat.addServlet(ctx, "simple", new SimpleServlet());
-+ ctx.addServletMappingDecoded("/simple", "simple");
-+
-+ // User a valid (non-revoked) server certificate
-+ TesterSupport.initSsl(tomcat, TesterSupport.LOCALHOST_RSA_JKS, useOpenSSLTrust);
-+
-+ // Require client certificates and enable verification
-+ SSLHostConfig sslHostConfig = tomcat.getConnector().findSslHostConfigs()[0];
-+ sslHostConfig.setOcspEnabled(true);
-+ sslHostConfig.setCertificateVerification("required");
-+
-+ // Configure a revoked client certificate with a long AIA
-+ // Don't verify the server certificate
-+ TesterSupport.configureClientSsl(false, TesterSupport.CLIENT_CRL_LONG_JKS);
-+
-+ // Disable soft-fail
-+ sslHostConfig.setOcspSoftFail(false);
-+
-+ tomcat.start();
-+
-+ int rc = getUrl("https://localhost:" + getPort() + "/simple", new ByteChunk(), false);
-+
-+ // If the TLS handshake fails, the test won't get this far.
-+ Assert.assertEquals(HttpServletResponse.SC_OK, rc);
-+ }
-+}
-diff --git a/test/org/apache/tomcat/util/net/TestSSLHostConfigCipher.java b/test/org/apache/tomcat/util/net/TestSSLHostConfigCipher.java
-new file mode 100644
-index 0000000000..75c8e90d00
---- /dev/null
-+++ b/test/org/apache/tomcat/util/net/TestSSLHostConfigCipher.java
-@@ -0,0 +1,161 @@
-+/*
-+ * Licensed to the Apache Software Foundation (ASF) under one or more
-+ * contributor license agreements. See the NOTICE file distributed with
-+ * this work for additional information regarding copyright ownership.
-+ * The ASF licenses this file to You under the Apache License, Version 2.0
-+ * (the "License"); you may not use this file except in compliance with
-+ * the License. You may obtain a copy of the License at
-+ *
-+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+package org.apache.tomcat.util.net;
-+
-+import java.util.ArrayList;
-+import java.util.Collection;
-+import java.util.List;
-+
-+import javax.net.ssl.SSLHandshakeException;
-+
-+import org.junit.Assert;
-+import org.junit.Assume;
-+import org.junit.Test;
-+import org.junit.runner.RunWith;
-+import org.junit.runners.Parameterized;
-+import org.junit.runners.Parameterized.Parameter;
-+
-+import org.apache.catalina.Context;
-+import org.apache.catalina.connector.Connector;
-+import org.apache.catalina.startup.TesterServlet;
-+import org.apache.catalina.startup.Tomcat;
-+import org.apache.catalina.startup.TomcatBaseTest;
-+import org.apache.tomcat.util.buf.ByteChunk;
-+import org.apache.tomcat.util.net.openssl.OpenSSLStatus;
-+
-+@RunWith(Parameterized.class)
-+public class TestSSLHostConfigCipher extends TomcatBaseTest {
-+
-+ private static final String CIPHER_12_AVAILABLE = "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
-+ private static final String CIPHER_12_NOT_AVAILABLE = "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384";
-+ private static final String CIPHER_13_AVAILABLE = "TLS_AES_128_GCM_SHA256";
-+ private static final String CIPHER_13_NOT_AVAILABLE = "TLS_AES_256_GCM_SHA384";
-+
-+ @Parameterized.Parameters(name = "{0}")
-+ public static Collection