views:

292

answers:

3

How do I perform an HTTP request and sign it with a X.509 certificate using Java?

I usually program in C#. Now, what I would like to do is something similar to the following, only in Java:

 private HttpWebRequest CreateRequest(Uri uri, X509Certificate2 cert) 
 {
     HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
     request.ClientCertificates.Add(cert);
     /* ... */
     return request;
 }

In Java I have created a java.security.cert.X509Certificate instance but I cannot figure out how to associate it to a HTTP request. I can create a HTTP request using a java.net.URL instance, but I don't seem to be able to associate my certificate with that instance (and I'm not sure whether using java.net.URL is even appropriate).

+1  A: 

I would recommend the open source HttpClient library from Apache Commons:

http://hc.apache.org/httpcomponents-client/

Covers this use case and many others.

jordan002
A: 

I'm not a C# programmer, but I'm presuming that code makes a call using HTTPS/TLS and provides a client certificate for authentication? Aka, you're not asking how to use WS-Security, right?

In that case, I think the answers here and here will be of use to you. You need to use an openssl utility to import your certificate into a p12 client keystore. If your server is using a non-standard CA or self-signed cert, you'll need to set up a client truststore with those certificates as well.

At this point, look at the questions I've linked: you'll need to specify a whole slew of JVM arguments. Finally, try to make your call again (using standard Java objects or httpclient). The client should accept the server cert if your truststore is correct and the server should ask for a client cert. If your keystore is set up correctly, the client with authenticate with the X.509 client cert and you'll be good to go.

jasonmp85
A: 

It looks like you're trying to use HTTPS with client-certificate authentication. I'm assuming that your server is configured to request this (because the client certificate can only be requested by the server).

In Java, java.security.cert.X509Certificate is really just the certificate (a public key certificate, without the private key). What you need on the client side is to configure the private key with it. Assuming that your private key and certificate are in a keystore (to simplify, I'm assuming there's only one suitable certificate with its private key, perhaps with other certificates in the chain, in that keystore), and that you're using the default trust store:

KeyStore ks = ...
/* load the keystore */

KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, password);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), null, null);

URL url = new URL("https://example/");
HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();

connection.setSSLSocketFactory(sslContext.getSSLSocketFactory());

Other libraries will allow you to set the SSLContext or the KeyStore slightly differently, but the principles should be the same.

(You could also use the javax.net.ssl.keyStore system properties if it's appropriate.)

Bruno