【问题标题】:UnrecoverableKeyException: Cannot recover key [duplicate]UnrecoverableKeyException:无法恢复密钥 [重复]
【发布时间】:2014-10-18 17:44:03
【问题描述】:

我有一个服务器端代码加载密钥库的应用程序 -

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

当我在密钥库中只有一个私钥时,这很好用。当我向密钥库添加另一个私钥(使用不同的密码)时,出现此错误

    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,我会得到一个非空私钥 -

Sun RSA 私有 CRT 密钥,1024 位 模量:117260821110864021601500037071432398877761428124640545232618906306796101075244931231861318133902594657774603548686479580347869030216483422242066483203953111970007516384847036243243010603169399491545560497255823475630452314709747201644535089867367118834303975042348737995500693672037616900410158764770570813729 .......

这告诉我我的 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 的方式是否存在错误。另一件有趣的事是,如果我为 CustomKeyManager 中的所有方法入口点设置断点,它们都不会被命中。

【问题讨论】:

  • 之后您如何使用SSLContext,因为您的密钥管理器似乎没有被使用(根据您的断点)?

标签: java ssl ssl-certificate


【解决方案1】:

您的UnrecoverableKeyException 发生是因为密钥管理器未使用正确的密码。正如您所说,您的两个私钥使用不同的密码。 您链接到的代码在这里没有帮助,因为它只是包装了现有密钥管理器的行为,您仅使用两个密码之一对其进行了初始化。

如果您真的想使用两个不同的密码,则需要在您的自定义 X509KeyManager 中实现 getPrivateKey(String alias) 以考虑到这一点。特别是,它必须使用每个别名的正确密码从您的KeyStore 实例加载密钥(请参阅getKey(String alias, char[] password))。

【讨论】:

  • 我已经用我的评论编辑了这个问题
  • 您的getCertificateChain(...) 的实现也有问题,您正在返回null。您需要返回证书链(从该别名的密钥库加载)。不要总是从getPrivateKey 的密钥库中加载相同的私钥,也可以使用别名(并根据需要更改密码)。根据您使用SSLContext 的方式,您可能希望使用X509ExtendedKeyManager 而不是普通的X509KeyManager
  • getCertificateChain 的实现 //cert 和 xcert decl cert = ks.getCertificateChain(alias); xcert = new X509Certificate[cert.length]; for(int i = 0; i
  • @PAN,你如何使用SSLContext?你试过X509ExtendedKeyManager吗?
  • 我试过 X509ExtendedKeyManager。我正在扩展我的自定义实现。那没有帮助。我创建 SSL 上下文,然后将与 ssl 上下文关联的引擎传递给 netty。 pipeline.addLast("ssl", new SslHandler(sslContext.createSSLEngine));
猜你喜欢
  • 2013-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 2021-07-26
  • 1970-01-01
相关资源
最近更新 更多