If you want detailed documenntation, take a look at the JSSE Reference Guide, more specifically its SSLContext section.
The default values (if you pass null
to SSLContext.init(...)
) are sensible by default, but you may want to understand what these default values are (see the Customization section).
There's no default for the keystore (only the truststore, which you'll almost certainly want to customise anyway if you want client certificate authentication).
Typically, you can initialise an SSLContext
as follows:
KeyStore ks = KeyStore.getInstance(...); // Load the keystore
ks.load(...); // Load as required from the inputstream of your choice, for example.
KeyStore ts = KeyStore.getInstance(...); // Load the truststore
ts.load(...);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, <the key password>);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
Perhaps you may also be interested in this answer for the difference between keystore and truststore. In short, both are "keystores" in the storage sense, but the keystore is where you store your certificates (+chain) and associated private keys (i.e. the server cert and priv. key on a server and the client cert and priv. key on a client) and the truststore is where you store the CA certificates or the remote certificates (without private keys, because they're not your certs) that you're willing to trust, when the remote party presents its certificate.
Regarding what to do with your key/cert files, the easiest is certainly to use a keystore of type PCKS12
, which you can build as described in this answer.
EDIT: (Following comments)
So is it correctly understood that I can get away with a null
TrustManager if I'm a server and not yet doing SSL client
authentication?
Yes.
But that if I were to do cliemt authentication I need to provide a
TrustManager that contains the public keys of every client that should
be able to connect?
Usually not. You'd provide a CA certificate for the CA that issued these client certificates. If you don't have this infrastructure (or if you're building it and don't have any client certificates yet), you should look into creating your own PKI, or perhaps buying client certificates from a well-known CA.
You could also build a TrustManager that accepts self-signed certificates (independently from any CA) and verifies them using the fingerprint from a pre-defined list, but this comes with a number of problems (in particular how the server asks for the right certificate), and you'd may end up replicating parts of what PKIs are for. That's not something I'd recommend unless you understand more about what you're doing.
That's a bit of a downer; I had hoped I could have waited until I got
the request URL before I needed to retrieve a fingerprint for the
authorized client and only then compare to the fingerprint the actual
client authenticated with.
Here, you're talking about a completely different aspect. If you want to get the requested URL first, before requesting the certificate, you'll need to use re-negotiation. The HTTP layer would have to talk to the SSLEngine
for ask it to trigger a new handshake (now set up to ask for a client certificate).
SSLEngine
isn't the easy path to SSL/TLS in Java in general, but asynchronous renegotiation can become very tricky. Indeed, its semantics aren't quite clear at the application layer. You could very well trigger a re-negotiation after receiving an HTTP request, but be in the middle of sending a response at the same time (since you may have asynchronous request/response, possibly pipelined). Technically, the new handshake would affect both pipes.
Overall, renegotiation or not, that's quite independent of checking how you trust the client certificate. If you really want to go down the road of having your application layer (and not the SSL/TLS layer) do the certificate verification, you'd have to write an X509TrustManager
that trusts anything (bypassing the verification at the SSL/TLS layer) and have your application get the cert from the SSLSession
(peer certificate) and do the verification there. Overall, that's quite similar to accepting self-signed certs and verifying them more manually. It can be done, but you'd be stepping out of the PKI model, and you would need some custom code to do so (as opposed to just using the API as it's meant to be used by default).
If you're new to all this, I'd avoid this approach. Try perhaps to set up a test CA and learn how it works first. The whole issue about using a CA or doing manual fingerprint verification is ultimately more an administrative problem: it's defined by how you're going to distribute your certificates between the parties involved.
Also, what is <the key password>
doing here? This is supposed to run
on an unattended server in a hosting facility somewhere; we cannot
wait for someone to come around to type in a password during startup
(say, after a power outage).
You'll need to set a password. Most servers read it from a configuration file if needed (or worse, you could hard-code it).