I am programming a client with mutual authentication. The Server has provided me with certificate (.cer), key and password. With these I can connect through Insomnia without problems. Through openSSL I have generated a pfx file that I use to connect from FireFox (and what am I trying to use here). However I can't connect from JAVA as I always get the message "PKIX..." (getOutputStream line). Below my code:
private static void testConnection(String urlS) throws Exception {
KeyStore keyStore;
keyStore = KeyStore.getInstance("PKCS12");
keyStore.load((Main.class.getResourceAsStream("serverCertificate.pfx")), "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, "password".toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
KeyStore trustStore = KeyStore.getInstance("JKS");
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
TrustManager[] tms = tmf.getTrustManagers();
SSLContext sc;
sc = SSLContext.getInstance("TLSv1.2");
sc.init(kms, tms, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
URL url = new URL(urlS);
HttpsURLConnection urlConn = (HttpsURLConnection) url.openConnection();
urlConn.setSSLSocketFactory(sc.getSocketFactory());
urlConn.setRequestMethod("POST");
urlConn.setRequestProperty("KeyId", "myKeyID");
urlConn.setRequestProperty("X-Request-ID", "XXX");
urlConn.setRequestProperty("Content-Type", "application/json");
urlConn.setDoOutput(true);
String jsonString = "my json string here";
OutputStream os = urlConn.getOutputStream();
os.write(jsonString.getBytes());
os.flush();
os.close();
int response = urlConn.getResponseCode();
}
It's wrong?
PS: I've seen the question in this link and I think it's not the same problem because my code is different and also I don't intend to create a keystore and add it to the jvm (if possible), as suggested in the solution.
I have noticed that there is no documentation that clearly defines how to set up a client in mutual authentication without using the jvm (cacerts). Even here on StackOverflow that configuration mode is the most widespread, and the only one. I have inquired about how to do it, it becomes a bit complex due to the use of OpenSSL, but the result is worth it. Next I leave you a step-by-step document so that you can configure your client in this way.
MUTUAL AUTHENTICATION
Mutual authentication requires both client and server to present their certificates and validate each other's certificate.
The client certificate can be issued by the entity that owns the server or by a certifying institution.
(you can find a lot of information online, starting from wikipedia)
PURPOSE OF THIS GUIDE
Existing documentation for configuring client certificate inside the JVM (cacerts) is abundant. In fact it is the default.
This configuration has some disadvantages such as:
This document will explain how to configure both certificates within the project, without making any changes to the JVM.
SOFTWARE REQUIRED
OpenSSL (you can download it from here, to be safe don't download it from third parties)
PRECONDITIONS
You must have:
PROCEDURE
If you already meet the conditions, here are the instructions:
KeyStore (Client Certificate)
The KeyStore is a single file, in this case with the extension pfx (it can also be .jks), which includes the Client Certificate + the Key.
It is generated by openssl like this:
openssl will ask for the password for the client certificate
If you have a root CA and intermediate certificates, include these as well using various -in parameters, for example:
TrustStore (Server Certificate)
Once you have the server certificate, you must first convert it to a cer file as explained below:
.pem to .cer
.cer to .jks
You must define $CERT_ALIAS and $CERT_PASSWORD
At this point you should have the KeyStore (keystore.pfx) and the TrustStore (truststore.jks). So let's see how they are used in the code.
ENCODING
Later we will see, in part and then in full, how to use these files in a method.
Add the keystore.pfx and truststore.jks files inside the project, in the path of your Main class.
How to get the KeyManager
How to get TrustManager (IDEM KeyManager)
Complete method with connection
In the example case the server requested:
The following method is intended to illustrate the sections of code that must be defined in order to communicate with a server via mutual authentication according to the premises established above. Error handling is out of scope - I'll leave that part up to you, as is defining use of other libraries, etc ;-)
If you find it useful, don't forget to leave your "Like"!
For any questions, leave me your comment. Thanks.