20

I'm trying to secure a connection from a Java Client/Server application that communicates over the Internet. My idea was to use SSL sockets with self-signed certificates and client authentication. I did the following:

  • Server: Keystore containing new self-signed certificate. keytool -genkey -kelalg RSA ...
  • Client: Keystore containing new self-signed certificate. keytool -genkey -kelalg RSA ...
  • Server: Truststore containing exported client certificate (from bullet point above). keytool -export to export client certificate and keytool -import -v -trustcacerts to import it into the server's truststore
  • Client: Truststore containing exported server certificate (from first bullet point). keytool -export to export server certificate and keytool -import -v -trustcacerts to import it into the client's truststore

Trust- and keystores are attached correctly to the server/client. I can see the certificates being loaded (SSL debug information). But the whole thing doesn't work. During the SSL handshake, I get the following error (SSL debug information):

main, WRITE: TLSv1 Handshake, length = 897
main, READ: TLSv1 Handshake, length = 141
*** Certificate chain
***
main, SEND TLSv1 ALERT:  fatal, description = bad_certificate
main, WRITE: TLSv1 Alert, length = 2
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: null cert chain
main, IOException in getSession():  javax.net.ssl.SSLHandshakeException: null cert chain
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
    at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificateChain(Unknown Source)
    at sslsocket.Server.getClientDistinguishedName(Server.java:86)
    at sslsocket.Server.main(Server.java:37)

When I disable client side authentication, it works flawlessly.

I'd really appreciate some help. Thank you very much!

Below you find the full, but anonymized output from the server:

Initializing SSL
***
found key for : server
chain [0] = [
[
  Version: V3
  Subject: CN=xxxxxx Server, OU=communication, O=xxxxxx, L=Zuerich, ST=ZH, C=CH
  Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5

  Key:  Sun RSA public key, 1024 bits
  modulus: 9487726xxxxxx15617628447913191
  public exponent: 65537
  Validity: [From: Thu Dec 09 17:04:05 CET 2010,
               To: Wed Jul 03 18:04:05 CEST 2109]
  Issuer: CN=xxxxxx Server, OU=communication, O=xxxxxx, L=Zuerich, ST=ZH, C=CH
  SerialNumber: [    4dxxxxxx5]

]
  Algorithm: [SHA1withRSA]
  Signature:
0000: 6F 06 1D EA E9 DC 5B 5D   EC EB 33 D4 47 01 94 1A  o.....[]..3.G...
xxxxxx
0070: 99 78 C4 31 5F 84 8F 7B   C1 2F 10 A1 9F 50 72 A1  .x.1_..../...Pr.

]
***
adding as trusted cert:
  Subject: CN=xxxxxx Client, OU=communication, O=xxxxxx, L=Zuerich, ST=ZH, C=CH
  Issuer:  CN=xxxxxx Client, OU=communication, O=xxxxxx, L=Zuerich, ST=ZH, C=CH
  Algorithm: RSA; Serial number: 0x4xxxxxx0
  Valid from Thu Dec 09 17:06:56 CET 2010 until Wed Jul 03 18:06:56 CEST 2109

