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)
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:
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
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
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.
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.