Finally managed to solve all the issues, so I'll answer my own question. These are the settings/files I've used to manage to get my particular problem(s) solved;
The client's keystore is a PKCS#12 format file containing
- The client's public certificate (in this instance signed by a self-signed CA)
- The client's private key
To generate it I used OpenSSL's pkcs12
command, for example;
openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12 -name "Whatever"
Tip: make sure you get the latest OpenSSL, not version 0.9.8h because that seems to suffer from a bug which doesn't allow you to properly generate PKCS#12 files.
This PKCS#12 file will be used by the Java client to present the client certificate to the server when the server has explicitly requested the client to authenticate. See the Wikipedia article on TLS for an overview of how the protocol for client certificate authentication actually works (also explains why we need the client's private key here).
The client's truststore is a straight forward JKS format file containing the root or intermediate CA certificates. These CA certificates will determine which endpoints you will be allowed to communicate with, in this case it will allow your client to connect to whichever server presents a certificate which was signed by one of the truststore's CA's.
To generate it you can use the standard Java keytool, for example;
keytool -genkey -dname "cn=CLIENT" -alias truststorekey -keyalg RSA -keystore ./client-truststore.jks -keypass whatever -storepass whatever
keytool -import -keystore ./client-truststore.jks -file myca.crt -alias myca
Using this truststore, your client will try to do a complete SSL handshake with all servers who present a certificate signed by the CA identified by myca.crt
.
The files above are strictly for the client only. When you want to set-up a server as well, the server needs its own key- and truststore files. A great walk-through for setting up a fully working example for both a Java client and server (using Tomcat) can be found on this website.
Issues/Remarks/Tips
- Client certificate authentication can only be enforced by the server.
- (Important!) When the server requests a client certificate (as part of the TLS handshake), it will also provide a list of trusted CA's as part of the certificate request. When the client certificate you wish to present for authentication is not signed by one of these CA's, it won't be presented at all (in my opinion, this is weird behaviour, but I'm sure there's a reason for it). This was the main cause of my issues, as the other party had not configured their server properly to accept my self-signed client certificate and we assumed that the problem was at my end for not properly providing the client certificate in the request.
- Get Wireshark. It has great SSL/HTTPS packet analysis and will be a tremendous help debugging and finding the problem. It's similar to
-Djavax.net.debug=ssl
but is more structured and (arguably) easier to interpret if you're uncomfortable with the Java SSL debug output.
It's perfectly possible to use the Apache httpclient library. If you want to use httpclient, just replace the destination URL with the HTTPS equivalent and add the following JVM arguments (which are the same for any other client, regardless of the library you want to use to send/receive data over HTTP/HTTPS):
-Djavax.net.debug=ssl
-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.keyStore=client.p12
-Djavax.net.ssl.keyStorePassword=whatever
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.trustStore=client-truststore.jks
-Djavax.net.ssl.trustStorePassword=whatever
Don't do it with JavaScript. JavaScript cryptography has a number of problems, and I don't think many browsers will let you access the PKCS#11 directly from JavaScript (running from within the page) easily.
A number of browsers support PKCS#11 for HTTPS authentication, that is, using PKCS#11 for client-certificate authentication as part of the SSL/TLS connection (as part of HTTPS).
Assuming you already have a PKCS#11 library available (let's say OpenSC in /usr/lib/opensc.so
), you can configure Firefox to use it:
- Preferences -> Advanced -> Encryption, go in "Security Devices"
- Click on 'Load'
- Choose a module name (for your own reference in the list) and point to the
/usr/lib/opensc.so
file (or whatever the appropriate PKCS#11 module is in your case).
Then, when you connect to a website that requests a client certificate, the browser should offer you to choose a certificate from the PKCS#11-enabled device.
The PKCS#11 configuration mechanism will vary from one browser to another, but it's usually a matter of setting the path of the PKCS#11 module.
As far as I know, Internet Explorer doesn't use PKCS#11 (at least not without extra support), but should rely on MS CryptoAPI and InfoCards instead.
On the server side, you will need to configure the requirement for client-certificate authentication. Nothing specific to PKCS#11 there.
Following your edit, you should read about Certification Authorities (CAs) and Public Key Infrastructures (PKIs). You could deploy your own internal PKI, but it sounds like your requirements are to integrate with an existing PKI. This is an administrative problem mainly, so check with those making this requirement to see on which CA they want to rely (probably theirs).
When using client-certificate authentication, the client will present its certificate (which contains the user's public key and other attributes, including an identifier: the Subject Distinguished Name) and the SSL/TLS handshake will ensure that the client has the private key for this public key certificate. Then, the server verifies this certificate against CAs it trusts (that's also an SSL setting on the server side).
Once you've configured which CAs you want to trust, the mapping is usually done using the certificate's Subject DN to an internal user name if needed. There is no hard rule for this, since it depends on your internal user naming scheme. This being said, it's often sensible to use the full Subject DN as the user name.
Best Answer
Yes. However you may recognize a higher delay when using a hardware token compared to a software token (e.g. for a smartcard 2-3 seconds).
by default e.g. Firefox only tries to access the client certificates if you connect to a web-page that has HTTPS client auth enabled. Then the PIN will be requested. Usually the PIN is then no longer needed as long as the token is not removed but that behavior may differ depending on the used PKCS#11 module (the software that connects Firefox with the token).
Then depends on the token. Some may have an API for extracting the private key but usually you can only use or delete private key + certificate from the token.