JDK-8042622 : Check for CRL results in IllegalArgumentException "white space not allowed"
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 8,8u5
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_8
  • CPU: x86
  • Submitted: 2014-04-22
  • Updated: 2016-01-19
  • Resolved: 2014-10-17
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u31Fixed 9Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
Under Trusty Thar 64bit:
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)

Under Windows 8.1:

java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) Client VM (build 25.5-b02, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Following were tested: Windows 8.1, Linux 64bit (Ubuntu Trusty, Ubuntu Precise)

EXTRA RELEVANT SYSTEM CONFIGURATION :
The Certificate used is from startssl, it's properly imported into the system keystore (just visit https://oashi.com with IE, it will import it silently).

A DESCRIPTION OF THE PROBLEM :
Every once in a while the certificate check fails with the following stacktrace:

java.lang.IllegalArgumentException: white space not allowed
	at java.net.URLPermission.normalizeHeaders(URLPermission.java:401)
	at java.net.URLPermission.init(URLPermission.java:189)
	at java.net.URLPermission.<init>(URLPermission.java:166)
	at sun.net.www.protocol.http.HttpURLConnection.URLtoSocketPermission(HttpURLConnection.java:1031)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1424)
	at com.sun.deploy.net.HttpUtils.followRedirects(Unknown Source)
	at com.sun.deploy.net.BasicHttpRequest.doRequest(Unknown Source)
	at com.sun.deploy.net.BasicHttpRequest.doGetRequestEX(Unknown Source)
	at com.sun.deploy.cache.ResourceProviderImpl.checkUpdateAvailable(Unknown Source)
	at com.sun.deploy.cache.ResourceProviderImpl.isUpdateAvailable(Unknown Source)
	at com.sun.deploy.cache.DeployCacheHandler.get(Unknown Source)
	at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1048)
	at sun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:987)
	at sun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:985)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessController.doPrivileged(AccessController.java:713)
	at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:984)
	at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:931)
	at sun.net.www.protocol.http.HttpURLConnection.followRedirect0(HttpURLConnection.java:2648)
	at sun.net.www.protocol.http.HttpURLConnection.access$300(HttpURLConnection.java:90)
	at sun.net.www.protocol.http.HttpURLConnection$12.run(HttpURLConnection.java:2565)
	at sun.net.www.protocol.http.HttpURLConnection$12.run(HttpURLConnection.java:2563)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessController.doPrivileged(AccessController.java:713)
	at sun.net.www.protocol.http.HttpURLConnection.followRedirect(HttpURLConnection.java:2562)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1768)
	at sun.net.www.protocol.http.HttpURLConnection.access$200(HttpURLConnection.java:90)
	at sun.net.www.protocol.http.HttpURLConnection$9.run(HttpURLConnection.java:1431)
	at sun.net.www.protocol.http.HttpURLConnection$9.run(HttpURLConnection.java:1429)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessController.doPrivileged(AccessController.java:713)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1428)
	at sun.security.provider.certpath.URICertStore.engineGetCRLs(URICertStore.java:396)
	at java.security.cert.CertStore.getCRLs(CertStore.java:181)
	at sun.security.provider.certpath.DistributionPointFetcher.getCRL(DistributionPointFetcher.java:246)
	at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:190)
	at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:122)
	at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:79)
	at com.sun.deploy.security.RevocationChecker.checkCRLs(Unknown Source)
	at com.sun.deploy.security.RevocationChecker.check(Unknown Source)
	at com.sun.deploy.security.TrustDecider.checkRevocationStatus(Unknown Source)
	at com.sun.deploy.security.TrustDecider.getValidationState(Unknown Source)
	at com.sun.deploy.security.TrustDecider.validateChain(Unknown Source)
	at com.sun.deploy.security.TrustDecider.isAllPermissionGranted(Unknown Source)

As you can see, it fails on the way to get the CRL from http://www.startssl.com/sfsca.crl, which returns a 301 and forwards the request to http://crl.startssl.com/sfsca.crl

