How to request a URL that requires a client certificate for authentication

It's not clear what the restrictions you're talking about are. More specifically, I'm not sure what you consider the difference between the local certificate file and a keystore. Most keystores are file-based, so you might be able to load the file this way directly, without needing an installation process. Are the restrictions related to the security policies used by the JVM itself (which may prevent you from instantiating KeyStores)?

First, it's not just the certificate you need on the client side, but its private key. Often, people use the word "certificate" in this context to mean both, but you do need to make sure your file doesn't contain the certificate without the private key. Typically, you'll find the combination of private key + certificate in a PKCS#12 file (.p12/.pfx), a lot of tools import/export in this format; it's also a keystore format natively supported by the Sun JVM (type PKCS12).

To make this work, you need to configure what makes the connection with the appropriate keystore. SSL/TLS client-certificate authentication is always initiated by the server: the client responds with a certificate if it has one (and wants to use it). To configure it for a specific URL, you need to find out what makes the connection (perhaps HttpsURLConnection) and set it there (unless it's set up in the default context -- even if it's set up in the default context, it will only be used for servers that request it).

To set up the keystore globally on the JVM (which may be what your restrictions prevent you to do), you can set the javax.net.ssl.keyStore javax.net.ssl.keyStorePassword (and related) system properties. (Because the password could be visible, it's better not to do it on the command line).

These system properties are used for the configuration of the default SSLContext (which is used, often transparently, by libraries or classes such as HttpsURLConnection to build the SSLSocketFactory and then SSLSocket, initialized with those properties).

You could build SSLContext from your file specifically for use for that connection. The SSLContext is effectively a factory for the SSLSocketFactory or SSLEngine, and you can set the SSLSocketFactory in a given HttpsURLConnection.

The following would build an SSLContext using "/path/to/file.p12" as your keystore (that is the one with your private key and the certificate you're going to send) and keep the default settings for the truststore (you'd need to catch the exception for the input stream too).

KeyStore ks = KeyStore.getInstance("PKCS12");
FileInputStream fis = new FileInputStream("/path/to/file.p12");
ks.load(fis, "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "password".toCharArray());
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, null);

From there you can configure the connection like this (if this is what you're using):

HttpURLConnection connection = (HttpURLConnection) url.openConnection();
if (connection instanceof HttpsURLConnection) {
    ((HttpsURLConnection)connection)
         .setSSLSocketFactory(sc.getSocketFactory());
}

Some libraries will let you pass an SSLContext directly (Apache HTTP Client 4 supports that, and this can be done with Apache HTTP Client 3 using this.)

Note that you don't need to provide the password as a direct parameter when loading the keystore, you could also use a callback (maybe better from the GUI point of view).

Perhaps this library could help (but it's not necessary): you could use the KeystoreLoader for its helpers to do this. There are also SSLContextFactories in this libraries (but you would probably not need any of the wrappers as they tend to be for customizing the trust management or key selection).

This is generally how using a client-certificate is configured, but it's difficult to provide more details without clarifications regarding what your restrictions exactly are (and which libraries you're using).


You can change the default JSSE keystore through a property when you invoke your app, -Djavax.net.ssl.keystore=somefile.

So you could import your cert with the keytool command into a keystore and invoke your app pointing to that, e.g.

keytool -importcert -file mycert -keystore mystore
java -Djavax.net.ssl.keystore=mystore ...