JDK-8173956 : KeyStore regression due to default keystore being changed to PKCS12
  • Type: Bug
  • Component: security-libs
  • Sub-Component: java.security
  • Affected Version: 8,9
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2017-02-03
  • Updated: 2020-02-18
  • Resolved: 2017-02-06
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 10 JDK 8 JDK 9 Other
10Fixed 8u241Fixed 9 b156Fixed openjdk8u242Fixed
Description
FULL PRODUCT VERSION :
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+153)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+153, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Any Java 9 platform.  I used x64 Linux (Ubuntu 14.04) and x64 Windows Server 2008 R2.

A DESCRIPTION OF THE PROBLEM :
I believe this bug has been present since changeset 6427:1da93663f8f3 but it's a lot more obvious in Java 9 now that PKCS12 is the default KeyStore type.  The bug is also visible on Java 8 if you're explicitly using PKCS12 rather than JKS.

REGRESSION.  Last worked in version 8u121

ADDITIONAL REGRESSION INFORMATION: 
Any Java 1.4, 1.5, 1.6, or 1.7 works fine, as does 1.8 unless you're explicitly using PKCS12.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute the test code with -enableassertions

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Passed (or omitted "-enableassertions"?)

ACTUAL -
X509TrustManager has no trust roots (!?):  sun.security.ssl.X509TrustManagerImpl@224edc67
Exception in thread "main" java.lang.AssertionError: Oh where, oh where has my little cert gone?
        at Bug8079616OnceMoreWithFeeling.main(Bug8079616OnceMoreWithFeeling.java:37)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;


/**
 * KeyStore regression in Java 9.
 * <p>
 * This code works on Java 1.4, 1.5, 1.6, 1.7 and 1.8 but fails on Java 9
 * because the default KeyStore type is now PKCS12.  It also fails on 1.8
 * if the KeyStore type is explicitly chosen to be PKCS12.
 */
public class Bug8079616OnceMoreWithFeeling {

    public static void main(String[] ignored) throws Exception {

        // The first few lines below are just setup, not part of the test
        KeyStore pleaseUseCACerts = null;
        X509Certificate testCert = gimmeACert(pleaseUseCACerts);
        assert testCert != null;

        // Test code starts here
        String storeType = KeyStore.getDefaultType();  // or hard-code "pkcs12"
        KeyStore p12 = KeyStore.getInstance(storeType);
        p12.load(null, null);

        p12.setCertificateEntry("testCert", testCert);
        assert p12.size() == 1;
        assert Collections.list(p12.aliases()).size() == 1;

        X509Certificate check = gimmeACert(p12);
        assert check != null:  "Oh where, oh where has my little cert gone?";
        assert check.equals(testCert);

        System.out.println("Passed (or omitted \"-enableassertions\"?)");
    }

    static X509Certificate gimmeACert(KeyStore storeOrNull) {
        TrustManager[] reallyOnlyOne;

        try {
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(storeOrNull);
            reallyOnlyOne = tmf.getTrustManagers();
        } catch (NoSuchAlgorithmException bogus) {
            throw new AssertionError(bogus);
        } catch (KeyStoreException bogus) {
            throw new AssertionError(bogus);
        }

        // Stick with pre-1.5 syntax to allow execution on 1.4
        for (int i = 0;  i < reallyOnlyOne.length;  i++) {
            TrustManager tm = reallyOnlyOne[i];
            if (tm instanceof X509TrustManager) {
                X509Certificate[] certs =
                    ((X509TrustManager) tm).getAcceptedIssuers();
                if (certs.length > 0) {
                    return certs[0];
                } else {
                    System.err.println(
                        "X509TrustManager has no trust roots (!?):  " + tm);
                    // ... which would lead to hair-pulling later in SSL code
                }
            }
            // TODO:  Else log somewhat surprising non-X.509 TrustManager
        }
        return null;  // (Evil if this was an API, but fine for this test)
    }
}

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

CUSTOMER SUBMITTED WORKAROUND :
Eschew Java 9, or set the default KeyStore type back to JKS, or explicitly use KeyStore.getInstance("JKS")


Comments
Fix request (8u) I'd like to have an approval for a 8u backport of this fix. This would bring feature parity between OpenJDK and Oracle JDK. Patch does not apply cleanly because of a copyright date. Request for review here: https://mail.openjdk.java.net/pipermail/jdk8u-dev/2019-November/010654.html
21-11-2019

To reproduce the issue , run the attached test case. Following is the output on JDK 9-ea + 153 : java version "9-ea" Java(TM) SE Runtime Environment (build 9-ea+153) Java HotSpot(TM) 64-Bit Server VM (build 9-ea+153, mixed mode) X509TrustManager has no trust roots (!?): sun.security.ssl.X509TrustManagerImpl@3c0ecd4b Exception in thread "main" java.lang.AssertionError: Oh where, oh where has my little cert gone? at JI9047484.main(JI9047484.java:29) The same exception occurs in JDK 8 if the keystore type is set to PKCS12 explicitly.
06-02-2017