简体   繁体   中英

Java SSL - Connect to secure Rest Service using pkcs12 (.p12) file

I am consuming a rest service for my web application. And the service provider has provided a.p12 file with a password to connect to their service.

I installed the certificate file in postman for testing purposes and it works fine.Now I have to integrate it to my java code.

This is my java code for integration.

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.KeyManagerFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

@Service
public class DemoIntegration
{

    String key = "XYX";
    String value = "12BN";
    String encVal= "343fhh22343mm90ddfd61lcsert";
    private static String certPw = "44vvxxffx";  //Password to cerfificate file

    public void checkConnection()
    {
        try
        {
            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders httpHeaders = new HttpHeaders();

            String uri = "https://my_demo_uri";

            KeyStore ks = KeyStore.getInstance("pkcs12");
            ks.load(new FileInputStream("C:\\Users\\my_cert.p12"), certPw.toCharArray()); //my_cert.p12 is my cerfificate file 

            KeyStore jks = KeyStore.getInstance("JKS");
            jks.load(null);

            for (Enumeration<String> t = ks.aliases(); t.hasMoreElements();)
            {
                String alias = t.nextElement();
                System.out.println("@:" + alias);
                if (ks.isKeyEntry(alias))
                {
                    Certificate[] a = ks.getCertificateChain(alias);
                    for (int i = 0; i < a.length; i++)
                    {
                        X509Certificate x509 = (X509Certificate) a[i];
                        System.out.println(x509.getSubjectDN().toString());
                        if (i > 0)
                        {
                            jks.setCertificateEntry(x509.getSubjectDN().toString(), x509);
                        }
                        System.out.println(ks.getCertificateAlias(x509));
                        System.out.println("ok");
                    }
                }
            }

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

            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(jks);

            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            httpHeaders.set("API_KEY", api_key);
            httpHeaders.set("Signature", SHA256Val);

            String r2 = restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<>(httpHeaders), String.class).getBody();
            System.out.println("Result " + r2);
        }
        catch (Exception ex)
        {
            System.out.println("Error " + ex.toString());
            Logger.getLogger(DemoIntegration.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

And always I get the response like below. This is the same response I got when I tested it with postman without adding the certificate file to it.

400 Bad Request:{
  "error": {
    "message": "No SSL cetificate"
  }
}

Can someone point out what am I doing wrong here?

I am a newbie when it comes to java security area.To be honest I followed a guide to write this code/Is there a checklist to follow when trying to connect? (Like adding the file to keystore or truststore.At least a guide would help me here)

Thanks a lot in advance.

Can you give this code a try? I have made some changes to the load Truststore. Make sure to pass the path of the system Truststore from your code.

package com.jerry;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import javax.net.ssl.*;

import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;


public class SSLTest {
    private String api_key = "XYX";
    private  String api_secret = "12BN";
    private String SHA256Val = "343fhh633343mm90ddfd61lcsert";
    private static String certPw = "44vvxxffx";  //

    String trustStorePath = "C:/Program Files/Java/jre1.8.0_91/lib/security/cacerts";
    String trustStorePassword = "changeit"; // default trust store password

    public void checkConnection()
    {
        try
        {
//            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders httpHeaders = new HttpHeaders();

            String uri = "https://my_demo_uri";

            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(new FileInputStream("C:\\Users\\IB\\Downloads\\my_cert.p12"), certPw.toCharArray()); //my_cert.p12 is my cerfificate file

            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(ks, certPw.toCharArray());
            KeyManager[] kms = kmf.getKeyManagers();

            KeyStore jks = KeyStore.getInstance("JKS");
            jks.load(new FileInputStream(trustStorePath), trustStorePassword.toCharArray());
//
//            for (Enumeration<String> t = ks.aliases(); t.hasMoreElements();)
//            {
//                String alias = t.nextElement();
//                System.out.println("@:" + alias);
//                if (ks.isKeyEntry(alias))
//                {
//                    Certificate[] a = ks.getCertificateChain(alias);
//                    for (int i = 0; i < a.length; i++)
//                    {
//                        X509Certificate x509 = (X509Certificate) a[i];
//                        System.out.println(x509.getSubjectDN().toString());
//                        if (i > 0)
//                        {
//                            jks.setCertificateEntry(x509.getSubjectDN().toString(), x509);
//                        }
//                        System.out.println(ks.getCertificateAlias(x509));
//                        System.out.println("ok");
//                    }
//                }
//            }


            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(jks);
            TrustManager[] tms = tmf.getTrustManagers();


            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
            SSLSocketFactory socketFactory = new SSLSocketFactory(ks, certPw, jks);

            HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(
                    socketFactory).build();
            ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(
                    httpClient);
            RestTemplate restTemplate = new RestTemplate(requestFactory);
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            httpHeaders.set("API_KEY", api_key);
            httpHeaders.set("Signature", SHA256Val);

            HttpEntity<String> entity = new HttpEntity<>("body", httpHeaders);

            String r2 = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class).getBody();
            System.out.println("Result " + r2);
        }
        catch (Exception ex)
        {
            System.out.println("Error " + ex.toString());
        }
    }
}

PS: I could not validate this code because i dont have the certificate and key. :)

You should not have to hardcode anything to get this to work but just add some startup parameters for Java, like:

-Djavax.net.ssl.keyStore=C:\Users\my_cert.p12

. (although they are then shared by all threads and code running in your application which may not be acceptable) Check out this question and the answers provided:

java SSL and cert keystore

Further it can be very useful to know what is going on behind the curtain which you can see with some extra logging enabled with eg:

-Djavax.net.debug=all

Try this approach.I cannot test this since I do not have the certificate file but I hope with some minor modifications,it will work.

Please include your certificate file in the resources folder.

@Service
public class DemoIntegration
{
    String key = "XYX";
    String value = "12BN";
    String encVal= "343fhh22343mm90ddfd61lcsert";
    private static String certPw = "44vvxxffx";

    public void checkConnection()
    {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        httpHeaders.set("API_KEY", api_key);
        httpHeaders.set("Signature", SHA256Val);

        String uri = "https://my_demo_uri";

        try
        {
            RestTemplate restTemplate = getRestTemplateClientAuthentication();

            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            httpHeaders.set("API_KEY", api_key);
            httpHeaders.set("Signature", SHA256Val);

            String r2 = restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<>(httpHeaders), String.class).getBody();
            System.out.println("Result " + r2);
        }
        catch (Exception ex)
        {
            System.out.println("Error " + ex.toString());
            Logger.getLogger(PesonetService.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private RestTemplate getRestTemplateClientAuthentication() throws Exception
    {
        TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;

        SSLContext sslContext = SSLContextBuilder
                .create()
                .loadKeyMaterial(ResourceUtils.getFile("classpath:my_cert.p12"),
                 certPw.toCharArray(), certPw.toCharArray())
                .build();

        CloseableHttpClient client = HttpClients.custom()
                .setSSLContext(sslContext)
                .build();

        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(client);

        RestTemplate restTemplate = new RestTemplate(requestFactory);
        return restTemplate;
    }
}

Let me know if it works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM