5

I use this method to register the client certificate into the server certificate.

/**
 * Links the user's certificate into the server's keystore/truststore.
 * 
 * @param server
 *            The server party.
 * @return <code>true</code> if the certificate has been bound,
 *         <code>false</code> if the certificate already was bound to the
 *         truststore.
 * @throws KeyStoreException
 */
public boolean linkToServerCertificate(Party server) throws KeyStoreException {
    if (keyAlias.equals(server.keyAlias)) {
        throw new IllegalArgumentException("The alias of client and server must be different!");
    }
    keystore.setCertificateEntry(server.keyAlias, server.getAliasCert());
    Certificate certificate = keystore.getCertificate(keyAlias);
    server.keystore.setCertificateEntry(keyAlias, certificate);
    return true;
}

After the restart of the AS i get this message:

enter image description here

Having environment variable JAVA_OPTS="-Djavax.net.debug=ssl" i get this informatinos:

*** ServerHelloDone
https-jsse-nio-8443-exec-7, WRITE: TLSv1.2 Handshake, length = 1522
https-jsse-nio-8443-exec-8, READ: TLSv1.2 Handshake, length = 7
*** Certificate chain
<Empty>
***
https-jsse-nio-8443-exec-8, fatal error: 42: null cert chain
javax.net.ssl.SSLHandshakeException: null cert chain
%% Invalidated:  [Session-4, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
https-jsse-nio-8443-exec-8, SEND TLSv1.2 ALERT:  fatal, description = bad_certificate

So the certificate-chain of the certificate is empty

But inspecting the certificate on client, its pointing out that there is a certificate chain.

enter image description here

I am confused, why is the certificate chain not transported to the server?

Grim
  • 1,938
  • 10
  • 56
  • 123
  • I'm not really sure what you are trying to accomplish here. But have a look if [this post](https://stackoverflow.com/questions/36309562/err-bad-ssl-client-auth-cert) matches and solves your problem. – Steffen Ullrich Jan 27 '18 at 08:06
  • @SteffenUllrich Does not help. Eset is not installed. – Grim Jan 27 '18 at 08:29
  • *"Eset is not installed"* - but maybe there is some other SSL intercepting software (another antivirus product, deep inspection firewalls, proxy...) between client and server? These might cause the same problems because client side certificates will not work together with SSL interception in general. – Steffen Ullrich Jan 27 '18 at 08:41
  • @SteffenUllrich No such software is installed, and why should they modify the certificate chain of outgoing certificates? – Grim Jan 27 '18 at 08:49
  • SSL interception is terminating the SSL connection at the interception device/software and creating a new one. Based on how SSL works it is impossible to forward the original server and client certificates to the peer in this case. It might help in your case to make a packet capture at the client and analyze (with wireshark or similar) what gets actually sent, i.e. especially if the client sends the client certificate at all and what CA the server announces to the client as required for the client certificate. – Steffen Ullrich Jan 27 '18 at 09:27
  • 1
    Is the server sending the list of accepted certificates? probably not, then the client does not send his certificate to authenticate himself. Check that the ServerHello message includes the client certificate or the root. – pedrofb Jan 27 '18 at 10:37
  • @pedrofb If the server is not sending a list of accepted certificates the client does not send a certificate. Right? If the client is not sending a certificate, why is the server complaining that the certificate recieved from the client has no chain? – Grim Jan 27 '18 at 13:25
  • the server does not say that the client is sending a certificate. It says that the certificate chain is empty (the certificate is part of the chain). If the client sent certificate, you would see it in the trace. – pedrofb Jan 27 '18 at 15:18
  • @pedrofb The sever **does** say the client sends a certificate but the certificate is bad. See the error message from the server "(...)BAD_SSL_CLIENT_(...)CERT". Means the client certificate is bad! How do the server know the certificate is bad? Because he recieved it. – Grim Jan 30 '18 at 18:45
  • The traces does not show any certificate being sent to server. It would be useful if you post the complete SSL trace to check the CA list that the server is sending to client, and if the client sends an invalid certificate or none. – pedrofb Jan 30 '18 at 19:20
  • Hi Peter, Can you please tell us what you try to accomplish? I assume you are trying to implement "TLS with client authentication/2 way SSL". What i can understand from your code is that you are trying to "Add a certificate to the server keystore" The default keystore of a JVM is located at '$JAVA_HOME/jre/lib/security/cacerts' You are not adding a certificate to a certificate. Also if you want to properly debug a ssl connection please use openssl. Execute the following command and post it here: openssl s_client -connect www.google.com:443 -showcerts. – guicey Jan 31 '18 at 16:30
  • @TheHagueCoder Thank you for the message. Under my circumstances is that the keystore is the same as the truststore. This one file is located at %HOME%/.keystore on server side. Normal users are not allowed to create private keyrings by their own, so I let users download generated pfx files including the private keys and install teir public keys to the server's truststore. Vise versa I install the server's public key to the pfx-file. Also I use the tomcat's ocsp functionality, but this should not be part of the question. It more than two way ssl, its prepared mutual authentication. – Grim Jan 31 '18 at 18:15
  • @PeterRader Hi peter, sorry what i meant was the truststore indeed. In tomcat to enable https you have to set a keystore. There are different formats for keystores but the easiest to use is a JKS (Java KeyStore). In this keystore you put the server x509 certificate holding the public key and the corresponding private key (javax.net.ssl.keyStore). Tomcat has also a truststore this is a JKS file holding all x509 certificates he trust (javax.net.ssl.trustStore). Good opensource GUI tool to do PKI stuff can be found here: http://keystore-explorer.org/ – guicey Jan 31 '18 at 20:42
  • @PeterRader Make sure you are adding the client root x509 certificate to the tomcat truststore. In the picture listed above it is the top most certficate with the blackstipes. Also add the authentication x509 certificate to the truststore. From the authentication certificate listed in the picture above you send only the corresponding private key (not the chain, pfx or x509) to the server. The easiest format i found to work with extracting certificates and private keys is in PEM (base64 encoded) format. You can then open the files with a text editor. DER format is binary not human readable – guicey Jan 31 '18 at 21:07
  • @PeterRader, does your client keystore contain the private key of the certificate? On the "Allgemein" tab you should see "Sie besitzen einen privaten Schlüssel für dieses Zertifikat". In the client keystore both public and private keys shall be available. – Alexey Feb 01 '18 at 09:24
  • @Alexey yes, the client keystore contains the private key of the client's access. I confirm that the pfx contains the private key (I installed the private key as "exportalbe with private key".) – Grim Feb 02 '18 at 12:17
  • The code seems fine to me, this is just a strong guess: you need the [`Unlimited Strength Jurisdiction Policy Files`](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html) to enable encrypt-decrypt above a certain key length. Let me know if it worked and I'll post it as an answer. – Hash Feb 05 '18 at 07:44

2 Answers2

1

You can copy the full certificate chain like the following.

Key key = keystore.getKey(keyAlias, clientKeyStorePassPhrase);
Certificate[] chain = keystore.getCertificateChain(keyAlias);
server.keystore.setKeyEntry(keyAlias, key, serverKeyStorePassPhrase, chain);

Refer - http://www.java2s.com/Code/Java/Security/Importakeycertificatepairfromapkcs12fileintoaregularJKSformatkeystore.htm for more details on how you can copy certificates from one keystore to another keystore.

Update -

Java api docs also suggest that keystore.getCertificate(keyAlias); returns only the first element of the certificate chain. Ref - https://docs.oracle.com/javase/8/docs/api/index.html?java/security/KeyStore.html

Ref - for more examples of loading certificate chain - https://www.pixelstech.net/article/1420427307-Different-types-of-keystore-in-Java----PKCS12

vsoni
  • 2,828
  • 9
  • 13
0

I made the mistake, I had the certificate chain in the wrong order.

keystore.setKeyEntry(alias, pair.getPrivate(), pass.toCharArray(), 
         chainSet.toArray(new Certificate[0]));

The chainSet must be in the order that the closest certificate is the first certificate.

The real mistake was to use the built-in implementation of pki.

Grim
  • 1,938
  • 10
  • 56
  • 123