This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/11.0.x by this push:
new 9aab76056e More robustness improvements for OCSOP processing
9aab76056e is described below
commit 9aab76056e7470bcc8ca9a20b33b6558b1046da2
Author: Mark Thomas <[email protected]>
AuthorDate: Sun Sep 6 11:35:39 2026 +0100
More robustness improvements for OCSOP processing
---
.../util/net/openssl/panama/OpenSSLEngine.java | 61 +++++++++++++++++-----
java/org/apache/tomcat/util/openssl/openssl_h.java | 50 ++++++++++++++++++
webapps/docs/config/http.xml | 16 +++---
3 files changed, 108 insertions(+), 19 deletions(-)
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 7f40b156aa..efceba392e 100644
--- a/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLEngine.java
+++ b/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLEngine.java
@@ -1201,7 +1201,9 @@ public final class OpenSSLEngine extends SSLEngine
implements SSLUtil.ProtocolIn
private static int processOCSP(EngineState state, MemorySegment /*
X509_STORE_CTX */ x509ctx) {
int ocspResponse = V_OCSP_CERTSTATUS_UNKNOWN();
MemorySegment x509 = X509_STORE_CTX_get_current_cert(x509ctx);
- if (!MemorySegment.NULL.equals(x509)) {
+ if (MemorySegment.NULL.equals(x509)) {
+ X509_STORE_CTX_set_error(x509ctx, X509_V_ERR_UNABLE_TO_GET_CRL());
+ } else {
// No need to check cert->valid, because ssl_verify_OCSP() only
// is called if OpenSSL already successfully verified the
certificate
// (parameter "ok" in SSL_callback_SSL_verify() must be true).
@@ -1223,7 +1225,9 @@ public final class OpenSSLEngine extends SSLEngine
implements SSLUtil.ProtocolIn
issuer =
x509IssuerPointer.get(ValueLayout.ADDRESS, 0);
}
}
- if (!MemorySegment.NULL.equals(issuer)) {
+ if (MemorySegment.NULL.equals(issuer)) {
+ X509_STORE_CTX_set_error(x509ctx,
X509_V_ERR_UNABLE_TO_GET_CRL());
+ } else {
// sslutils.c ssl_ocsp_request(x509, issuer,
x509ctx);
int nid = X509_get_ext_by_NID(x509,
NID_info_access(), -1);
boolean requestAttempted = false;
@@ -1245,6 +1249,7 @@ public final class OpenSSLEngine extends SSLEngine
implements SSLUtil.ProtocolIn
}
if (!urls.isEmpty()) {
// Use OpenSSL to build OCSP request
+ int errorStatusForUnknownResponse =
X509_V_ERR_UNABLE_TO_GET_CRL();
for (String urlString : urls) {
try {
URL url = (new
URI(urlString)).toURL();
@@ -1257,9 +1262,30 @@ public final class OpenSSLEngine extends SSLEngine
implements SSLUtil.ProtocolIn
}
} catch (MalformedURLException |
URISyntaxException e) {
log.warn(sm.getString("engine.invalidOCSPURL", urlString));
+ // No response to process so skip
to next URL
+ continue;
}
- if (ocspResponse !=
V_OCSP_CERTSTATUS_UNKNOWN()) {
+ if (ocspResponse ==
V_OCSP_CERTSTATUS_GOOD()) {
+ // Clear any error associated with
an unknown response from a previous URL
+ X509_STORE_CTX_set_error(x509ctx,
X509_V_OK());
break;
+ } else if (ocspResponse ==
V_OCSP_CERTSTATUS_REVOKED()) {
+ // Error will reflect this failure
+ break;
+ } else {
+ /*
+ * Unknown.
+ *
+ * Should only soft-fail if all
the errors from unknown responses are
+ * soft-failable. If there is more
than one non-soft-failable error, the
+ * first one is reported.
+ */
+ if (errorStatusForUnknownResponse
!= X509_V_ERR_UNABLE_TO_GET_CRL()) {
+ // Prior non-soft-failable
error. Reset error status
+
X509_STORE_CTX_set_error(x509ctx, errorStatusForUnknownResponse);
+ } else {
+ errorStatusForUnknownResponse
= X509_STORE_CTX_get_error(x509ctx);
+ }
}
}
}
@@ -1323,6 +1349,7 @@ public final class OpenSSLEngine extends SSLEngine
implements SSLUtil.ProtocolIn
return V_OCSP_CERTSTATUS_UNKNOWN();
}
MemorySegment ocspRequest = MemorySegment.NULL;
+ MemorySegment ocspRequestDer = MemorySegment.NULL;
MemorySegment ocspResponse = MemorySegment.NULL;
MemorySegment id;
MemorySegment ocspOneReq;
@@ -1346,19 +1373,19 @@ public final class OpenSSLEngine extends SSLEngine
implements SSLUtil.ProtocolIn
return V_OCSP_CERTSTATUS_UNKNOWN();
}
OCSP_request_add1_nonce(ocspRequest, (char) 0, -1);
- MemorySegment bufPointer =
localArena.allocateFrom(ValueLayout.ADDRESS, MemorySegment.NULL);
- int requestLength = i2d_OCSP_REQUEST(ocspRequest, bufPointer);
+ MemorySegment ocspRequestDerPointer =
localArena.allocateFrom(ValueLayout.ADDRESS, MemorySegment.NULL);
+ int requestLength = i2d_OCSP_REQUEST(ocspRequest,
ocspRequestDerPointer);
if (requestLength <= 0) {
X509_STORE_CTX_set_error(x509ctx,
X509_V_ERR_UNABLE_TO_GET_CRL());
return V_OCSP_CERTSTATUS_UNKNOWN();
}
- MemorySegment buf = bufPointer.get(ValueLayout.ADDRESS, 0);
+ ocspRequestDer = ocspRequestDerPointer.get(ValueLayout.ADDRESS, 0);
// HTTP request with the following header:
// POST urlPath HTTP/1.1
// Host: urlHost:urlPort
// Content-Type: application/ocsp-request
// Content-Length: ocspRequestData.length
- byte[] ocspRequestData = buf.reinterpret(requestLength,
localArena, null).toArray(ValueLayout.JAVA_BYTE);
+ byte[] ocspRequestDerData =
ocspRequestDer.reinterpret(requestLength, localArena,
null).toArray(ValueLayout.JAVA_BYTE);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(state.ocspTimeout);
connection.setReadTimeout(state.ocspTimeout);
@@ -1368,7 +1395,7 @@ public final class OpenSSLEngine extends SSLEngine
implements SSLUtil.ProtocolIn
connection.setFixedLengthStreamingMode(requestLength);
connection.setRequestProperty("Content-Type",
"application/ocsp-request");
connection.connect();
- connection.getOutputStream().write(ocspRequestData);
+ connection.getOutputStream().write(ocspRequestDerData);
int responseCode = connection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
X509_STORE_CTX_set_error(x509ctx,
X509_V_ERR_UNABLE_TO_GET_CRL());
@@ -1378,8 +1405,8 @@ public final class OpenSSLEngine extends SSLEngine
implements SSLUtil.ProtocolIn
int read;
byte[] responseBuf = new byte[1024];
while ((read = is.read(responseBuf)) > 0) {
- if (baos.size() > OCSP_MAX_RESPONSE_SIZE) {
- X509_STORE_CTX_set_error(x509ctx,
X509_V_ERR_UNABLE_TO_GET_CRL());
+ if (read > OCSP_MAX_RESPONSE_SIZE - baos.size()) {
+ X509_STORE_CTX_set_error(x509ctx,
X509_V_ERR_OCSP_RESP_INVALID());
return V_OCSP_CERTSTATUS_UNKNOWN();
}
baos.write(responseBuf, 0, read);
@@ -1392,7 +1419,8 @@ public final class OpenSSLEngine extends SSLEngine
implements SSLUtil.ProtocolIn
// Failed to get a valid response
X509_STORE_CTX_set_error(x509ctx,
X509_V_ERR_APPLICATION_VERIFICATION());
} else {
- if (OCSP_response_status(ocspResponse) ==
OCSP_RESPONSE_STATUS_SUCCESSFUL()) {
+ int ocspResponseStatus = OCSP_response_status(ocspResponse);
+ if (ocspResponseStatus == OCSP_RESPONSE_STATUS_SUCCESSFUL()) {
basicResponse = OCSP_response_get1_basic(ocspResponse);
if (MemorySegment.NULL.equals(basicResponse)) {
X509_STORE_CTX_set_error(x509ctx,
X509_V_ERR_OCSP_RESP_INVALID());
@@ -1434,9 +1462,17 @@ public final class OpenSSLEngine extends SSLEngine
implements SSLUtil.ProtocolIn
X509_STORE_CTX_set_error(x509ctx,
X509_V_ERR_OCSP_HAS_EXPIRED());
return V_OCSP_CERTSTATUS_UNKNOWN();
}
+ if (status == V_OCSP_CERTSTATUS_UNKNOWN()) {
+ X509_STORE_CTX_set_error(x509ctx,
X509_V_ERR_APPLICATION_VERIFICATION());
+ }
return status;
- } else {
+ } else if (ocspResponseStatus ==
OCSP_RESPONSE_STATUS_TRYLATER() ||
+ ocspResponseStatus ==
OCSP_RESPONSE_STATUS_INTERNALERROR()) {
+ // Soft-failable: consistent with JSSE
X509_STORE_CTX_set_error(x509ctx,
X509_V_ERR_UNABLE_TO_GET_CRL());
+ } else {
+ // Not soft-failable: consistent with JSSE
+ X509_STORE_CTX_set_error(x509ctx,
X509_V_ERR_APPLICATION_VERIFICATION());
}
}
} catch (IOException ioe) {
@@ -1451,6 +1487,7 @@ public final class OpenSSLEngine extends SSLEngine
implements SSLUtil.ProtocolIn
OCSP_BASICRESP_free(basicResponse);
OCSP_RESPONSE_free(ocspResponse);
OCSP_REQUEST_free(ocspRequest);
+ OPENSSL_free(ocspRequestDer);
if (connection != null) {
connection.disconnect();
}
diff --git a/java/org/apache/tomcat/util/openssl/openssl_h.java
b/java/org/apache/tomcat/util/openssl/openssl_h.java
index 6d1ac8f98a..518bd7fb58 100644
--- a/java/org/apache/tomcat/util/openssl/openssl_h.java
+++ b/java/org/apache/tomcat/util/openssl/openssl_h.java
@@ -896,6 +896,56 @@ public class openssl_h {
return OCSP_RESPONSE_STATUS_SUCCESSFUL;
}
+ private static final int OCSP_RESPONSE_STATUS_MALFORMEDREQUEST = (int) 1L;
+
+ /**
+ * {@snippet lang = c : * #define OCSP_RESPONSE_STATUS_MALFORMEDREQUEST 1
+ * }
+ */
+ public static int OCSP_RESPONSE_STATUS_MALFORMEDREQUEST() {
+ return OCSP_RESPONSE_STATUS_MALFORMEDREQUEST;
+ }
+
+ private static final int OCSP_RESPONSE_STATUS_INTERNALERROR = (int) 2L;
+
+ /**
+ * {@snippet lang = c : * #define OCSP_RESPONSE_STATUS_INTERNALERROR 2
+ * }
+ */
+ public static int OCSP_RESPONSE_STATUS_INTERNALERROR() {
+ return OCSP_RESPONSE_STATUS_INTERNALERROR;
+ }
+
+ private static final int OCSP_RESPONSE_STATUS_TRYLATER = (int) 3L;
+
+ /**
+ * {@snippet lang = c : * #define OCSP_RESPONSE_STATUS_TRYLATER 3
+ * }
+ */
+ public static int OCSP_RESPONSE_STATUS_TRYLATER() {
+ return OCSP_RESPONSE_STATUS_TRYLATER;
+ }
+
+ private static final int OCSP_RESPONSE_STATUS_SIGREQUIRED = (int) 5L;
+
+ /**
+ * {@snippet lang = c : * #define OCSP_RESPONSE_STATUS_SIGREQUIRED 5
+ * }
+ */
+ public static int OCSP_RESPONSE_STATUS_SIGREQUIRED() {
+ return OCSP_RESPONSE_STATUS_SIGREQUIRED;
+ }
+
+ private static final int OCSP_RESPONSE_STATUS_UNAUTHORIZED = (int) 6L;
+
+ /**
+ * {@snippet lang = c : * #define OCSP_RESPONSE_STATUS_UNAUTHORIZED 6
+ * }
+ */
+ public static int OCSP_RESPONSE_STATUS_UNAUTHORIZED() {
+ return OCSP_RESPONSE_STATUS_UNAUTHORIZED;
+ }
+
private static final int V_OCSP_CERTSTATUS_GOOD = (int) 0L;
/**
diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml
index a6e4fed537..0a5f9e5825 100644
--- a/webapps/docs/config/http.xml
+++ b/webapps/docs/config/http.xml
@@ -1495,13 +1495,15 @@
</attribute>
<attribute name="ocspSoftFail" required="false">
- <p>If an OCSP responder returns an error, the TLS handshake will always
- fail and a TLS connection will not be established. If the OCSP responder
- is unreachable or otherwise unavailable, this setting determines whether
- the handshake completes or fails. If <code>true</code>, the handskahe
will
- complete and a TLS connection will be established when the OCSP responder
- is unavailable. If <code>false</code>, the handshake will fail and no TLS
- connection will be established.</p>
+ <p>If an OCSP responder reports that the certificate is invalid, the TLS
+ handshake will always fail and a TLS connection will not be established.
+ If Tomcat is unable to create the OCSP request, the OCSP responder is
+ unreachable (network timeout or non HTTP 200 response), the OCSP
+ responder is unavailable (try later response) or the OCSP responder
+ reports an internal error this setting determines whether the handshake
+ completes or fails. If <code>true</code>, the handshake will complete and
+ a TLS connection will be established. If <code>false</code>, the
handshake
+ will fail and no TLS connection will be established.</p>
<p>If not specified, the default value of <code>true</code> will be
used.</p>
</attribute>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]