JDK-8149722 : JSSE TrustManagerFactory ignores deployment.system.security.cacerts
  • Type: Bug
  • Component: security-libs
  • Sub-Component: javax.net.ssl
  • Affected Version: 8u66
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: generic
  • CPU: generic
  • Submitted: 2015-12-15
  • Updated: 2016-02-12
  • Resolved: 2016-02-12
Description
FULL PRODUCT VERSION :
java version "1.8.0_51"
Java(TM) SE Runtime Environment (build 1.8.0_51-b16)
Java HotSpot(TM) Client VM (build 25.51-b03, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601] (Windows 7)

EXTRA RELEVANT SYSTEM CONFIGURATION :
Standard java installation
Custom deployment.properties with 
  deployment.system.security.cacerts=C:\tmp\cacerts

java_home/lib/security/cacerts file deleted


A DESCRIPTION OF THE PROBLEM :
When java is deployed with a custom deployment.properties file setting a new location for the cacerts file; this configuration is ignored by the default JSSE implementation.

Checking in the Java Control Panel, the Secure Site CA list is correctly populated.

Trying to establish a secure connection HTTPS connection fails with the error message: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

Copy back the cacerts in java_home/lib/security 
Executing the test again, the connection is working fine.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Remove the cacerts file present in java_home/lib/security

Modifiy the deployment.properties file to set the deployment.system.security.cacerts property on the new location of the cacerts file.

Verify with the Java control panel that the property points correctly the new cacerts file

Execute the test application

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The default SSL connection should find the cacerts file at its new location, as the Java Control Panel does and the connection should be established without problems.
ACTUAL -
The connection could not be established

ERROR MESSAGES/STACK TRACES THAT OCCUR :
trustStore is: No File Available, using empty keystore.
trustStore type is : jks
trustStore provider is : 
init truststore
trigger seeding of SecureRandom
done seeding SecureRandom
keyStore is : 
keyStore type is : jks
keyStore provider is : 
init keystore
init keymanager of type SunX509
....
main, handling exception: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
%% Invalidated:  [Session-1, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
main, SEND TLSv1.2 ALERT:  fatal, description = internal_error
main, WRITE: TLSv1.2 Alert, length = 2
[Raw write]: length = 7
0000: 15 03 03 00 02 02 50                               ......P
main, called closeSocket()
	at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
	at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
	at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1906)
	at sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1889)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1410)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
	at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
	at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1512)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1440)
	at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
	at SslGet.main(SslGet.java:30)
Caused by: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
	at sun.security.validator.PKIXValidator.<init>(PKIXValidator.java:90)
	at sun.security.validator.Validator.getInstance(Validator.java:179)
	at sun.security.ssl.X509TrustManagerImpl.getValidator(X509TrustManagerImpl.java:312)
	at sun.security.ssl.X509TrustManagerImpl.checkTrustedInit(X509TrustManagerImpl.java:171)
	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:184)
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1479)
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:212)
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
	at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
	... 7 more
Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
	at java.security.cert.PKIXParameters.setTrustAnchors(PKIXParameters.java:200)
	at java.security.cert.PKIXParameters.<init>(PKIXParameters.java:120)
	at java.security.cert.PKIXBuilderParameters.<init>(PKIXBuilderParameters.java:104)
	at sun.security.validator.PKIXValidator.<init>(PKIXValidator.java:88)
	... 19 more


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;


public class SslGet {

    public static void main(String[] args) {
        try {
            System.setProperty("javax.net.debug", "all");
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, null, null);

            SSLSocketFactory sslSocketFactory = context.getSocketFactory();

            Proxy theProx = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("my-proxy", 8080));

            URL google = new URL("https://www.google.com");
            URLConnection conn = google.openConnection(theProx);
            ((HttpsURLConnection) conn).setSSLSocketFactory(sslSocketFactory);

            InputStream ins = conn.getInputStream();
            InputStreamReader isr = new InputStreamReader(ins);
            BufferedReader in = new BufferedReader(isr);

            String inputLine;
            while ((inputLine = in.readLine()) != null)
            {
                System.out.println(inputLine);
            }

            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

---------- END SOURCE ----------


Comments
Executed the attached test case with the following steps: a) Copied the cacerts file from ${JAVA_HOME}\jre\lib\security to D:\temp\ b) deleted the cacerts from the ${JAVA_HOME}\jre\lib\security directory c) Ran the attached test case with the following vm arguments: -Djavax.net.ssl.trustStore=D:\\temp\\cacerts d) The test ran successfully with JDK 8u66, JDK 8u72, JDK 8u76 ea
12-02-2016