I have an application where the server side code loads the keystore -
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keyStoreFile), "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "privatepassword".toCharArray());
SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(kmf.getKeyManagers(), null, null);
This worked fine when I had only one private key in the keystore. When I added another private key (with a different password) to the keystore I got this error
java.security.UnrecoverableKeyException: Cannot recover key
at sun.security.provider.KeyProtector.recover(KeyProtector.java:311)
at sun.security.provider.JavaKeyStore.engineGetKey(JavaKeyStore.java:121)
at sun.security.provider.JavaKeyStore$JKS.engineGetKey(JavaKeyStore.java:38)
at java.security.KeyStore.getKey(KeyStore.java:763)
at com.sun.net.ssl.internal.ssl.SunX509KeyManagerImpl.<init>(SunX509KeyManagerImpl.java:113)
at com.sun.net.ssl.internal.ssl.KeyManagerFactoryImpl$SunX509.engineInit(KeyManagerFactoryImpl.java:48)
I then tried creating a custom keymanager as specified in the link below
@Bruno I tried the suggestion you have given. However that does not work. My custom key manager factory looks like this -
class CustomKeyManager implements X509KeyManager {
private final KeyStore ks;
private final String alias;
public CustomKeyManager(KeyStore ks, String alias) {
this.ks = ks;
this.alias = alias;
}
@Override
public String[] getClientAliases(String paramString,
Principal[] paramArrayOfPrincipal) {
return new String[]{alias};
}
@Override
public String chooseClientAlias(String[] paramArrayOfString,
Principal[] paramArrayOfPrincipal, Socket paramSocket) {
// TODO Auto-generated method stub
return alias;
}
@Override
public String[] getServerAliases(String paramString,
Principal[] paramArrayOfPrincipal) {
// TODO Auto-generated method stub
return new String[] {alias};
}
@Override
public String chooseServerAlias(String paramString,
Principal[] paramArrayOfPrincipal, Socket paramSocket) {
// TODO Auto-generated method stub
return alias;
}
@Override
public X509Certificate[] getCertificateChain(String paramString) {
// TODO Auto-generated method stub
return null;
}
@Override
public PrivateKey getPrivateKey(String paramString) {
PrivateKey pk = null;
try { //have hardcoded this to the key i am working with
pk = (PrivateKey) ks.getKey("mykey", "privatepassword".toCharArray());
} catch (UnrecoverableKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return pk;
}
}
After I create an object of CustomKeyManager if I make a call to getPrivateKey I get a non null private key -
Sun RSA private CRT key, 1024 bits modulus: 117260821110864021601500037071432398877761428124640545232618906306796101075244931231861318133902594657774603548686479580347869030216483422242066483203953111970007516384847036243243010603169399491545560497255823475630452314709747201644535089867367118834303975042348737995500693672037616900410158764770570813729 .......
This tells me that my getPrivateKey is working.
I use the CustomKeyManager in the following manner
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keyStoreFile), "password".toCharArray());
SSLContext sslCtx = SSLContext.getInstance("TLS");
CustomKeyManager ck = new CustomKeyManager(ks, "mykey");
KeyManager[] kms = new KeyManager[1];
kms[0] = ck;
System.out.println(ck.getPrivateKey("mykey")); //returns a non null value
sslCtx.init(kms , null, null); //throws an exception
The exception I get is
javax.net.ssl.SSLHandshakeException: no cipher suites in common
Is there a mistake in the way I am creating and using the CustomKeyManager. The other thing of interest is that if I set breakpoints to all the method entry points in the CustomKeyManager, none of them are hit.
Your UnrecoverableKeyException
happens because the keymanager isn't using the correct password. As you said, your two private keys use different passwords.
The code you link to isn't going to help here, since it's merely wrapping the behaviour of the existing keymanager, which you've initialised with only one of the two passwords.
If you really want to use two distinct passwords, you'll need to implement getPrivateKey(String alias)
in your custom X509KeyManager
to take this into account. In particular, it will have to load the keys from your KeyStore
instance with the right password for each alias (see getKey(String alias, char[] password)
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With