Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8296343: CPVE thrown on missing content-length in OCSP response #11917

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -206,20 +206,23 @@ public static byte[] getOCSPBytes(List<CertId> certIds, URI responderURI,
out.flush();
}

// Check the response
if (debug != null &&
con.getResponseCode() != HttpURLConnection.HTTP_OK) {
debug.println("Received HTTP error: " + con.getResponseCode()
+ " - " + con.getResponseMessage());
// Check the response. Non-200 codes will generate an exception
// but path validation may complete successfully if revocation info
// can be obtained elsewhere (e.g. CRL).
int respCode = con.getResponseCode();
if (respCode != HttpURLConnection.HTTP_OK) {
String msg = "Received HTTP error: " + respCode + " - " +
con.getResponseMessage();
if (debug != null) {
debug.println(msg);
}
throw new IOException(msg);
}

int contentLength = con.getContentLength();
if (contentLength == -1) {
contentLength = Integer.MAX_VALUE;
}

return IOUtils.readExactlyNBytes(con.getInputStream(),
contentLength);
return (contentLength == -1) ? con.getInputStream().readAllBytes() :
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the returned OCSP bytes, what if the response code is not OK?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, in the case of a 404 what appears to happen is that HttpURLConnection would throw a FileNotFoundException. That ultimately would result in a CPVE if there were no other sources of revocation information (e.g. CRL) for that certificate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be more effective/accuracy to stop read OCSP response bytes if response code is not OK.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging the error code and returning with no read and not throwing an exception I believe would still work since the revocation information would be missing. I'm wondering though if this needs to be a separate issue given that we're talking about a different use case, and one that involves the behavior of HttpURLConnection when dealing with different response codes. I'll also check to see if there are existing tests that make CPV checks against URIs that have non-200 response codes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I was not quite correct about the HttpURLConnection behavior - it's not the 404 that's causing the issue directly, it is indeed the getContentLength when the 404 happens. So forget a separate issue, I will deal with non-200 codes in this PR.

IOUtils.readExactlyNBytes(con.getInputStream(),
contentLength);
} finally {
if (con != null) {
con.disconnect();
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -60,6 +60,8 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import sun.security.testlibrary.SimpleOCSPServer;
import sun.security.testlibrary.SimpleOCSPServer;
import sun.security.testlibrary.SimpleOCSPServer;
Expand Down Expand Up @@ -114,11 +116,10 @@ public static void main(String args[]) throws Exception {
SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)));
ocspResponder.start();
// Wait 5 seconds for server ready
for (int i = 0; (i < 100 && !ocspResponder.isServerReady()); i++) {
Thread.sleep(50);
}
if (!ocspResponder.isServerReady()) {
throw new RuntimeException("Server not ready yet");
boolean readyStatus =
ocspResponder.awaitServerReady(5, TimeUnit.SECONDS);
if (!readyStatus) {
throw new RuntimeException("Server not ready");
}

int ocspPort = ocspResponder.getPort();
Expand Down
53 changes: 40 additions & 13 deletions test/jdk/java/security/testlibrary/SimpleOCSPServer.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -84,10 +84,11 @@ public static enum CertStatus {
private boolean logEnabled = false;
private ExecutorService threadPool;
private volatile boolean started = false;
private volatile boolean serverReady = false;
private CountDownLatch serverReady = new CountDownLatch(1);
private volatile boolean receivedShutdown = false;
private volatile boolean acceptConnections = true;
private volatile long delayMsec = 0;
private boolean omitContentLength = false;

// Fields used in the generation of responses
private long nextUpdateInterval = -1;
Expand Down Expand Up @@ -216,14 +217,15 @@ public void run() {
listenPort), 128);
log("Listening on " + servSocket.getLocalSocketAddress());

// Singal ready
serverReady = true;

// Update the listenPort with the new port number. If
// the server is restarted, it will bind to the same
// port rather than picking a new one.
listenPort = servSocket.getLocalPort();

// Decrement the latch, allowing any waiting entities
// to proceed with their requests.
serverReady.countDown();

// Main dispatch loop
while (!receivedShutdown) {
try {
Expand Down Expand Up @@ -257,7 +259,7 @@ public void run() {
// Reset state variables so the server can be restarted
receivedShutdown = false;
started = false;
serverReady = false;
serverReady = new CountDownLatch(1);
}
}
});
Expand Down Expand Up @@ -497,7 +499,7 @@ public void setSignatureAlgorithm(String algName)
* server has not yet been bound to a port.
*/
public int getPort() {
if (serverReady) {
if (serverReady.getCount() == 0) {
InetSocketAddress inetSock =
(InetSocketAddress)servSocket.getLocalSocketAddress();
return inetSock.getPort();
Expand All @@ -507,12 +509,21 @@ public int getPort() {
}

/**
* Use to check if OCSP server is ready to accept connection.
* Allow SimpleOCSPServer consumers to wait for the server to be in
* the ready state before sending requests.
*
* @param timeout the length of time to wait for the server to be ready
* @param unit the unit of time applied to the timeout parameter
*
* @return true if server ready, false otherwise
* @return true if the server enters the ready state, false if the
* timeout period elapses while the caller is waiting for the server
* to become ready.
*
* @throws InterruptedException if the current thread is interrupted.
*/
public boolean isServerReady() {
return serverReady;
public boolean awaitServerReady(long timeout, TimeUnit unit)
throws InterruptedException {
return serverReady.await(timeout, unit);
}

/**
Expand All @@ -531,6 +542,19 @@ public void setDelay(long delayMillis) {
}
}

/**
* Setting to control whether HTTP responses have the Content-Length
* field asserted or not.
*
* @param isDisabled true if the Content-Length field should not be
* asserted, false otherwise.
*/
public void setDisableContentLength(boolean isDisabled) {
if (!started) {
omitContentLength = isDisabled;
}
}

/**
* Log a message to stdout.
*
Expand Down Expand Up @@ -776,8 +800,11 @@ public void sendResponse(OutputStream out, LocalOcspResponse resp)

sb.append("HTTP/1.0 200 OK\r\n");
sb.append("Content-Type: application/ocsp-response\r\n");
sb.append("Content-Length: ").append(respBytes.length);
sb.append("\r\n\r\n");
if (!omitContentLength) {
sb.append("Content-Length: ").append(respBytes.length).
append("\r\n");
}
sb.append("\r\n");

out.write(sb.toString().getBytes("UTF-8"));
out.write(respBytes);
Expand Down
18 changes: 7 additions & 11 deletions test/jdk/javax/net/ssl/Stapling/HttpsUrlConnClient.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -562,11 +562,9 @@ private static void createPKI() throws Exception {
rootOcsp.start();

// Wait 5 seconds for server ready
for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {
Thread.sleep(50);
}
if (!rootOcsp.isServerReady()) {
throw new RuntimeException("Server not ready yet");
boolean readyStatus = rootOcsp.awaitServerReady(5, TimeUnit.SECONDS);
if (!readyStatus) {
throw new RuntimeException("Server not ready");
}

rootOcspPort = rootOcsp.getPort();
Expand Down Expand Up @@ -615,11 +613,9 @@ private static void createPKI() throws Exception {
intOcsp.start();

// Wait 5 seconds for server ready
for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) {
Thread.sleep(50);
}
if (!intOcsp.isServerReady()) {
throw new RuntimeException("Server not ready yet");
readyStatus = intOcsp.awaitServerReady(5, TimeUnit.SECONDS);
if (!readyStatus) {
throw new RuntimeException("Server not ready");
}

intOcspPort = intOcsp.getPort();
Expand Down
18 changes: 7 additions & 11 deletions test/jdk/javax/net/ssl/Stapling/SSLEngineWithStapling.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -503,11 +503,9 @@ private static void createPKI() throws Exception {
rootOcsp.start();

// Wait 5 seconds for server ready
for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {
Thread.sleep(50);
}
if (!rootOcsp.isServerReady()) {
throw new RuntimeException("Server not ready yet");
boolean readyStatus = rootOcsp.awaitServerReady(5, TimeUnit.SECONDS);
if (!readyStatus) {
throw new RuntimeException("Server not ready");
}

rootOcspPort = rootOcsp.getPort();
Expand Down Expand Up @@ -556,11 +554,9 @@ private static void createPKI() throws Exception {
intOcsp.start();

// Wait 5 seconds for server ready
for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) {
Thread.sleep(50);
}
if (!intOcsp.isServerReady()) {
throw new RuntimeException("Server not ready yet");
readyStatus = intOcsp.awaitServerReady(5, TimeUnit.SECONDS);
if (!readyStatus) {
throw new RuntimeException("Server not ready");
}

intOcspPort = intOcsp.getPort();
Expand Down
68 changes: 27 additions & 41 deletions test/jdk/javax/net/ssl/Stapling/SSLSocketWithStapling.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -432,11 +432,9 @@ static void testMissingIntermediate(boolean isTls13) throws Exception {
rootOcsp.acceptConnections();

// Wait 5 seconds for server ready
for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {
Thread.sleep(50);
}
if (!rootOcsp.isServerReady()) {
throw new RuntimeException("Root OCSP responder not ready yet");
boolean rootOcspReady = rootOcsp.awaitServerReady(5, TimeUnit.SECONDS);
if (!rootOcspReady) {
throw new RuntimeException("Server not ready");
}
}

Expand Down Expand Up @@ -493,13 +491,11 @@ static void testHardFailFallback(boolean isTls13) throws Exception {
intOcsp.acceptConnections();
rootOcsp.acceptConnections();

// Wait 5 seconds for server ready
for (int i = 0; (i < 100 && (!intOcsp.isServerReady() ||
!rootOcsp.isServerReady())); i++) {
Thread.sleep(50);
}
if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) {
throw new RuntimeException("Server not ready yet");
// Wait up to 5 seconds for each server
boolean rootOcspReady = rootOcsp.awaitServerReady(5, TimeUnit.SECONDS);
boolean intOcspReady = intOcsp.awaitServerReady(5, TimeUnit.SECONDS);
if (!rootOcspReady || !intOcspReady) {
throw new RuntimeException("Server not ready");
}
}

Expand Down Expand Up @@ -563,12 +559,10 @@ static void testSoftFailFallback(boolean isTls13) throws Exception {
rootOcsp.acceptConnections();

// Wait 5 seconds for server ready
for (int i = 0; (i < 100 && (!intOcsp.isServerReady() ||
!rootOcsp.isServerReady())); i++) {
Thread.sleep(50);
}
if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) {
throw new RuntimeException("Server not ready yet");
boolean rootOcspReady = rootOcsp.awaitServerReady(5, TimeUnit.SECONDS);
boolean intOcspReady = intOcsp.awaitServerReady(5, TimeUnit.SECONDS);
if (!rootOcspReady || !intOcspReady) {
throw new RuntimeException("Server not ready");
}
}

Expand Down Expand Up @@ -602,12 +596,10 @@ static void testLatencyNoStaple(Boolean fallback, boolean isTls13)
Thread.sleep(1000);

// Wait 5 seconds for server ready
for (int i = 0; (i < 100 && (!intOcsp.isServerReady() ||
!rootOcsp.isServerReady())); i++) {
Thread.sleep(50);
}
if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) {
throw new RuntimeException("Server not ready yet");
boolean rootOcspReady = rootOcsp.awaitServerReady(5, TimeUnit.SECONDS);
boolean intOcspReady = intOcsp.awaitServerReady(5, TimeUnit.SECONDS);
if (!rootOcspReady || !intOcspReady) {
throw new RuntimeException("Server not ready");
}

System.out.println("========================================");
Expand Down Expand Up @@ -654,12 +646,10 @@ static void testLatencyNoStaple(Boolean fallback, boolean isTls13)
Thread.sleep(1000);

// Wait 5 seconds for server ready
for (int i = 0; (i < 100 && (!intOcsp.isServerReady() ||
!rootOcsp.isServerReady())); i++) {
Thread.sleep(50);
}
if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) {
throw new RuntimeException("Server not ready yet");
rootOcspReady = rootOcsp.awaitServerReady(5, TimeUnit.SECONDS);
intOcspReady = intOcsp.awaitServerReady(5, TimeUnit.SECONDS);
if (!rootOcspReady || !intOcspReady) {
throw new RuntimeException("Server not ready");
}
}

Expand Down Expand Up @@ -959,11 +949,9 @@ private static void createPKI() throws Exception {
rootOcsp.start();

// Wait 5 seconds for server ready
for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {
Thread.sleep(50);
}
if (!rootOcsp.isServerReady()) {
throw new RuntimeException("Server not ready yet");
boolean readyStatus = rootOcsp.awaitServerReady(5, TimeUnit.SECONDS);
if (!readyStatus) {
throw new RuntimeException("Server not ready");
}

rootOcspPort = rootOcsp.getPort();
Expand Down Expand Up @@ -1012,11 +1000,9 @@ private static void createPKI() throws Exception {
intOcsp.start();

// Wait 5 seconds for server ready
for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) {
Thread.sleep(50);
}
if (!intOcsp.isServerReady()) {
throw new RuntimeException("Server not ready yet");
readyStatus = intOcsp.awaitServerReady(5, TimeUnit.SECONDS);
if (!readyStatus) {
throw new RuntimeException("Server not ready");
}

intOcspPort = intOcsp.getPort();
Expand Down