Skip to content

Commit 25c7a7b

Browse files
author
Alexey Bakhtin
committed
8179502: Enhance OCSP, CRL and Certificate Fetch Timeouts
Reviewed-by: yan Backport-of: 2836c34b64e4626e25c86a53e5bef2bf32f95d2e
1 parent df6014e commit 25c7a7b

File tree

7 files changed

+885
-116
lines changed

7 files changed

+885
-116
lines changed

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

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2021, 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
@@ -162,6 +162,68 @@ public Properties run() {
162162
}
163163
}
164164

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+
}
226+
165227
/**
166228
* Convenience method for fetching System property values that are booleans.
167229
*

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

Lines changed: 26 additions & 19 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;
@@ -74,11 +71,20 @@ public final class OCSP {
7471
private static final int DEFAULT_CONNECT_TIMEOUT = 15000;
7572

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

8389
/**
8490
* Boolean value indicating whether OCSP client can use GET for OCSP
@@ -107,16 +113,13 @@ public final class OCSP {
107113
* system property. If the property has not been set, or if its
108114
* value is negative, set the timeout length to the default.
109115
*/
110-
private static int initializeTimeout() {
111-
@SuppressWarnings("removal")
112-
Integer tmp = java.security.AccessController.doPrivileged(
113-
new GetIntegerAction("com.sun.security.ocsp.timeout"));
114-
if (tmp == null || tmp < 0) {
115-
return DEFAULT_CONNECT_TIMEOUT;
116+
private static int initializeTimeout(String prop, int def) {
117+
int timeoutVal =
118+
GetPropertyAction.privilegedGetTimeoutProp(prop, def, debug);
119+
if (debug != null) {
120+
debug.println(prop + " set to " + timeoutVal + " milliseconds");
116121
}
117-
// Convert to milliseconds, as the system property will be
118-
// specified in seconds
119-
return tmp * 1000;
122+
return timeoutVal;
120123
}
121124

122125
private static boolean initializeBoolean(String prop, boolean def) {
@@ -277,16 +280,18 @@ public static byte[] getOCSPBytes(List<CertId> certIds, URI responderURI,
277280
Base64.getEncoder().encodeToString(bytes), "UTF-8"));
278281

279282
if (USE_GET && encodedGetReq.length() <= 255) {
280-
url = new URL(encodedGetReq.toString());
283+
url = new URI(encodedGetReq.toString()).toURL();
281284
con = (HttpURLConnection)url.openConnection();
285+
con.setConnectTimeout(CONNECT_TIMEOUT);
286+
con.setReadTimeout(READ_TIMEOUT);
282287
con.setDoOutput(true);
283288
con.setDoInput(true);
284289
con.setRequestMethod("GET");
285290
} else {
286291
url = responderURI.toURL();
287292
con = (HttpURLConnection)url.openConnection();
288293
con.setConnectTimeout(CONNECT_TIMEOUT);
289-
con.setReadTimeout(CONNECT_TIMEOUT);
294+
con.setReadTimeout(READ_TIMEOUT);
290295
con.setDoOutput(true);
291296
con.setDoInput(true);
292297
con.setRequestMethod("POST");
@@ -316,6 +321,8 @@ public static byte[] getOCSPBytes(List<CertId> certIds, URI responderURI,
316321
return (contentLength == -1) ? con.getInputStream().readAllBytes() :
317322
IOUtils.readExactlyNBytes(con.getInputStream(),
318323
contentLength);
324+
} catch (URISyntaxException urise) {
325+
throw new IOException(urise);
319326
} finally {
320327
if (con != null) {
321328
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, 2020, 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)