After adding some debug code into the classes involved, it seems to stumble upon parsing the request headers after the forward, so the URLPermission class gets the String "GET:accept-encoding,User-Agent,UA-Java-Version,GET /sfsca.crl HTTP/1.1,Accept" as actions within the constuctor, on which it fails.

What I can't tell at the moment is why it sometimes succeeds. As I don't have the source code for the com.sun.deploy classes, I can't tell where it comes from.

As neither Java6 nor Java7 expose this behaviour and the URLs passed around by the Startssl servers, I would declare this a  bug.

If further help is needed, I will assist.

REGRESSION.  Last worked in version 7u51

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Under Windows, first visit https://oashi.com to silently import the startssl certs.

Then, visit this URL:

https://m.oashi.com/deploy/Solstice.jnlp

When the logon prompt appears, just cancel it. Retry until it fails (mostly within the first to third try).

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Logon prompt
ACTUAL -
Failure to verify the certificate

ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.IllegalArgumentException: white space not allowed
	at java.net.URLPermission.normalizeHeaders(URLPermission.java:401)
	at java.net.URLPermission.init(URLPermission.java:189)
	at java.net.URLPermission.<init>(URLPermission.java:166)
	at sun.net.www.protocol.http.HttpURLConnection.URLtoSocketPermission(HttpURLConnection.java:1031)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1424)
	at com.sun.deploy.net.HttpUtils.followRedirects(Unknown Source)
	at com.sun.deploy.net.BasicHttpRequest.doRequest(Unknown Source)
	at com.sun.deploy.net.BasicHttpRequest.doGetRequestEX(Unknown Source)
	at com.sun.deploy.cache.ResourceProviderImpl.checkUpdateAvailable(Unknown Source)
	at com.sun.deploy.cache.ResourceProviderImpl.isUpdateAvailable(Unknown Source)
	at com.sun.deploy.cache.DeployCacheHandler.get(Unknown Source)
	at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1048)
	at sun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:987)
	at sun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:985)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessController.doPrivileged(AccessController.java:713)
	at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:984)
	at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:931)
	at sun.net.www.protocol.http.HttpURLConnection.followRedirect0(HttpURLConnection.java:2648)
	at sun.net.www.protocol.http.HttpURLConnection.access$300(HttpURLConnection.java:90)
	at sun.net.www.protocol.http.HttpURLConnection$12.run(HttpURLConnection.java:2565)
	at sun.net.www.protocol.http.HttpURLConnection$12.run(HttpURLConnection.java:2563)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessController.doPrivileged(AccessController.java:713)
	at sun.net.www.protocol.http.HttpURLConnection.followRedirect(HttpURLConnection.java:2562)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1768)
	at sun.net.www.protocol.http.HttpURLConnection.access$200(HttpURLConnection.java:90)
	at sun.net.www.protocol.http.HttpURLConnection$9.run(HttpURLConnection.java:1431)
	at sun.net.www.protocol.http.HttpURLConnection$9.run(HttpURLConnection.java:1429)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessController.doPrivileged(AccessController.java:713)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1428)
	at sun.security.provider.certpath.URICertStore.engineGetCRLs(URICertStore.java:396)
	at java.security.cert.CertStore.getCRLs(CertStore.java:181)
	at sun.security.provider.certpath.DistributionPointFetcher.getCRL(DistributionPointFetcher.java:246)
	at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:190)
	at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:122)
	at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:79)
	at com.sun.deploy.security.RevocationChecker.checkCRLs(Unknown Source)
	at com.sun.deploy.security.RevocationChecker.check(Unknown Source)
	at com.sun.deploy.security.TrustDecider.checkRevocationStatus(Unknown Source)
	at com.sun.deploy.security.TrustDecider.getValidationState(Unknown Source)
	at com.sun.deploy.security.TrustDecider.validateChain(Unknown Source)
	at com.sun.deploy.security.TrustDecider.isAllPermissionGranted(Unknown Source)
	at com.sun.javaws.security.AppPolicy.grantUnrestrictedAccess(Unknown Source)
	at com.sun.javaws.security.JNLPSignedResourcesHelper.checkSignedResourcesHelper(Unknown Source)
	at com.sun.javaws.security.JNLPSignedResourcesHelper.checkSignedResources(Unknown Source)
	at com.sun.javaws.Launcher.prepareResources(Unknown Source)
	at com.sun.javaws.Launcher.prepareAllResources(Unknown Source)
	at com.sun.javaws.Launcher.prepareToLaunch(Unknown Source)
	at com.sun.javaws.Launcher.prepareToLaunch(Unknown Source)
	at com.sun.javaws.Launcher.launch(Unknown Source)
	at com.sun.javaws.Main.launchApp(Unknown Source)
	at com.sun.javaws.Main.continueInSecureThread(Unknown Source)
	at com.sun.javaws.Main.access$000(Unknown Source)
	at com.sun.javaws.Main$1.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:744)


