收到致命警报:bad_certificate

时间:2012-08-03 16:31:27

标签: java sockets ssl x509certificate truststore

我正在尝试设置SSL套接字连接(并在客户端上执行以下操作)

  1. 我生成Certificte签名请求以获取签名的客户端证书

  2. 现在我有一个私钥(在CSR期间使用),一个签名的客户端证书和根证书(在带外获得)。

  3. 我将私钥和签名的客户端证书添加到证书链并将其添加到密钥管理器。以及信任管理员的根证书。 但是我收到了错误的证书错误。

  4. 我很确定我使用的是正确的证书。我是否应该将签名的客户端证书添加到信任管理器?试过,还没有运气。

    //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
    

3 个答案:

答案 0 :(得分:12)

您还需要将根证书添加到密钥库中。

答案 1 :(得分:0)

如果服务器证书已签名且有效,您只需照常打开连接:

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使用的密钥库(useful commands)。

答案 2 :(得分:0)

当我删除这两行时,我收到此错误。如果您知道您的密钥库具有正确的证书,请确保您的代码正在查看正确的密钥库。

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