1

I need to add these 3 pem files (ca.pem, key.pem, and cert.pem) to my http client in order to access a client's service.

How do I get these to work with my existing httpclient? Any help will be appreciated.

Thank you.


File caFile = new File(getClass().getResource("/certs/ca.pem").getPath());
File keyFile = new File(getClass().getResource("/certs/key.pem").getPath());
File certFile = new File(getClass().getResource("/certs/cert.pem").getPath());


SSLContext sslContext = new SSLContextBuilder()
            .loadTrustMaterial(null, ( certificate, authType ) -> true).build();

CloseableHttpClient httpClient = HttpClients.custom()
            .setSSLContext(sslContext)
            .setSSLHostnameVerifier(new NoopHostnameVerifier())
            .addInterceptorFirst((HttpRequestInterceptor) ( httpRequest, httpContext ) -> {
                httpRequest.setHeader("Content-Type", "application/xml");
            })
            .build();

HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
Robert Wilson
  • 659
  • 1
  • 12
  • 28
  • What is in `cert.pem`? Is it a certificate for the service the client wants to access? Or a certificate for the client (because the service requires client certificates)? Similarly, what is in the CA file? And why do you need the key file? What is it a key file _for_? (Not for the service the client wants to access, I assume, as the client should never have that). – andrewJames May 06 '23 at 15:16
  • Possibly related: [Apache HttpClient and PEM certificate files](https://stackoverflow.com/q/4146624/12567365), and [Including a .pem certificate in a Java HTTP request](https://stackoverflow.com/q/47161402/12567365) - and [similar questions](https://www.google.com/search?q=apache+httpclient+use+pem+files+site:stackoverflow.com). – andrewJames May 06 '23 at 15:20
  • @andrewJames, ```ca.pem``` and ```cert.pem``` are both certificates and ```key.pem``` is RSA private key – Robert Wilson May 06 '23 at 15:28
  • @andrewJames. Also, note, these are not certificates I generated. It was shared by a client. I've seen the related posts and they are both slightly different solutions. I possibly would want to avoid converting the certs to .p12 – Robert Wilson May 06 '23 at 15:38
  • Right - but certificates and key file _**for what**_? So, for `cert.pem` - what is it? Is it a certificate for the service the client wants to access? Or a certificate for the client (because the service requires client certificates)? (Also the use of the word "client" may be confusing here - "client" as in "my ApacheClient program" and "client" as in some other people I am working for...). – andrewJames May 06 '23 at 16:07
  • I think this is the answer you are looking for which I have posted here: https://stackoverflow.com/questions/42675033/how-to-build-a-sslsocketfactory-from-pem-certificate-and-key-without-converting/66297869#66297869 – Hakan54 May 06 '23 at 22:32
  • @Hakan54. Thanks for sharing, however, I'm getting the exception below. ```No valid InputStream has been provided. InputStream must be present, but was absent.``` The ```.pem``` files are located in a folder named ```certs``` under ```resources```. – Robert Wilson May 08 '23 at 09:27
  • 1
    It seems like you are providing a InputStream, which should work but it seems like the inputstream which you have loaded yourself is null and therefor it is throwing that exception. It would be maybe better to delegate the loading of the file to the library, can you maybe try: `PemUtils.loadTrustMaterial("certs/ca.pem");` and `PemUtils.loadIdentityMaterial("certs/cert.pem", "certs/key.pem")`; – Hakan54 May 08 '23 at 10:00
  • @Hakan54. It worked. Thanks a lot. Can you kindly convert this to an answer so I can accept it? Somebody might be needing this solution too I guess. – Robert Wilson May 08 '23 at 10:26

1 Answers1

1

I have guided the OP and provided the answer in the comment section of his question. The solution did work, so I am posting it here.

Java is limited and verbose of handling all of the different pem files. In the past I wanted also to load pem files for different projects and to make it reusable I created a library which does the trick. The solution which I provided to the OP for an apache http client is:

Option 1

You first need to add the following dependency GitHub - SSLContext Kickstart:

<dependency>
    <groupId>io.github.hakky54</groupId>
    <artifactId>sslcontext-kickstart-for-pem</artifactId>
    <version>8.0.0</version>
</dependency>

And then you can use the following code snippet:

import nl.altindag.ssl.SSLFactory;
import nl.altindag.ssl.pem.util.PemUtils;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;

import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509ExtendedTrustManager;

public class App {

    public static void main(String[] args) {
        X509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial("certs/cert.pem", "certs/key.pem");
        X509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial("certs/ca.pem");

        SSLFactory sslFactory = SSLFactory.builder()
                .withIdentityMaterial(keyManager)
                .withTrustMaterial(trustManager)
                .build();

        HttpClient httpclient = HttpClients.custom()
                .setSSLContext(sslFactory.getSslContext())
                .build();

        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpclient);
    }
    
}

Option 2

If you don't want the above library and you don't have an encrypted private keys and just certificates as pem files, then you can also give the following example from another answer a try: https://stackoverflow.com/a/42733858/6777695 That one provides an example in just plain java how to parse a pem file. If you have an encrypted private key it will get a bit more verbose, see here for more: Parsing encrypted PKCS#8 encoded pem file programatically

Hakan54
  • 3,121
  • 1
  • 23
  • 37