仍然收到 Received fatal alert: bad_certificate ,

still getting Received fatal alert: bad_certificate ,

我将密钥和证书(组合)放入一个 cert.pem 文件中, 我得到, "exception": "javax.net.ssl.SSLHandshakeException", "message": "Received fatal alert: bad_certificate", pem file is right, but i think problem is how i generating jks keystore file.

.pem 证书格式

BEGIN CERTIFICATE

...

END CERTIFICATE

BEGIN CERTIFICATE

...

END CERTIFICATE

BEGIN RSA PRIVATE KEY

...

END RSA PRIVATE KEY###`

将它与 keytool 命令结合使用命令是

keytool -import -trustcacerts -alias yourdomain -file combined.pem -keystore yourkeystore.jks

java代码为

public class HttpsTrustManager implements X509TrustManager {
    @Override
    public void checkClientTrusted(X509Certificate[] arg0, String arg1)
            throws CertificateException {
        // TODO Auto-generated method stub

    }

    @Override
    public void checkServerTrusted(X509Certificate[] arg0, String arg1)
            throws CertificateException {
        // TODO Auto-generated method stub

    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[]{};
    }
}

请求是

FileInputStream instream = new FileInputStream(
      new File(this.resourcePath()+"/path_to.jks")
  );
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(instream, "password".toCharArray());

    SSLContext sslContext = SSLContexts.custom()
            .loadKeyMaterial(keyStore, "password".toCharArray()) // use null as second param if you don't have a separate key password
            .build();

    sslContext.init(null,new X509TrustManager[]{new HttpsTrustManager()}, new SecureRandom());


    HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
    HttpResponse response = httpClient.execute(
            new HttpPost("https://url")
    );
    HttpEntity entity = response.getEntity();

    System.out.println("----------------------------------------");
    System.out.println(response.getStatusLine());
    EntityUtils.consume(entity);

当您使用 Apache SSLContexts.custom().loadKeyMaterial().build() 时,它会使用指定的密钥库和默认的信任管理器初始化构建的上下文。然后你调用 sslContext.init()re——用 no keymanager 和指定的 trustmanager 初始化它;这将忽略并丢弃先前的初始化。因此,您的上下文没有密钥管理器,无法进行客户端身份验证。

你需要保持一致。要么使用 Apache 并给(相同的)构建器 both loadKeyMaterial and loadTrustMaterial 对应于你想要的 - 在特别是 httpclient 4.5.4 添加了 org.apache.http.conn.ssl.TrustAllStrategy 实现了 "cheerfully let all thieves and crooks see and change my supposedly secure data"。或者,使用 JSSE 使用零安全信任管理器和从密钥库创建的密钥管理器(以及显式 SecureRandom 如果你喜欢但如果你省略它默认)。

但是,这可能不起作用,因为仅当 yourdomain 是与您导入的证书链匹配的预先存在的 PrivateKeyEntry 时,您显示的 keytool 命令才是正确的。使用 keytool -list -alias yourdomain 确保它是 PrivateKeyEntry 而不是 TrustedCertEntry。如果没有,并且如果您需要使用 PEM 文件中的私钥(而不是已经存在于密钥库中的私钥),您需要首先使用 OpenSSL 将密钥 and 证书链转换为 PKCS12,并且然后根据您的 Java 可能 使用 keytool 将 PKCS12 转换为 JKS。为此,在几个堆栈上有几十个 Q(和 A)。