we are trying to build a MUTUAL/2WAY authentication mechanism.
Because we hit two different hosts, we have the same client certificate stored in the client keystore container under two different aliases (please note the same fingerprint):
root@perf-golem-4:/opt/golem# keytool -list -keystore ./client.keystore -storepass ________
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 2 entries
i.domain.io, Jun 16, 2015, trustedCertEntry,
Certificate fingerprint (SHA1): 28:94:45:A1:78:C0:BD:D6:82:7E:09:66:15:11:8D:A5:56:0B:99:39
r.domain.io, Jun 16, 2015, trustedCertEntry,
Certificate fingerprint (SHA1): 28:94:45:A1:78:C0:BD:D6:82:7E:09:66:15:11:8D:A5:56:0B:99:39
Now, under the trusted container we have the target domains certificates (please note how the fingerprint is different between them and also compared to the keystore above):
root@perf-golem-4:/opt/golem# keytool -list -keystore ./trusted.keystore -storepass _______
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 2 entries
i.domain.io, Jun 16, 2015, trustedCertEntry,
Certificate fingerprint (SHA1): 73:F5:96:68:89:56:5E:50:9C:06:69:67:AC:8E:18:D2:D9:C1:33:71
r.domain.io, Jun 16, 2015, trustedCertEntry,
Certificate fingerprint (SHA1): 12:93:C8:41:3F:68:22:8F:40:F8:3C:B9:B6:C4:90:C0:60:49:D0:50
My understanding is that if you have to store a certificate with an alias matching the target domain name (in our case i.domain.io or r.domain.io) so java can provide the associated certificate as a client certificate when you are attempting a SSL connection to that domain e.g. https://r.domain.io
We are launching our app like this:
java -Djavax.net.debug=all \
-Djavax.net.ssl.keyStore=/opt/golem/client.keystore \
-Djavax.net.ssl.keyStorePassword=_____ \
-Djavax.net.ssl.trustStore=/opt/golem/trusted.keystore \
-Djavax.net.ssl.trustStorePassword=_____ \
Our problem is that no client certificate is being presented, or used from the client side so, the big question is does java provide the client certificate associated with an alias that matches target domain name (or subject line in the target SSL cert) or the name of the certificate should be mangled from the code?
That's not the case at all.
Matching is based on the
certificate_authorities
list sent by the server in its TLSCertificateRequest
message (the issuers), and on the type of key (e.g. RSA or DSA). Some imperfect matches can be chosen if the attributes are not quite as expected (see this answer), but you'd at least want to have your client certificate issued by a CA the server advertises for (this is generally done automatically on the server side when you configure the CA certificates it's willing to accept, unless you explicitly change the configuration there).If intermediate certificates are required, you'll certainly want to make sure you've imported the full chain.
Essentially, there is no point having twice the same certificate in your keystore.
(You can try to force a specific alias by extending your own
X509KeyManager
, but that's not sufficient; in particular, that's not going to make the server request it nor make the chain valid.)You need to make sure that the server is configured to request a certificate. This can sometimes be done via renegotiation, so the
CertificateRequest
TLS message might not necessarily be visible using Wireshark. However, you should be able to see it from the client side using-Djavax.net.debug=ssl
(orall
): the official documentation for Debugging SSL/TLS Connections has an example if you search forCertificateRequest
on the page.Then, you need to make sure your certificate (or the top of the chain on the client end, if there are intermediate certs) was issued by one of the CAs that is advertised in that
CertificateRequest
message (the Issuer DN must match).(If the certificate authorities list in
CertificateRequest
is empty, but theCertificateRequest
message is still sent, the client will send the first certificate it finds in its keystore by default. That sort of scenario is atypical, since it requires custom configuration on the server side in general.)