收到致命警报:bad_certificate(Received fatal alert: bad_c

2019-07-30 19:19发布

我试图建立一个SSL Socket连接(和我做客户端以下)

  1. 我生成证明文件签名请求,以获取签名的客户端证书

  2. 现在我有一个私钥(企业社会责任过程中使用),签署的客户端证书和根证书(获得带外)。

  3. 我的私钥和客户签署证书添加到证书链,并添加到密钥管理。 和根证书的信任管理器。 但是,我得到一个坏证书错误。

我敢肯定我是使用正确的证书。 我应该签署的客户端证书添加到信任的经理呢? 试过了,没有运气依然。

//I add the private key and the client cert to KeyStore ks
FileInputStream certificateStream = new FileInputStream(clientCertFile);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
java.security.cert.Certificate[] chain = {};
chain = certificateFactory.generateCertificates(certificateStream).toArray(chain);
certificateStream.close();
String privateKeyEntryPassword = "123";
ks.setEntry("abc", new KeyStore.PrivateKeyEntry(privateKey, chain),
        new KeyStore.PasswordProtection(privateKeyEntryPassword.toCharArray()));

//Add the root certificate to keystore jks
FileInputStream is = new FileInputStream(new File(filename));
CertificateFactory cf = CertificateFactory.getInstance("X.509");
java.security.cert.X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
System.out.println("Certificate Information: ");
System.out.println(cert.getSubjectDN().toString());
jks.setCertificateEntry(cert.getSubjectDN().toString(), cert);

//Initialize the keymanager and trustmanager and add them to the SSL context
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "123".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(jks);

是否有某种我需要在这里创建证书链的?
我曾与这些组件以及和使用时相当类似代码P12,将私钥对的KeyManager和P12的信任管理器的根证书,我可以使它发挥作用。 但现在我需要它没有P12的工作。

编辑:请求堆栈跟踪。 希望这应该足够了。 (注:我屏蔽的文件名)

Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1720)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:954)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1149)
at client.abc2.openSocketConnection(abc2.java:33)
at client.abc1.runClient(abc1.java:63)
at screens.app.abc.validateLogin(abc.java:197)
... 32 more

Answer 1:

您需要将根证书添加到密钥存储为好。



Answer 2:

并提供服务器证书签发有效的,你只需要打开连接一样:

import java.net.*;
import java.io.*;

public class URLConnectionReader {
    public static void main(String[] args) throws Exception {
        URL google = new URL("https://www.google.com/");
        URLConnection yc = google.openConnection();
        BufferedReader in = new BufferedReader(new InputStreamReader(
                                    yc.getInputStream()));
        String inputLine;
        while ((inputLine = in.readLine()) != null) 
            System.out.println(inputLine);
        in.close();
    }
}

需要注意的是URL的HTTPS模式指示使用SSL。

如果服务器的证书签名,但您使用的是不同的IP地址/域名比一个证书的访问,可以绕过这个主机名验证:

HostnameVerifier hv = new HostnameVerifier() {
    public boolean verify(String urlHostName,SSLSession session) {
        return true;
    }
};

HttpsURLConnection.setDefaultHostnameVerifier(hv);

如果证书没有,那么你签需要将其添加到由JVM(使用密钥库有用的命令 )。



Answer 3:

当我删除了这两条线我得到这个错误。 如果你知道你的密钥库有正确的证书,请确保您的代码是寻找正确的密钥库。

System.setProperty("javax.net.ssl.keyStore", <keystorePath>));
System.setProperty("javax.net.ssl.keyStorePassword",<keystorePassword>));

我还需要这个VM参数: -Djavax.net.ssl.trustStore=/app/certs/keystore.jk在这里看到更多的细节: https://stackoverflow.com/a/34311797/1308453



文章来源: Received fatal alert: bad_certificate