Question

I'm trying to read back an ECPrivateKey (including certificate chain) from a JKS KeyStore as shown in the code below.

String storeType = "JKS", storePass = "secret", storePath = "c:/keystore.ks";
ECNamedCurveParameterSpec bcParamSpec = ECNamedCurveTable.getParameterSpec("brainpoolp224r1");
ECNamedCurveSpec jceParamSpec = new ECNamedCurveSpec(bcParamSpec.getName(), bcParamSpec.getCurve(), bcParamSpec.getG(), bcParamSpec.getN(), bcParamSpec.getH(), bcParamSpec.getSeed());

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(jceParamSpec);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
ECPublicKey publicKey = (ECPublicKey)keyPair.getPublic();
ECPrivateKey privateKey = (ECPrivateKey)keyPair.getPrivate();

Certificate trustCert =  createX509Certificate("CN=CA", "CN=CA", publicKey, privateKey, "SHA224withECDSA");
Certificate[] chain = { createX509Certificate("CN=Client", "CN=CA", publicKey, privateKey, "SHA224withECDSA"), trustCert };

KeyStore keyStore = KeyStore.getInstance(storeType);
keyStore.load(null, storePass.toCharArray());
keyStore.setKeyEntry("eckey", privateKey, storePass.toCharArray(), chain);

FileOutputStream outputStream = new FileOutputStream(storePath);
keyStore.store(outputStream, storePass.toCharArray());
outputStream.close();

/* Now read it back */
FileInputStream inputStream = new FileInputStream(storePath);
KeyStore keyStore2 = KeyStore.getInstance(storeType);
keyStore2.load(inputStream, storePass.toCharArray());

Key privateKey2 = keyStore2.getKey("eckey", storePass.toCharArray());

The curve I'm using is not supported by the Sun/Oracle security provider, so I'm using Bouncy Castle. BC is inserted at position 0 in my list of security providers. Storing works fine, reading back fails:

java.security.UnrecoverableKeyException: Unknown named curve: 1.3.36.3.3.2.8.1.1.5
    at sun.security.provider.KeyProtector.recover(KeyProtector.java:338)
at sun.security.provider.JavaKeyStore.engineGetKey(JavaKeyStore.java:138)
at sun.security.provider.JavaKeyStore$JKS.engineGetKey(JavaKeyStore.java:55)
at java.security.KeyStore.getKey(KeyStore.java:792)

Apparently the JKS KeyStore implementation doesn't loop through the list of security providers. This works fine, however, for other KeyStore types that are supported by BC: PKCS12 and BKS. Is there a way to use JKS as KeyStore type while using BC to recover the key?

The createX509Certificate method used in the code above is given by:

private static X509Certificate createX509Certificate(String dn, String issuer, PublicKey publicKey, PrivateKey privateKey, String sigAlg) throws Exception {
    X509V3CertificateGenerator certGenerator = new X509V3CertificateGenerator();
certGenerator.setSerialNumber(BigInteger.valueOf(Math.abs(new Random().nextLong())));
certGenerator.setIssuerDN(new X509Name(issuer));
    certGenerator.setSubjectDN(new X509Name(dn));
    certGenerator.setNotBefore(Calendar.getInstance().getTime());
certGenerator.setNotAfter(Calendar.getInstance().getTime());
certGenerator.setPublicKey(publicKey);
certGenerator.setSignatureAlgorithm(sigAlg);
X509Certificate certificate = (X509Certificate)certGenerator.generate(privateKey, "BC");
return certificate;
}
Était-ce utile?

La solution

My only thought would be to implement your own Provider that could either proxy "KeyFactory" request to a BouncyCastle provider and the rest to another one that knows about JKS or proxy all requests to BouncyCastle with the exception of the "KeyStore" request. Here's documentation on how to implement a provider.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top