SSL handshake failure when importing certificates

2019-04-16 23:19发布

问题:

I am creating a HTTPS Server and validating the certificates on my own.

I have a strange error.

When I generate a certificate and add that keystore, I was able to SSL handshake.

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

Whereas When I import the certificate using keytool and add it to the keystore, I am getting SSH Handshake Failure Error.

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

To be precise the first one is a self-signed certificate. The second one is a third party certificate.

SSLHandshake works with self-signed certificates but not with third-party certificates.

Can anyone please tell why ?

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);

        }

}

Console Ouput

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)

回答1:

A third party certificate shouldn't be imported as 'mycert'. It isn't your certficate, it's someone else's. In addition, you have just clobbered your own key pair and certificate. Start again, using a different alias for the 3rd-party cert.



回答2:

The thing is that the keystore has to contain a public certificate and a private key.
In the first example, keytool is creating both of them and putting them into the keystore.
In the second example, you are missing the private key.

You should do:

  1. Import the public certificate and the private key into a pkcs12 (*.p12) keystore
    openssl pkcs12 -export -in mycert.crt -inkey mykey.key \ -out lig.p12 -name some-alias \ -CAfile ca.crt -caname root

  2. Convert the pkcs12 to JSK
    keytool -importkeystore \ -deststorepass changeit -destkeypass changeit -destkeystore lig.keystore \ -srckeystore lig.p12 -srcstoretype PKCS12 -srcstorepass some-password \ -alias some-alias

  3. Refer to this new JKS keystore from your code


Arguments explanation

mycert.crt --> your public certificate
mykey.key --> your private key
ca.crt --> the public certificate of the Certification Authority who signed your public certificate and private key

You could not use that ca.crt for creating the p12 keystore, but you should. The p12 is supossed to hold that too, and you may have problems with some libraries if it isn't there. Anyway, you can try with and without it; in case of fail, the library will most probably tell you about the problem quite clearly.
If you are using self-signed certificates, you absolutely can forget that ca.crt argument, and no program should give you any problem. But if I understood well, you are using third-party certificates, so my guess is that they already gave you their ca.cert or maybe a .p12 with everything (or a .pfx, which is the same).

If it's still unclear, you could list the files they provided you, and I could tell you which one is which. I guess the system administrator names the files coherently (they usually do), so it should be quite straightfoward.