【问题标题】:SSL handshake failure when importing certificates from file从文件导入证书时 SSL 握手失败
【发布时间】:2014-08-29 20:07:16
【问题描述】:

我正在创建一个 HTTPS 服务器并自行验证证书。

我有一个奇怪的错误。

当我生成证书并添加该密钥库时,我能够进行 SSL 握手。

keytool -genkey -keyalg rsa -alias mycert -keystore lig.keystore -storepass changeit -keypass changeit

而当我使用 keytool 导入证书并将其添加到密钥库时,我收到 SSH Handshake Failure 错误。

keytool -noprompt -importcert -file certDer -alias mycert -keystore lig.keystore -storepass changeit -keypass changeit

确切地说,第一个是自签名证书。第二个是第三方证书。

SSLHandshake 适用于自签名证书,但不适用于第三方证书。

谁能告诉我为什么?

HttpsNetServer.java

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocketFactory;

public class HttpsNetServer {


    public static void main(String args[]) throws Exception {
        SSLContext context;
        KeyManagerFactory kmf;
        KeyStore ks;
        char[] storepass = "changeit".toCharArray();
        char[] keypass = "changeit".toCharArray();
        String storename = "/home/krishnan/.keystore";


        context = SSLContext.getInstance("TLS");
        kmf = KeyManagerFactory.getInstance("SunX509");
        FileInputStream fin = new FileInputStream(storename);
        ks = KeyStore.getInstance("JKS");
        ks.load(fin, storepass);

        kmf.init(ks, keypass);
        context.init(kmf.getKeyManagers(), null, null);
        SSLServerSocketFactory ssf = context.getServerSocketFactory();

        ServerSocket ss = ssf.createServerSocket(8000);

          Socket s = ss.accept();
          PrintStream out = new PrintStream(s.getOutputStream());
          out.println("Hi");
          out.close();
          s.close();

    }

}

HttpsNetClient.java

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.security.cert.CertPath;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class HttpsNetClient {
    public static void main(String args[]) throws Exception {
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, // No Key Manager
            new TrustManager[] { new X509TrustManager()
              {
                @Override
                public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                    throws CertificateException
                  {}

                @Override
                public void checkServerTrusted(X509Certificate[] xcert, String arg1)
                    throws CertificateException {
                    System.out.println("Certificate");
                  /*  for( X509Certificate certificate : xcert)
                    {
                        System.out.println(certificate.toString());
                    }*/
                     // check the certs
                }

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

              } }, // TrustManager 
            null);
        SSLSocketFactory factory = context.getSocketFactory();
        SSLSocket socket = (SSLSocket) factory.createSocket("127.0.0.1", 8000);
        socket.startHandshake();
        SSLSession session = socket.getSession();
        java.security.cert.Certificate[] servercerts = session.getPeerCertificates();

        List mylist = new ArrayList();
        for (int i = 0; i < servercerts.length; i++) {
          mylist.add(servercerts[i]);
        }

        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        CertPath cp = cf.generateCertPath(mylist);

        FileOutputStream f = new FileOutputStream("CertPath.dat");
        ObjectOutputStream b = new ObjectOutputStream(f);
        b.writeObject(cp);

        }

}

控制台输出