REPRODUCIBILITY :
This bug can be reproduced often.

---------- BEGIN SOURCE ----------
nothing to supply here - it needs a complete application with descriptors and everything.

If you really need this, please contact me, I might be able to prepare something.
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Restart the app until it works.


Comments
According to Marty: "Not a recent regression, issue found in JDK 8". Due to this, escape-old label is added.
07-04-2015

The problem is when the HTTP protocol handler calls a registered ResponseCache it provides a set of headers that includes an implementation artifact (namely the response status line) which is not a valid header. The deploy ResponseCache implementation tries to set the same headers in a repeat request and this is causing the URLPermission error (due to the space in the header name). Solution is to filter out this header from the Map provided to the caller.
07-10-2014

The final exception is from the new URLPermissions code: at java.net.URLPermission.init(URLPermission.java:173)^M at java.net.URLPermission.<init>(URLPermission.java:166)^M at sun.net.www.protocol.http.HttpURLConnection.URLtoSocketPermission(HttpURLConnection.java:1034)^M at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1427)^M at com.sun.deploy.net.HttpUtils.followRedirects(Unknown Source)^M at com.sun.deploy.net.BasicHttpRequest.doRequest(Unknown Source)^M at com.sun.deploy.net.BasicHttpRequest.doGetRequestEX(Unknown Source)^M at com.sun.deploy.cache.ResourceProviderImpl.checkUpdateAvailable(Unknown Source)^M at com.sun.deploy.cache.ResourceProviderImpl.isUpdateAvailable(Unknown Source)^M at com.sun.deploy.cache.DeployCacheHandler.get(Unknown Source)^M at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1051)^M at sun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:987)^M at sun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:985)^M at java.security.AccessController.doPrivileged(Native Method)^M at java.security.AccessController.doPrivileged(AccessController.java:713)^M at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:984)^M at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:931)^M at sun.net.www.protocol.http.HttpURLConnection.followRedirect0(HttpURLConnection.java:2651)^M at sun.net.www.protocol.http.HttpURLConnection.access$300(HttpURLConnection.java:90)^M at sun.net.www.protocol.http.HttpURLConnection$12.run(HttpURLConnection.java:2568)^M at sun.net.www.protocol.http.HttpURLConnection$12.run(HttpURLConnection.java:2566)^M at java.security.AccessController.doPrivileged(Native Method)^M at java.security.AccessController.doPrivileged(AccessController.java:713)^M at sun.net.www.protocol.http.HttpURLConnection.followRedirect(HttpURLConnection.java:2565)^M at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1771)^M at sun.net.www.protocol.http.HttpURLConnection.access$200(HttpURLConnection.java:90)^M at sun.net.www.protocol.http.HttpURLConnection$9.run(HttpURLConnection.java:1434)^M at sun.net.www.protocol.http.HttpURLConnection$9.run(HttpURLConnection.java:1432)^M at java.security.AccessController.doPrivileged(Native Method)^M at java.security.AccessController.doPrivileged(AccessController.java:713)^M at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1431)^M at sun.security.provider.certpath.URICertStore.engineGetCRLs(URICertStore.java:396)^M at java.security.cert.CertStore.getCRLs(CertStore.java:181)^M at sun.security.provider.certpath.DistributionPointFetcher.getCRL(DistributionPointFetcher.java:246)^M at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:190)^M at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:122)^M at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:79)^M at com.sun.deploy.security.RevocationChecker.checkCRLs(Unknown Source)^M at com.sun.deploy.security.RevocationChecker.check(Unknown Source)^M at com.sun.deploy.security.TrustDecider.checkRevocationStatus(Unknown Source)^M And is caused by the insertion of the request property key = GET http://www.startssl.com/sfsca.crl HTTP/1.1 value = null
22-09-2014

