JDK-8080102 : Java 8 cannot load its cacerts in FIPS. no such provider: SunEC
  • Type: Bug
  • Component: security-libs
  • Sub-Component: javax.crypto
  • Affected Version: 8u31
  • Priority: P2
  • Status: Closed
  • Resolution: Cannot Reproduce
  • OS: linux_suse_sles_11
  • CPU: x86_64
  • Submitted: 2015-04-01
  • Updated: 2016-06-22
  • Resolved: 2016-06-22
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
8u60Fixed 9Resolved
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :

java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux sentinel-dev-25 2.6.32.12-0.7-default #1 SMP 2010-05-20 11:14:20 +0200 x86_64 x86_64 x86_64 GNU/Linux


A DESCRIPTION OF THE PROBLEM :
Cannot load cacerts in java8 when FIPS is enabled.

I was able to load the same in jre7u72 builds. It shouldnt be a cacerts issue since i copied the java7 cacerts to java8 and the problem still remains. Suspecting the changes to sunpkcs11 in java8 to cause this.

Following exception is seen while loading cacerts using a test tool. The same works fine in 

Exception in thread "main" java.lang.RuntimeException: java.security.NoSuchProviderException: no such provider: SunEC
        at sun.security.util.ECUtil.getKeyFactory(ECUtil.java:96)
        at sun.security.util.ECUtil.decodeX509ECPublicKey(ECUtil.java:102)
        at sun.security.pkcs11.P11ECKeyFactory.engineGeneratePublic(P11ECKeyFactory.java:170)
        at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
        at sun.security.x509.X509Key.buildX509Key(X509Key.java:223)
        at sun.security.x509.X509Key.parse(X509Key.java:170)
        at sun.security.x509.CertificateX509Key.<init>(CertificateX509Key.java:75)
        at sun.security.x509.X509CertInfo.parse(X509CertInfo.java:667)
        at sun.security.x509.X509CertInfo.<init>(X509CertInfo.java:167)
        at sun.security.x509.X509CertImpl.parse(X509CertImpl.java:1806)
        at sun.security.x509.X509CertImpl.<init>(X509CertImpl.java:195)
        at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:99)
        at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
        at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:747)
        at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:55)
        at java.security.KeyStore.load(KeyStore.java:1433)
        at TestKeyStoreFIPS.main(TestKeyStoreFIPS.java:46)
Caused by: java.security.NoSuchProviderException: no such provider: SunEC
        at sun.security.jca.GetInstance.getService(GetInstance.java:83)
        at sun.security.jca.GetInstance.getInstance(GetInstance.java:206)
        at java.security.KeyFactory.getInstance(KeyFactory.java:211)
        at sun.security.util.ECUtil.getKeyFactory(ECUtil.java:94)


REGRESSION.  Last worked in version 7u76

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Setup and NSS DB:
	1. export LD_LIBRARY_PATH=/usr/lib64
	2. mkdir /tmp/fips/nssdb
	3. modutil -create -dbdir nssdb/
	4. modutil -fips true -dbdir nssdb
	5. modutil -changepw "NSS FIPS 140-2 Certificate DB" -dbdir nssdb
             (provide a complex password like password1!)

Run the testcase provided to load cacerts. First run it using java7 and then run with java8

/tmp/java7/bin/java -Dnss.lib=/usr/lib64 -Dnss.db=/tmp/fips/nssdb  -Djavax.net.ssl.keyStorePassword=password1! TestKeyStoreFIPS /tmp/jre8/lib/security/cacerts changeit

/tmp/java8/jbin/ava -Dnss.lib=/usr/lib64 -Dnss.db=/tmp/fips/nssdb  -Djavax.net.ssl.keyStorePassword=password1! TestKeyStoreFIPS /tmp/jre8/lib/security/cacerts changeit




EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The list of all certificates in ca certs. While running the tool, output should be following.