trigger seeding of SecureRandom
done seeding SecureRandom
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
%% No cached client session
*** ClientHello, TLSv1
RandomCookie:  GMT: 1388082990 bytes = { 150, 135, 207, 23, 25, 26, 29, 28, 215, 141, 166, 204, 95, 134, 251, 101, 171, 119, 173, 127, 35, 182, 181, 72, 56, 81, 36, 68 }
Session ID:  {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
***
[write] MD5 and SHA1 hashes:  len = 163
0000: 01 00 00 9F 03 01 53 BC   77 2E 96 87 CF 17 19 1A  ......S.w.......
0010: 1D 1C D7 8D A6 CC 5F 86   FB 65 AB 77 AD 7F 23 B6  ......_..e.w..#.
0020: B5 48 38 51 24 44 00 00   38 C0 0A C0 14 00 35 C0  .H8Q$D..8.....5.
0030: 05 C0 0F 00 39 00 38 C0   09 C0 13 00 2F C0 04 C0  ....9.8...../...
0040: 0E 00 33 00 32 C0 07 C0   11 00 05 C0 02 C0 0C C0  ..3.2...........
0050: 08 C0 12 00 0A C0 03 C0   0D 00 16 00 13 00 04 00  ................
0060: FF 01 00 00 3E 00 0A 00   34 00 32 00 17 00 01 00  ....>...4.2.....
0070: 03 00 13 00 15 00 06 00   07 00 09 00 0A 00 18 00  ................
0080: 0B 00 0C 00 19 00 0D 00   0E 00 0F 00 10 00 11 00  ................
0090: 02 00 12 00 04 00 05 00   14 00 08 00 16 00 0B 00  ................
00A0: 02 01 00                                           ...
main, WRITE: TLSv1 Handshake, length = 163
[Raw write]: length = 168
0000: 16 03 01 00 A3 01 00 00   9F 03 01 53 BC 77 2E 96  ...........S.w..
0010: 87 CF 17 19 1A 1D 1C D7   8D A6 CC 5F 86 FB 65 AB  ..........._..e.
0020: 77 AD 7F 23 B6 B5 48 38   51 24 44 00 00 38 C0 0A  w..#..H8Q$D..8..
0030: C0 14 00 35 C0 05 C0 0F   00 39 00 38 C0 09 C0 13  ...5.....9.8....
0040: 00 2F C0 04 C0 0E 00 33   00 32 C0 07 C0 11 00 05  ./.....3.2......
0050: C0 02 C0 0C C0 08 C0 12   00 0A C0 03 C0 0D 00 16  ................
0060: 00 13 00 04 00 FF 01 00   00 3E 00 0A 00 34 00 32  .........>...4.2
0070: 00 17 00 01 00 03 00 13   00 15 00 06 00 07 00 09  ................
0080: 00 0A 00 18 00 0B 00 0C   00 19 00 0D 00 0E 00 0F  ................
0090: 00 10 00 11 00 02 00 12   00 04 00 05 00 14 00 08  ................
00A0: 00 16 00 0B 00 02 01 00                            ........
[Raw read]: length = 5
0000: 15 03 01 00 02                                     .....
[Raw read]: length = 2
0000: 02 28                                              .(
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT:  fatal, handshake_failure
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1961)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1077)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
    at HttpsNetClient.main(HttpsNetClient.java:49)

【问题讨论】:

  • “第三方证书”是什么意思?
  • @EJP 从网上下载的证书? EX:从 www.mozilla.org 下载的证书

标签: java ssl https openssl keytool


【解决方案1】:

不应将第三方证书导入为“mycert”。不是你的证书,是别人的。此外,您刚刚破坏了自己的密钥对和证书。重新开始,为 3rd-party 证书使用不同的别名。

【讨论】:

  • 但是您是否恢复了您的私钥和证书?
  • 如何从证书中恢复私钥?我们无法从从互联网下载的证书中恢复私钥吗?
  • 您无法从证书中恢复私钥。你必须重新开始。在别名“mycert”下生成密钥对和自签名证书,并在不同别名下导入您需要的任何其他证书。试图从别人的其他人的证书中获取私钥没有意义。
【解决方案2】:

问题是密钥库必须包含一个公共证书和一个私钥。
在第一个示例中,keytool 正在创建它们并将它们放入密钥库中。
在第二个示例中,您缺少私钥。

你应该这样做:

  1. 将公共证书和私钥导入 pkcs12 (*.p12) 密钥库
    openssl pkcs12 -export -in mycert.crt -inkey mykey.key \ -out lig.p12 -name some-alias \ -CAfile ca.crt -caname root

  2. 将 pkcs12 转换为 JSK
    keytool -importkeystore \ -deststorepass changeit -destkeypass changeit -destkeystore lig.keystore \ -srckeystore lig.p12 -srcstoretype PKCS12 -srcstorepass some-password \ -alias some-alias

  3. 从您的代码中引用这个新的 JKS 密钥库


参数解释

mycert.crt --> 你的公共证书
mykey.key --> 你的私钥
ca.crt --> 签署您的公共证书和私钥的证书颁发机构的公共证书

不能使用该 ca.crt 创建 p12 密钥库,但您应该强>。 p12 也应该拥有它,如果某些库不存在,您可能会遇到问题。无论如何,您可以尝试使用和不使用它;如果失败,图书馆很可能会非常清楚地告诉您问题。
如果您使用的是自签名证书,您绝对可以忘记 ca.crt 参数,并且任何程序都不会给您带来任何问题。但如果我理解得很好,您使用的是第三方证书,所以我猜他们已经给了您他们的 ca.cert 或者可能是 .p12 以及所有内容(或 .pfx,这是相同的)。
如果仍然不清楚,您可以列出他们提供给您的文件,我可以告诉您哪个是哪个。我猜系统管理员会连贯地命名文件(他们通常会这样做),所以应该很简单。

【讨论】:

  • 什么是 -CAfile 和 -caname ?我们是否需要创建 ca.crt 和 root 或者它们是现有文件。你能详细解释一下吗?
  • 我为你添加了一些额外的信息。我觉得你会更舒服一些指导,请提供系统管理员给你的文件的文件名,我很乐意编辑命令以适应它们。
猜你喜欢
  • 2019-12-06
  • 2018-01-12
  • 2016-05-04
  • 2012-03-02
  • 2016-01-18
  • 2018-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多