I'm trying to reach a Rest WebService that should send me a JSON response,
for which I need to expose a certificate in a KeyStore that lets me authenticate, meanwhile I need the same certificate to be in the TrustStore of my App so that my client recognizes the WebService.
I succesfully put the keys in the SSLContext, but I didn't have the same luck with the TrustStore, since it keeps giving me PKIX Path Building Failed.
This is the method that defines the Context:
public SSLContext defineTrustManager() {
TrustManagerFactory trustManagerFactory;
try {
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
X509TrustManager defaultX509CertificateTrustManager = null;
for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
if (trustManager instanceof X509TrustManager ) {
defaultX509CertificateTrustManager = (X509TrustManager) trustManager;
break;
}
}
FileInputStream myKeys = new FileInputStream("./certificatiAddizionali");
KeyStore myTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
myTrustStore.load(myKeys, "".toCharArray());
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(myTrustStore);
X509TrustManager myTrustManager = null;
for (TrustManager tm : trustManagerFactory.getTrustManagers()) {
if (tm instanceof X509TrustManager ) {
myTrustManager = (X509TrustManager) tm;
break;
}
}
X509TrustManager finalDefaultTm = defaultX509CertificateTrustManager;
X509TrustManager finalMyTm = myTrustManager;
X509TrustManager wrapper = new X509TrustManager() {
private X509Certificate[] mergeCertificates() {
ArrayList<X509Certificate> resultingCerts = new ArrayList<>();
resultingCerts.addAll(Arrays.asList(finalDefaultTm.getAcceptedIssuers()));
resultingCerts.addAll(Arrays.asList(finalMyTm.getAcceptedIssuers()));
return resultingCerts.toArray(new X509Certificate[resultingCerts.size()]);
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return mergeCertificates();
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
finalMyTm.checkServerTrusted(chain, authType);
} catch (CertificateException e) {
finalDefaultTm.checkServerTrusted(chain, authType);
}
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
finalDefaultTm.checkClientTrusted(mergeCertificates(), authType);
}
};
String keyPassphrase = "";
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream("./certificatiKeystore"), keyPassphrase.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keyPassphrase.toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), new TrustManager[] { wrapper }, null);
SSLContext.setDefault(context);
return context;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
This is the test method I'm using to reach WS and check the response:
@RequestMapping(value = "/getSomething", method = RequestMethod.GET)
public void test(HttpServletRequest request) {
HttpResponse response = null;
try {
SSLContext sslContext = defineTrustManager();
HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
response =httpClient.execute(new HttpGet("mytesturl.com"));
System.out.println(response);
}
catch(Exception e) {
e.printStackTrace();
}
}
In debug I can clearly see that the certificates are present and read by the TrustManagerFactory, so then why it keeps giving me the PKIX error? Ps. both the keystore and truststore have no password.