FIPS test success
digicertassuredidrootca : X.509
trustcenterclass2caii : X.509
thawtepremiumserverca : X.509
swisssignplatinumg2ca : X.509
swisssignsilverg2ca : X.509
thawteserverca : X.509
equifaxsecureebusinessca1 : X.509
....
ACTUAL -
FIPS test success
Exception in thread "main" java.lang.RuntimeException: java.security.NoSuchProviderException: no such provider: SunEC
        at sun.security.util.ECUtil.getKeyFactory(ECUtil.java:96)
        at sun.security.util.ECUtil.decodeX509ECPublicKey(ECUtil.java:102)
        at sun.security.pkcs11.P11ECKeyFactory.engineGeneratePublic(P11ECKeyFactory.java:170)
        at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
        at sun.security.x509.X509Key.buildX509Key(X509Key.java:223)
        at sun.security.x509.X509Key.parse(X509Key.java:170)
        at sun.security.x509.CertificateX509Key.<init>(CertificateX509Key.java:75)
        at sun.security.x509.X509CertInfo.parse(X509CertInfo.java:667)
        at sun.security.x509.X509CertInfo.<init>(X509CertInfo.java:167)
        at sun.security.x509.X509CertImpl.parse(X509CertImpl.java:1806)
        at sun.security.x509.X509CertImpl.<init>(X509CertImpl.java:195)
        at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:99)
        at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
        at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:747)
        at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:55)
        at java.security.KeyStore.load(KeyStore.java:1433)
        at TestKeyStoreFIPS.main(TestKeyStoreFIPS.java:46)
Caused by: java.security.NoSuchProviderException: no such provider: SunEC
        at sun.security.jca.GetInstance.getService(GetInstance.java:83)
        at sun.security.jca.GetInstance.getInstance(GetInstance.java:206)
        at java.security.KeyFactory.getInstance(KeyFactory.java:211)
        at sun.security.util.ECUtil.getKeyFactory(ECUtil.java:94)
        ... 16 more


ERROR MESSAGES/STACK TRACES THAT OCCUR :
FIPS test success
Exception in thread "main" java.lang.RuntimeException: java.security.NoSuchProviderException: no such provider: SunEC
        at sun.security.util.ECUtil.getKeyFactory(ECUtil.java:96)
        at sun.security.util.ECUtil.decodeX509ECPublicKey(ECUtil.java:102)
        at sun.security.pkcs11.P11ECKeyFactory.engineGeneratePublic(P11ECKeyFactory.java:170)
        at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
        at sun.security.x509.X509Key.buildX509Key(X509Key.java:223)
        at sun.security.x509.X509Key.parse(X509Key.java:170)
        at sun.security.x509.CertificateX509Key.<init>(CertificateX509Key.java:75)
        at sun.security.x509.X509CertInfo.parse(X509CertInfo.java:667)
        at sun.security.x509.X509CertInfo.<init>(X509CertInfo.java:167)
        at sun.security.x509.X509CertImpl.parse(X509CertImpl.java:1806)
        at sun.security.x509.X509CertImpl.<init>(X509CertImpl.java:195)
        at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:99)
        at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
        at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:747)
        at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:55)
        at java.security.KeyStore.load(KeyStore.java:1433)
        at TestKeyStoreFIPS.main(TestKeyStoreFIPS.java:46)
Caused by: java.security.NoSuchProviderException: no such provider: SunEC
        at sun.security.jca.GetInstance.getService(GetInstance.java:83)
        at sun.security.jca.GetInstance.getInstance(GetInstance.java:206)
        at java.security.KeyFactory.getInstance(KeyFactory.java:211)
        at sun.security.util.ECUtil.getKeyFactory(ECUtil.java:94)
        ... 16 more


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.Provider;
import java.security.Security;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import sun.security.provider.Sun;
import sun.security.rsa.SunRsaSign;

public class TestKeyStoreFIPS {
	
    public static final String NSS_LIB_DIR_PROP = "nss.lib";
    public static final String NSS_DB_DIR_PROP = "nss.db";
    public static final String SUN_JSSE = "SunJSSE";
    public static List<String> disabledAlgs = new ArrayList<String>();
	public static final String CONFIG = "config/configuration.properties";

    private static final Logger logger = Logger.getLogger(TestKeyStoreFIPS.class.getName());
    
	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		if(args.length != 2){
			System.out.println("Usage eg: java -Dnss.lib=/usr/lib64 -Dnss.db=/tmp/fips/nssdb  -Djavax.net.ssl.keyStorePassword=password1! TestKeyStoreFIPS /tmp/jre8/lib/security/cacerts changeit");
			System.exit(1);
		}
		
