Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UnrecoverableKeyException: Cannot recover key [duplicate]

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.

like image 257
PAN Avatar asked Aug 25 '14 14:08

PAN


1 Answers

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)).

like image 84
Bruno Avatar answered Nov 16 '22 23:11

Bruno