Skip to content

Commit 2836c34

Browse files
author
Jamil Nimeh
committed
8179502: Enhance OCSP, CRL and Certificate Fetch Timeouts
Reviewed-by: mullan
1 parent 8ffa264 commit 2836c34

File tree

7 files changed

+888
-118
lines changed

7 files changed

+888
-118
lines changed

src/java.base/share/classes/sun/security/action/GetPropertyAction.java

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
2828
import java.security.AccessController;
2929
import java.security.PrivilegedAction;
3030
import java.util.Properties;
31+
import sun.security.util.Debug;
3132

3233
/**
3334
* A convenience class for retrieving the string value of a system
@@ -160,4 +161,66 @@ public Properties run() {
160161
);
161162
}
162163
}
164+
165+
/**
166+
* Convenience method for fetching System property values that are timeouts.
167+
* Accepted timeout values may be purely numeric, a numeric value
168+
* followed by "s" (both interpreted as seconds), or a numeric value
169+
* followed by "ms" (interpreted as milliseconds).
170+
*
171+
* @param prop the name of the System property
172+
* @param def a default value (in milliseconds)
173+
* @param dbg a Debug object, if null no debug messages will be sent
174+
*
175+
* @return an integer value corresponding to the timeout value in the System
176+
* property in milliseconds. If the property value is empty, negative,
177+
* or contains non-numeric characters (besides a trailing "s" or "ms")
178+
* then the default value will be returned. If a negative value for
179+
* the "def" parameter is supplied, zero will be returned if the
180+
* property's value does not conform to the allowed syntax.
181+
*/
182+
public static int privilegedGetTimeoutProp(String prop, int def, Debug dbg) {
183+
if (def < 0) {
184+
def = 0;
185+
}
186+
187+
String rawPropVal = privilegedGetProperty(prop, "").trim();
188+
if (rawPropVal.length() == 0) {
189+
return def;
190+
}
191+
192+
// Determine if "ms" or just "s" is on the end of the string.
193+
// We may do a little surgery on the value so we'll retain
194+
// the original value in rawPropVal for debug messages.
195+
boolean isMillis = false;
196+
String propVal = rawPropVal;
197+
if (rawPropVal.toLowerCase().endsWith("ms")) {
198+
propVal = rawPropVal.substring(0, rawPropVal.length() - 2);
199+
isMillis = true;
200+
} else if (rawPropVal.toLowerCase().endsWith("s")) {
201+
propVal = rawPropVal.substring(0, rawPropVal.length() - 1);
202+
}
203+
204+
// Next check to make sure the string is built only from digits
205+
if (propVal.matches("^\\d+$")) {
206+
try {
207+
int timeout = Integer.parseInt(propVal);
208+
return isMillis ? timeout : timeout * 1000;
209+
} catch (NumberFormatException nfe) {
210+
if (dbg != null) {
211+
dbg.println("Warning: Unexpected " + nfe +
212+
" for timeout value " + rawPropVal +
213+
". Using default value of " + def + " msec.");
214+
}
215+
return def;
216+
}
217+
} else {
218+
if (dbg != null) {
219+
dbg.println("Warning: Incorrect syntax for timeout value " +
220+
rawPropVal + ". Using default value of " + def +
221+
" msec.");
222+
}
223+
return def;
224+
}
225+
}
163226
}

src/java.base/share/classes/sun/security/provider/certpath/OCSP.java

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,7 @@
2626

2727
import java.io.IOException;
2828
import java.io.OutputStream;
29-
import java.net.URI;
30-
import java.net.URL;
31-
import java.net.HttpURLConnection;
32-
import java.net.URLEncoder;
29+
import java.net.*;
3330
import java.security.cert.CertificateException;
3431
import java.security.cert.CertPathValidatorException;
3532
import java.security.cert.CertPathValidatorException.BasicReason;
@@ -41,7 +38,7 @@
4138
import java.util.List;
4239
import java.util.Map;
4340

