web-dev-qa-db-ja.com

UnrecoverableKeyException:キーを回復できません

サーバー側のコードがキーストアをロードするアプリケーションがあります-

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

これは、キーストアに秘密鍵が1つしかない場合は問題なく機能しました。キーストアに別の秘密鍵(パスワードが異なる)を追加すると、このエラーが発生しました

    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)

次に、以下のリンクで指定されているカスタムキーマネージャーを作成してみました

@ブルーノ私はあなたが与えた提案を試みました。ただし、これは機能しません。私のカスタムキーマネージャーファクトリは次のようになります-

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;
}   

}

CustomKeyManagerのオブジェクトを作成した後、getPrivateKeyを呼び出すと、null以外の秘密鍵が取得されます-

Sun RSAプライベートCRTキー、1024ビットモジュラス:1172608211108640216015000370714323988777614281246405452326189063067961010752449312318613181339025946577746035486864795803478690302164834222420664832039531119700075163848470362432430106031693994950154972558234756304755017597497497437575753763751037517537550175255114756304755017595491049113753505010は1名が2600に9を付けたものである。

これにより、getPrivateKeyが機能していることがわかります。

CustomKeyManagerを次のように使用します

         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

私が得る例外は

javax.net.ssl.SSLHandshakeException:共通の暗号スイートがない

CustomKeyManagerを作成して使用する方法に誤りはありますか?もう1つの興味深い点は、CustomKeyManagerのすべてのメソッドエントリポイントにブレークポイントを設定しても、ヒットしないことです。

8
PAN

キーマネージャーが正しいパスワードを使用していないため、UnrecoverableKeyExceptionが発生します。おっしゃったように、2つの秘密鍵は異なるパスワードを使用します。リンクするコードは、2つのパスワードのいずれか1つだけで初期化した既存のキーマネージャーの動作を単にラップするだけなので、ここでは役に立ちません。

本当に2つの異なるパスワードを使用したい場合は、カスタム_X509KeyManager_にgetPrivateKey(String alias)を実装して、これを考慮に入れる必要があります。特に、KeyStoreインスタンスから、各エイリアスに適切なパスワードを使用してキーをロードする必要があります( getKey(String alias, char[] password) を参照)。

10
Bruno