I was able to reproduce the problem using the customers app with a slightly different exception after instrumenting the jre to show what the illegal actions string is: at URLPermission.java line 173 it throws exception if actions string contains multiple colons, and the given string is: GET:accept-encoding,User-Agent,UA-Java-Version,GET http://www.startssl.com/sfsca.crl HTTP/1.1,Accept,Proxy-Connection we set the request property: "GET http://www.startssl.com/sfsca.crl HTTP/1.1" to null in line 304 of BasicHttpRequest,java the code there: if (keys != null && values != null) { for(int i = 0; i < keys.length; i++) { conn.setRequestProperty(keys[i], values[i]); } } the keys and values are passed in to BasicHttpRequest.doGetRequest. from: at com.sun.deploy.net.BasicHttpRequest.createUrlConnection(Unknown Source)^M at com.sun.deploy.net.BasicHttpRequest.doRequest(Unknown Source)^M at com.sun.deploy.net.BasicHttpRequest.doGetRequestEX(Unknown Source)^M at com.sun.deploy.cache.ResourceProviderImpl.checkUpdateAvailable(Unknown Source)^M at com.sun.deploy.cache.ResourceProviderImpl.isUpdateAvailable(Unknown Source)^M at com.sun.deploy.cache.DeployCacheHandler.get(Unknown Source)^M at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1051) The problem occurs when we are doing crl revocation checking and: 1.) request is made by sun.security.provider.certpath.DistributionPointFetcher to download the crl list from http://crl.startcom.org/sfsca-crl.crl 2.) and that request is redirected in networking code to http://www.startssl.com/sfsca.crl 3.) and that http request calls the DeployCacheHandler to see if the redirected url is cached, with the args: uri = http://www.startssl.com/sfsca.crl requestHeaders = {GET http://www.startssl.com/sfsca.crl HTTP/1.1=[null], Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], User-Agent=[Java/1.8.0_40-internal], Host=[www.startssl.com], Proxy-Connection=[keep-alive]} 4.) Then the object is cached, but expired, so a new connection is created and the request property (GET http://www.startssl.com/sfsca.crl HTTP/1.1, null) is set on it.
22-09-2014

The Specification of URLPermissions requires that "No white-space is permitted in the actions string". The action string used in the call to the URLPermissions constructor at line 1031 of ./sun/net/www/protocol/http/HttpURLConnection.java is generated on line 1025: String actions = getRequestMethod()+":" + getUserSetHeaders().getHeaderNamesInList(); The MessageHeaders returned by getUserSetHeaders can only be set by calls to the public methods HttpURLConnection.setRequestProperty() and HttpURLConnection.addRequestProperty(). com/sun/deploy/net/BasicHttpRequest has several calls to connection.setRequestProperty: 297 conn.setRequestProperty(USER_AGENT, Environment.getUserAgent()); 298 conn.setRequestProperty(USER_AGENT_JAVA_VERSION, Config.getJavaVersion()); 304 conn.setRequestProperty(keys[i], values[i]); the example says it is webstart webstart, and the UserAgent string is full of whitespace ? : "JNLP/" + JNLP_VERSION + " javaws/" + BuiltInProperties.JAVAWS_VERSION + " (" +getBuildID() + ")" + " Java/" + System.getProperty("java.version"); so why wouldn't this be a problem on all connections , and all the time ?
19-09-2014

SQE is OK to defer this.
07-07-2014

defer request to 8u40: Not a recent regression, issue found in JDK 8. P3 not a stopper for 8u11.
06-07-2014