Connect to a https site with a given p12 certificate

后端 未结 5 1325
無奈伤痛
無奈伤痛 2020-12-04 10:32

The server side gave me a .p12 certificate file which I\'ve clicked and installed on my machine and then I can access the HTTPS site through browse

相关标签:
5条回答
  • 2020-12-04 10:46

    Simple keytool command would export your .p12 keystore into .jks keystore:

    keytool -importkeystore -srckeystore keystore.p12 -srcstoretype PKCS12 -deststoretype JKS -destkeystore keystore.jks

    0 讨论(0)
  • 2020-12-04 10:47

    If you want to attempt to code up the SSL configuration, you could use the P12 file given to you without having to convert it into a JKS. Also, you will need to use the private key in the P12, and not just the certificates that you copied into the JKS. Not sure if this will suit your needs directly, but this may put you on the right path:

            KeyStore clientStore = KeyStore.getInstance("PKCS12");
            clientStore.load(new FileInputStream("test.p12"), "testPass".toCharArray());
    
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(clientStore, "testPass".toCharArray());
            KeyManager[] kms = kmf.getKeyManagers();
    
            KeyStore trustStore = KeyStore.getInstance("JKS");
            trustStore.load(new FileInputStream("cacerts"), "changeit".toCharArray());
    
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(trustStore);
            TrustManager[] tms = tmf.getTrustManagers();
    
            SSLContext sslContext = null;
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(kms, tms, new SecureRandom());
    
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
            URL url = new URL("https://www.testurl.com");
    
            HttpsURLConnection urlConn = (HttpsURLConnection) url.openConnection();
    

    Configuring the trustStore this way is optional. You could create a JKS with all of the certificates in the chain of your P12, or just make sure they are in your JRE's cacerts file. As for keytool, for reference, you can run keytool commands on a P12 (specify -storetype pkcs12), but cannot import a P12 into a JKS. You also cannot export just a key from a P12 with the keytool command.

    I have no servers setup at the moment to test out this code, so give it a shot and see if you still receive the 403 error.

    0 讨论(0)
  • 2020-12-04 10:56

    Adding this as an answer as I need more space to write.

    First, a question: Is the certificate signed by a trusted authority such as Verisign? If it's not, the truststore should have the CA Certificate (usually a .pem file) which makes the p12 cert 'valid'. The default java trust store contains most (if not all) of the CA certificates from the big companies, such as Verisign and Thawte.

    Also, you can test your app to connect to the secure server without coding the SSL configuration, but with some command line parameters, for example:

    java -Djavax.net.ssl.keyStore=[path_to_p12_cert] \
     -Djavax.net.ssl.keyStorePassword=[p12_password] \
     -Djavax.net.ssl.keyStoreType=PKCS12 \
     -Djavax.net.ssl.trustStore=[path_to_trust_store_with_CA_certificates] \
     -Djavax.net.ssl.trustStorePassword=[trust_store_password] \
     [MainClass]
    

    and then your code becomes just

    HttpsURLConnection con = (HttpsURLConnection) (new URL(urlString)).openConnection();
    con.connect();
    con.getInputStream();
    con.disconnect();
    

    If you feel masochistic, the JSSE ref guide is great fun.

    0 讨论(0)
  • 2020-12-04 11:02

    In case you are using Spring, it could be reached by RestTemplate:

    public RestTemplate restTemplate() throws Exception {
        KeyStore clientStore = KeyStore.getInstance("PKCS12");
        InputStream resource = this.getClass().getClassLoader().getResourceAsStream("path_to_certificate.p12");
        clientStore.load(resource, "p12_password".toCharArray());
    
        SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
        sslContextBuilder.setProtocol("TLS");
        sslContextBuilder.loadKeyMaterial(clientStore, "p12_password".toCharArray());
        sslContextBuilder.loadTrustMaterial(new TrustSelfSignedStrategy());
    
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContextBuilder.build());
        CloseableHttpClient httpClient = HttpClients.custom()
            .setSSLSocketFactory(sslConnectionSocketFactory)
            .build();
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        return new RestTemplate(requestFactory);
    }
    
    0 讨论(0)
  • 2020-12-04 11:08

    This is what worked for me:

       KeyStore keyStore  = KeyStore.getInstance("PKCS12");
        FileInputStream instream = new FileInputStream(new File("client-p12-keystore.p12"));
        try {
            keyStore.load(instream, "password".toCharArray());
        } finally {
            instream.close();
        }
    
        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom()
            .loadKeyMaterial(keyStore, "password".toCharArray())
            //.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
            .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
            sslcontext,
            SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        CloseableHttpClient httpclient = HttpClients.custom()
            .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
            .setSSLSocketFactory(sslsf)
            .build();
        try {
    
            HttpGet httpget = new HttpGet("https://localhost:8443/secure/index");
    
            System.out.println("executing request" + httpget.getRequestLine());
    
            CloseableHttpResponse response = httpclient.execute(httpget);
            try {
                HttpEntity entity = response.getEntity();
    
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                if (entity != null) {
                    System.out.println("Response content length: " + entity.getContentLength());
                }
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }
    
    0 讨论(0)
提交回复
热议问题