44-
import sun.security.action.GetIntegerAction;
41+
import sun.security.action.GetPropertyAction;
4542
import sun.security.util.Debug;
4643
import sun.security.util.Event;
4744
import sun.security.util.IOUtils;
@@ -70,29 +67,36 @@ public final class OCSP {
7067
private static final Debug debug = Debug.getInstance("certpath");
7168

7269
private static final int DEFAULT_CONNECT_TIMEOUT = 15000;
70+
private static final int DEFAULT_READ_TIMEOUT = 15000;
7371

7472
/**
75-
* Integer value indicating the timeout length, in seconds, to be
76-
* used for the OCSP check. A timeout of zero is interpreted as
77-
* an infinite timeout.
73+
* Integer value indicating the timeout length, in milliseconds, to be
74+
* used for establishing a connection to an OCSP responder. A timeout of
75+
* zero is interpreted as an infinite timeout.
7876
*/
79-
private static final int CONNECT_TIMEOUT = initializeTimeout();
77+
private static final int CONNECT_TIMEOUT = initializeTimeout(
78+
"com.sun.security.ocsp.timeout", DEFAULT_CONNECT_TIMEOUT);
79+
80+
/**
81+
* Integer value indicating the timeout length, in milliseconds, to be
82+
* used for reading an OCSP response from the responder. A timeout of
83+
* zero is interpreted as an infinite timeout.
84+
*/
85+
private static final int READ_TIMEOUT = initializeTimeout(
86+
"com.sun.security.ocsp.readtimeout", DEFAULT_READ_TIMEOUT);
8087

8188
/**
8289
* Initialize the timeout length by getting the OCSP timeout
8390
* system property. If the property has not been set, or if its
8491
* value is negative, set the timeout length to the default.
8592
*/
86-
private static int initializeTimeout() {
87-
@SuppressWarnings("removal")
88-
Integer tmp = java.security.AccessController.doPrivileged(
89-
new GetIntegerAction("com.sun.security.ocsp.timeout"));
90-
if (tmp == null || tmp < 0) {
91-
return DEFAULT_CONNECT_TIMEOUT;
93+
private static int initializeTimeout(String prop, int def) {
94+
int timeoutVal =
95+
GetPropertyAction.privilegedGetTimeoutProp(prop, def, debug);
96+
if (debug != null) {
97+
debug.println(prop + " set to " + timeoutVal + " milliseconds");
9298
}
93-
// Convert to milliseconds, as the system property will be
94-
// specified in seconds
95-
return tmp * 1000;
99+
return timeoutVal;
96100
}
97101

98102
private OCSP() {}
@@ -183,17 +187,18 @@ public static byte[] getOCSPBytes(List<CertId> certIds, URI responderURI,
183187
Base64.getEncoder().encodeToString(bytes), UTF_8));
184188

185189
if (encodedGetReq.length() <= 255) {
186-
@SuppressWarnings("deprecation")
187-
var _unused = url = new URL(encodedGetReq.toString());
190+
url = new URI(encodedGetReq.toString()).toURL();
188191
con = (HttpURLConnection)url.openConnection();
192+
con.setConnectTimeout(CONNECT_TIMEOUT);
193+
con.setReadTimeout(READ_TIMEOUT);
189194
con.setDoOutput(true);
190195
con.setDoInput(true);
191196
con.setRequestMethod("GET");
192197
} else {
193198
url = responderURI.toURL();
194199
con = (HttpURLConnection)url.openConnection();
195200
con.setConnectTimeout(CONNECT_TIMEOUT);
196-
con.setReadTimeout(CONNECT_TIMEOUT);
201+
con.setReadTimeout(READ_TIMEOUT);
197202
con.setDoOutput(true);
198203
con.setDoInput(true);
199204
con.setRequestMethod("POST");
@@ -223,6 +228,8 @@ public static byte[] getOCSPBytes(List<CertId> certIds, URI responderURI,
223228
return (contentLength == -1) ? con.getInputStream().readAllBytes() :
224229
IOUtils.readExactlyNBytes(con.getInputStream(),
225230
contentLength);
231+
} catch (URISyntaxException urise) {
232+
throw new IOException(urise);
226233
} finally {
227234
if (con != null) {
228235
con.disconnect();

src/java.base/share/classes/sun/security/provider/certpath/URICertStore.java

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -50,7 +50,8 @@
5050
import java.util.Collections;
5151
import java.util.List;
5252
import java.util.Locale;
53-
import sun.security.action.GetIntegerAction;
53+
54+
import sun.security.action.GetPropertyAction;
5455
import sun.security.x509.AccessDescription;
5556
import sun.security.x509.GeneralNameInterface;
5657
import sun.security.x509.URIName;
@@ -127,8 +128,12 @@ class URICertStore extends CertStoreSpi {
127128
// allowed when downloading CRLs
128129
private static final int DEFAULT_CRL_READ_TIMEOUT = 15000;
129130

131+
// Default connect and read timeouts for CA certificate fetching (15 sec)
132+
private static final int DEFAULT_CACERT_CONNECT_TIMEOUT = 15000;
133+
private static final int DEFAULT_CACERT_READ_TIMEOUT = 15000;
134+
130135
/**
131-
* Integer value indicating the connect timeout, in seconds, to be
136+
* Integer value indicating the connect timeout, in milliseconds, to be
132137
* used for the CRL download. A timeout of zero is interpreted as
133138
* an infinite timeout.
134139
*/
@@ -137,30 +142,44 @@ class URICertStore extends CertStoreSpi {
137142
DEFAULT_CRL_CONNECT_TIMEOUT);
138143

139144
/**
140-
* Integer value indicating the read timeout, in seconds, to be
145+
* Integer value indicating the read timeout, in milliseconds, to be
141146
* used for the CRL download. A timeout of zero is interpreted as
142147
* an infinite timeout.
143148
*/
144149
private static final int CRL_READ_TIMEOUT =
145150
initializeTimeout("com.sun.security.crl.readtimeout",
146151
DEFAULT_CRL_READ_TIMEOUT);
147152

153+
/**
154+
* Integer value indicating the connect timeout, in milliseconds, to be
155+
* used for the CA certificate download. A timeout of zero is interpreted
156+
* as an infinite timeout.
157+
*/
158+
private static final int CACERT_CONNECT_TIMEOUT =
159+
initializeTimeout("com.sun.security.cert.timeout",
160+
DEFAULT_CACERT_CONNECT_TIMEOUT);
161+
162+
/**
163+
* Integer value indicating the read timeout, in milliseconds, to be
164+
* used for the CA certificate download. A timeout of zero is interpreted
165+
* as an infinite timeout.
166+
*/
167+
private static final int CACERT_READ_TIMEOUT =
168+
initializeTimeout("com.sun.security.cert.readtimeout",
169+
DEFAULT_CACERT_READ_TIMEOUT);
170+
148171
/**
149172
* Initialize the timeout length by getting the specified CRL timeout
150173
* system property. If the property has not been set, or if its
151174
* value is negative, set the timeout length to the specified default.
152175
*/
153176
private static int initializeTimeout(String prop, int def) {
154-
Integer tmp = GetIntegerAction.privilegedGetProperty(prop);
155-
if (tmp == null || tmp < 0) {
156-
return def;
157-
}
177+
int timeoutVal =
178+
GetPropertyAction.privilegedGetTimeoutProp(prop, def, debug);
158179
if (debug != null) {
159-
debug.println(prop + " set to " + tmp + " seconds");
180+
debug.println(prop + " set to " + timeoutVal + " milliseconds");
160181
}
161-
// Convert to milliseconds, as the system property will be
162-
// specified in seconds
163-
return tmp * 1000;
182+
return timeoutVal;
164183
}
165184

166185
/**
@@ -276,6 +295,8 @@ static CertStore getInstance(AccessDescription ad) {
276295
connection.setIfModifiedSince(lastModified);
277296
}
278297
long oldLastModified = lastModified;
298+
connection.setConnectTimeout(CACERT_CONNECT_TIMEOUT);
299+
connection.setReadTimeout(CACERT_READ_TIMEOUT);
279300
try (InputStream in = connection.getInputStream()) {
280301
lastModified = connection.getLastModified();
281302
if (oldLastModified != 0) {

0 commit comments

Comments
 (0)