        enablePkcs11Jsse(System.getProperty(NSS_LIB_DIR_PROP), System.getProperty(NSS_DB_DIR_PROP));
        testFips();

		String file = args[0];
		char[] keystorePassword = args[1].toCharArray();
		FileInputStream keystoreStream = new FileInputStream(file);

		KeyStore keyStore = KeyStore.getInstance("JKS");
		keyStore.load(keystoreStream, keystorePassword);

		Enumeration<String> aliases = keyStore.aliases();
		
		while(aliases.hasMoreElements()){
			String alias = aliases.nextElement();
			System.out.println(alias + " : " + keyStore.getCertificate(alias).getType());
			
		}

	}
	
	private static void testFips(){
		String keyPass = System.getProperty("javax.net.ssl.keyStorePassword");		
        KeyStore store;

        try {
            store = KeyStore.getInstance("PKCS11");
            if (keyPass != null) {
                store.load(null, keyPass.toCharArray());
            } else {
                store.load(null, null);
            }
            System.out.println("FIPS test success");
        } catch (Throwable e) {
            e.printStackTrace();
            store = null;
            System.out.println("FIPS test failed");
        }        				
	}
	
    /**
     * Configures a PKCS11 based provider and replace the existing JSSE provider
     * with one configured against the newly added PKCS11 based provider.
     */
    public static void enablePkcs11Jsse( String libDir, String dbDir) throws Exception {
    	removeAllProviders();
    	
        Provider nss = getNSSFIPSProvider( libDir, dbDir);
        removeDisabledAlgos(nss);   	
        Security.insertProviderAt(nss, 1);

        Provider sunJsse = new com.sun.net.ssl.internal.ssl.Provider(nss);
        removeDisabledAlgos(sunJsse);
        Security.insertProviderAt(sunJsse,2);
        
        Sun sun = new Sun();
        removeDisabledAlgos(sun);   	
        Security.insertProviderAt(sun,3);
        
        SunRsaSign sunrsa = new SunRsaSign();
        removeDisabledAlgos(sunrsa);
        Security.insertProviderAt(sunrsa,4);
    }	
    
    
    /**
    * Loads and returns an instance of the NSS provider in FIPS mode
    *
    * @return
    * @throws IOException
    */
   private static Provider getNSSFIPSProvider( String libDir, String dbDir) throws Exception {
       
       if(libDir == null || dbDir == null) {
           throw new Exception(NSS_LIB_DIR_PROP + " or " + NSS_DB_DIR_PROP + " not set.");
       }

       Properties props = new Properties();
       props.put("name", "NSSfips");
       props.put("nssLibraryDirectory", libDir);
       props.put("nssSecmodDirectory", dbDir);
       props.put("nssModule", "fips");
       props.put("nssDbMode", "readWrite");

       return createProvider(props);
   }

   private static Provider createProvider(Properties props) throws IOException {
       ByteArrayOutputStream out = new ByteArrayOutputStream();
       props.store(out, null);
       ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());

       Provider ret = new sun.security.pkcs11.SunPKCS11(in);
       if (logger.isLoggable(Level.FINE)) {
           // Log all of the registered services
           for (Map.Entry<Object, Object> entry : ret.entrySet()) {
               logger.log(Level.FINE, "{0} = {1}", new Object[]{entry.getKey(), entry.getValue()});
           }
       }
       return ret;
   }
   
   /**
    * Remove all default providers except Sun and SunRsaSign
    */
   private static void removeAllProviders(){  	
   	Provider[] providers = Security.getProviders();
   	for(Provider prov : providers){
   		Security.removeProvider(prov.getName());
   	}
   }
   	
    /**
     * Remove invalid algorithms
     * @param provider
     */
    private static void removeDisabledAlgos(Provider provider){    	
    	for(String alg : disabledAlgs){
    		if(provider.getProperty(alg) != null){
    			logger.info("Removing algorithm " + alg + " from provider " + provider);
        		provider.remove(alg);
    		}
    	}
    }   

}

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

CUSTOMER SUBMITTED WORKAROUND :
Replace cacerts with a dummy keystore.