trigger seeding of SecureRandom
done seeding SecureRandom
Opening socket
Waiting for clients...
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
matching alias: server
main, called closeSocket()
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
[read] MD5 and SHA1 hashes:  len = 3
0000: 01 03 01                                           ...
[read] MD5 and SHA1 hashes:  len = 98
0000: 00 3C 00 00 00 20 00 00   04 01 00 80 00 00 05 00  .<... ..........
xxxxxx
0060: 26 51                                              &Q
main, READ:  SSL v2, contentType = Handshake, translated length = 75
*** ClientHello, TLSv1
RandomCookie:  GMT: 1292088238 bytes = { 223,xxxxxx, 81 }
Session ID:  {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_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_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
***
%% Created:  [Session-1, SSL_RSA_WITH_RC4_128_MD5]
*** ServerHello, TLSv1
RandomCookie:  GMT: 1292088238 bytes = { 222,xxxxxx, 241 }
Session ID:  {77,xxxxxx, 235}
Cipher Suite: SSL_RSA_WITH_RC4_128_MD5
Compression Method: 0
Extension renegotiation_info, renegotiated_connection: <empty>
***
Cipher suite:  SSL_RSA_WITH_RC4_128_MD5
*** Certificate chain
chain [0] = [
[
  Version: V3
  Subject: CN=xxxxxx Server, OU=communication, O=xxxxxx, L=Zuerich, ST=ZH, C=CH
  Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5

  Key:  Sun RSA public key, 1024 bits
  modulus: 948772xxxxxx17628447913191
  public exponent: 65537
  Validity: [From: Thu Dec 09 17:04:05 CET 2010,
               To: Wed Jul 03 18:04:05 CEST 2109]
  Issuer: CN=xxxxxx Server, OU=communication, O=xxxxxx, L=Zuerich, ST=ZH, C=CH
  SerialNumber: [    4d00fdf5]

]
  Algorithm: [SHA1withRSA]
  Signature:
0000: 6F 06 1D EA E9 DC 5B 5D   EC EB 33 D4 47 01 94 1A  o.....[]..3.G...
xxxxxx
0070: 99 78 C4 31 5F 84 8F 7B   C1 2F 10 A1 9F 50 72 A1  .x.1_..../...Pr.

]
***
*** CertificateRequest
Cert Types: RSA, DSS
Cert Authorities:
<CN=xxxxxx Client, OU=communication, O=xxxxxx, L=Zuerich, ST=ZH, C=CH>
*** ServerHelloDone
[write] MD5 and SHA1 hashes:  len = 897
0000: 02 00 00 4D 03 01 4D 04   B4 AE DE E4 AF 62 FA 48  ...M..M......b.H
0xxxxxx
0380: 00                                                 .
main, WRITE: TLSv1 Handshake, length = 897
main, READ: TLSv1 Handshake, length = 141
*** Certificate chain
***
main, SEND TLSv1 ALERT:  fatal, description = bad_certificate
main, WRITE: TLSv1 Alert, length = 2
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: null cert chain
main, IOException in getSession():  javax.net.ssl.SSLHandshakeException: null cert chain
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
    at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificateChain(Unknown Source)
    at sslsocket.Server.getClientDistinguishedName(Server.java:86)
    at sslsocket.Server.main(Server.java:37)
Chris
  • 203
  • 1
  • 2
  • 4
  • What happens if you add the client's self-signed certificate to its own truststore? – President James K. Polk Dec 12 '10 at 15:45
  • Doesn't make any difference. I still get the same error. – Chris Dec 12 '10 at 18:44
  • It works for me if my server truststore contains the client certificate and my client truststore contains the server certificate. – President James K. Polk Dec 13 '10 at 01:25
  • @GregS, implementing your first comment wouldn't help anything. – user207421 Dec 13 '10 at 02:47
  • I am unable to understand what would happen if the client was a browser or a medical device. A browser or a company running a device simply ask you for a certificate so that they can send it along with the API request(as they are the client and you are the server validating the client). How then can such a client have a keystore and a truststore? – veritas Dec 09 '22 at 09:49

1 Answers1

15

The first SSL trace appears to be part of the second one, displayed at the server. Please confirm.

The second trace shows that the server asked for an RSA or DSS certificate signed by 'CN=xxxxxx Client, OU=communication, O=xxxxxx, L=Zuerich, ST=ZH, C=CH', and the client replied by sending an empty certificate chain. That can only mean either that the client's keystore doesn't have such a cert in it or that the client wasn't using the correct keystore.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Thanks for that reply. I rechecked the clients keystore, although I thought that I had already done this 100 times. Anyway, I noticed that the keystore did only contain the public key and not the private key of the client's certificate. Somehow I must have messed up. – Chris Dec 13 '10 at 08:52
  • This was helpful, it clarified that either the CA signed cert or the private key or the entire keystore has to be missing for this process to fail at this point `*** Certificate chain` ... For me the problem was that `SSLSocketFactory.getSocketFactory()` automatically loads the truststore set by `-Djavax.net.ssl.trustStore` but it does NOT automatically load the keystore set by `-Djavax.net.ssl.keyStore`!! So I had to do this explicitly: http://www.smartjava.org/content/client-certificates-httpclient-4 – pulkitsinghal Feb 13 '13 at 00:10
  • 2
    Only the default SSLContext obeys javax.ney.ssl.keyStore. The ones you construct yourself with getInstance() don't for some reason. – user207421 Sep 21 '13 at 00:14