You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java HttpsURLConnection报NoSuchAlgorithmException(Cannot recover key)求助

问题描述

我在Java 1.8.0_201环境下编写了使用HttpsURLConnection连接URL的代码:

String u = "https://test.com/prova.asmx?WSDL";
URL url = new URL(u);
System.out.println("Link: " + u);

HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
//con.setSSLSocketFactory(sc.getSocketFactory());
System.out.println("After url connection");
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
String input;
while ((input = br.readLine()) != null) {
    System.out.println(input);
}
br.close();

通过以下命令行启动程序:

java -Djavax.net.ssl.trustStore=ws_cacerts_prod -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.keyStore=ws_cacerts_prod -Djavax.net.ssl.keyStorePassword=changeit -Djavax.net.debug=ssl -Djdk.tls.client.protocols=TLSv1 -Dhttps.protocols=TLSv1 TestHTTPS

运行时抛出如下异常:

Exception in thread "main" java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext)
        at javax.net.ssl.DefaultSSLSocketFactory.throwException(Unknown Source)
        at javax.net.ssl.DefaultSSLSocketFactory.createSocket(Unknown Source)
        at sun.net.www.protocol.https.HttpsClient.createSocket(Unknown Source)
        at sun.net.NetworkClient.doConnect(Unknown Source)
        at sun.net.www.http.HttpClient.openServer(Unknown Source)
        at sun.net.www.http.HttpClient.openServer(Unknown Source)
        at sun.net.www.protocol.https.HttpsClient.<init>(Unknown Source)
        at sun.net.www.protocol.https.HttpsClient.New(Unknown Source)
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(Unknown Source)
        at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(Unknown Source)
        at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Unknown Source)
        at TestHTTPS.main(TestHTTPS.java:19)
Caused by: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext)
        at java.security.Provider$Service.newInstance(Unknown Source)
        at sun.security.jca.GetInstance.getInstance(Unknown Source)
        at sun.security.jca.GetInstance.getInstance(Unknown Source)
        at javax.net.ssl.SSLContext.getInstance(Unknown Source)
        at javax.net.ssl.SSLContext.getDefault(Unknown Source)
        at javax.net.ssl.SSLSocketFactory.getDefault(Unknown Source)
        at javax.net.ssl.HttpsURLConnection.getDefaultSSLSocketFactory(Unknown Source)
        at javax.net.ssl.HttpsURLConnection.<init>(Unknown Source)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.<init>(Unknown Source)
        at sun.net.www.protocol.https.Handler.openConnection(Unknown Source)
        at sun.net.www.protocol.https.Handler.openConnection(Unknown Source)
        at java.net.URL.openConnection(Unknown Source)
        at TestHTTPS.main(TestHTTPS.java:18)
Caused by: java.security.UnrecoverableKeyException: Cannot recover key
        at sun.security.provider.KeyProtector.recover(Unknown Source)
        at sun.security.provider.JavaKeyStore.engineGetKey(Unknown Source)
        at sun.security.provider.JavaKeyStore$JKS.engineGetKey(Unknown Source)
        at sun.security.provider.KeyStoreDelegator.engineGetKey(Unknown Source)
        at sun.security.provider.JavaKeyStore$DualFormatJKS.engineGetKey(Unknown Source)
        at java.security.KeyStore.getKey(Unknown Source)
        at sun.security.ssl.SunX509KeyManagerImpl.<init>(Unknown Source)
        at sun.security.ssl.KeyManagerFactoryImpl$SunX509.engineInit(Unknown Source)
        at javax.net.ssl.KeyManagerFactory.init(Unknown Source)
        at sun.security.ssl.SSLContextImpl$DefaultManagersHolder.getKeyManagers(Unknown Source)
        at sun.security.ssl.SSLContextImpl$DefaultManagersHolder.<clinit>(Unknown Source)
        at sun.security.ssl.SSLContextImpl$DefaultSSLContext.<init>(Unknown Source)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
        at java.lang.reflect.Constructor.newInstance(Unknown Source)
        ... 13 more

我已尝试将密钥库中的所有证书密码修改为与密钥库密码一致,但问题仍未解决,请问该如何处理?

解决方案

从异常栈根因java.security.UnrecoverableKeyException: Cannot recover key来看,核心是Java无法从指定密钥库中恢复私钥,以下是针对性排查和解决步骤:

  • 匹配密钥库类型与启动参数
    如果ws_cacerts_prod是PKCS12格式,需额外添加启动参数-Djavax.net.ssl.keyStoreType=PKCS12。Java 8默认密钥库类型为JKS,若用JKS解析PKCS12文件,会导致私钥读取失败。

  • 验证私钥密码与密钥库密码一致性
    用keytool命令验证:

    keytool -list -v -keystore ws_cacerts_prod -storepass changeit -keypass changeit
    

    若执行失败,说明私钥密码与密钥库密码不匹配。可重新导入私钥确保密码一致,或临时添加参数指定私钥密码:

    -Djavax.net.ssl.keyPassword=changeit
    
  • 确认密钥库包含有效私钥
    用keytool查看密钥库条目:

    keytool -list -keystore ws_cacerts_prod -storepass changeit
    

    若仅存在trustedCertEntry,说明该文件只是信任库,无客户端私钥。此时需移除启动参数中的-Djavax.net.ssl.keyStore和-Djavax.net.ssl.keyStorePassword——普通HTTPS请求仅需信任库验证服务端证书,无需客户端证书认证。

  • 排查TLS协议兼容性
    Java 8高更新包可能默认禁用TLSv1,且多数服务器已不再支持该老旧协议。尝试将启动参数中的协议改为TLSv1.2:

    -Djdk.tls.client.protocols=TLSv1.2 -Dhttps.protocols=TLSv1.2
    
  • 重新生成密钥库
    若以上步骤无效,可重新生成密钥库:

    1. 导出原密钥库中的证书和私钥(如有)
    2. 用keytool重新创建密钥库,导入时确保所有密码一致
    3. 使用新密钥库文件测试连接

内容的提问来源于stack exchange,提问作者Andrea Rovelli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 08:54:22