Comments
JDK 9 security provider loading loading has changed considerably. The serviceLoader mechanism is now used. See JDK-7191662. As a result, "sun.security.pkcs11.SunPKCS11(InputStream)" is no longer a constructor in JDK 9. Original test was using that approach. I've ran a few tests on latest JDK 9 builds where a 3rd party EC provider is inserted (BouncyCastle) while SunEC is removed. All seems to work ok in terms of EC provisioning functionality. Closing this as 9-na
22-06-2016

New test issue while porting this to JDK 9. (now that JDK-8129562 is resolved) - One test failure on NSS testing when SunEC provider is not present. It's in 9 only and seems related to the DTLS changes that went into JDK 9 recently and how the Signature algorithm gets chosen. Test : sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java ** Failed TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 in TLSv1.2 mode with ECDSA client authentication** STDERR: javax.net.ssl.SSLHandshakeException: Error signing certificate verify at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1923) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:303) at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:1191) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:414) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:983) at sun.security.ssl.Handshaker.processRecord(Handshaker.java:917) at sun.security.ssl.SSLSocketImpl.processInputRecord(SSLSocketImpl.java:1101) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1038) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:949) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1356) at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:719) at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:67) at java.io.OutputStream.write(OutputStream.java:75) at CipherTest$Client.sendRequest(CipherTest.java:378) at JSSEClient.runTest(JSSEClient.java:57) at CipherTest$Client.run(CipherTest.java:365) at java.lang.Thread.run(Thread.java:746) Caused by: java.security.InvalidKeyException: No installed provider supports this key: sun.security.pkcs.PKCS8Key at java.security.Signature$Delegate.chooseProvider(Signature.java:1143) at java.security.Signature$Delegate.engineInitSign(Signature.java:1193) at java.security.Signature.initSign(Signature.java:550) at sun.security.ssl.HandshakeMessage$CertificateVerify.<init>(HandshakeMessage.java:1966) at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:1188)
13-08-2015

build issue due to some recent changes in build area. Won't push changes until we get to root cause : mail thread : http://mail.openjdk.java.net/pipermail/build-dev/2015-June/015254.html
16-06-2015

proposed webrev : http://cr.openjdk.java.net/~coffeys/webrev.8080102.jdk9.v2/webrev/
12-06-2015

Removing the SunEC provider from the code causes a stack overflow : at java.security.KeyFactory.generatePublic(KeyFactory.java:334) at sun.security.util.ECUtil.decodeX509ECPublicKey(ECUtil.java:105) at sun.security.pkcs11.P11ECKeyFactory.engineGeneratePublic(P11ECKeyFactory.java:170) at java.security.KeyFactory.generatePublic(KeyFactory.java:334) at sun.security.util.ECUtil.decodeX509ECPublicKey(ECUtil.java:105) at sun.security.pkcs11.P11ECKeyFactory.engineGeneratePublic(P11ECKeyFactory.java:170) at java.security.KeyFactory.generatePublic(KeyFactory.java:334) The P11ECKeyFactory has always had a dependency to call the SunEC provider for EC KeyFactory operations. By delegating back to SunPKCS11, we loop due to ECUtil.decodeX509ECPublicKey itself calling back into generatePublic. One proposal is to add a helper method to ECUtil where we let JCA framework return the preferred EC provider. If SunPKCS11 provider is returned, we override it and return the SunEC provider.
18-05-2015

It's a bug Sean. The current code explicitly requests the SunEC provider for EC KeyFactory operations. In a FIPS environment, users may wish to install their own EC provider which is just as capable of carrying out the EC operations (and unregister the SunEC provider). Simple fix but we need to fix up some issues arising from the change.
13-05-2015

Offhand this doesn't look like a bug. There are several CAs in the cacerts file with EC keys or signed with ECDSA, so an EC provider is required to load the cacerts file and parse certificates contained within it. I'll hold off closing this in case I am missing something else.
13-05-2015

We should look at modifying ECUtil.getKeyFactory() code so that it doesn't have a dependency on the SunEC provider.
12-05-2015

user code is removing the SunEC provider. A new dependency on that was made in JDK 8 via JDK-7194075 - at ECUtil.getKeyFactory. will have to investigate if user's config is supported.
12-05-2015