【问题标题】:How to attach .pfx certificate in https connection request using Java?如何使用 Java 在 https 连接请求中附加 .pfx 证书?
【发布时间】:2017-06-01 09:46:06
【问题描述】:

我在 Windows 证书存储中安装了一个 pfx 证书,我可以使用 C# 将其附加到 https REST 调用中。

现在我需要使用 Java 做同样的事情。我读到 .pfx 证书具有私钥以及一个或多个证书。

我收到以下错误:PKIX 路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效认证路径。

我在 Java 中尝试过的事情

  1. 我使用 KeyStore ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI") 直接从 Windows 商店获取证书并创建了我在 HTTPS 调用中使用的 SSLContext

  2. 我从 Windows 商店将证书导入为 .cer 文件,并从代码中将其作为文件读取并附加到 https 调用

  3. 我从代码中读取 .pfx 文件并将其附加到调用中。

  4. 我已使用 KeyTool 将证书添加到 Java-Home (C:/Work/certi/jre1.8.0_91/lib/security/cacerts) 的 cacerts 文件中。

完整的Java代码如下。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;

import javax.net.ssl.TrustManagerFactory;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.conn.ssl.NoopHostnameVerifier;


public class TestElk {

public static void main(String[] args) throws ClientProtocolException, IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, UnrecoverableKeyException, NoSuchProviderException {
        
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    Certificate certificate = certificateFactory.generateCertificate(new FileInputStream(new File("C:/Work/certi/jre1.8.0_91/lib/security/elkcert.cer")));//exported certificate

    /* KeyStore ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
    ks.load(null,null);
    
    Enumeration enumeration = ks.aliases();     
    while(enumeration.hasMoreElements()) {            
        String alias = (String)enumeration.nextElement();
        System.out.println("alias name: " + alias);        }
    
    Certificate[] certificate = ks.getCertificateChain("alias");
     */
    
    // Create TrustStore        
    KeyStore trustStoreContainingTheCertificate =     KeyStore.getInstance(KeyStore.getDefaultType());
    trustStoreContainingTheCertificate.load(null, null);

    trustStoreContainingTheCertificate.setCertificateEntry("cert", certificate);

    // Create SSLContext
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(trustStoreContainingTheCertificate);


    final SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null,trustManagerFactory.getTrustManagers(),new SecureRandom());
    SSLContext.setDefault(sslContext);
    
    HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;   
    
    HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
    HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

    URL url = new URL("https://server-link");
    
    HttpsURLConnection con =    (HttpsURLConnection)url.openConnection();           
    con.setRequestMethod("POST");
    con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko");
    con.setConnectTimeout(10000);
    con.setSSLSocketFactory(sslContext.getSocketFactory()); 
    con.connect();
    
    BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
    StringBuilder sb = new StringBuilder();
    String line;
    while ((line = br.readLine()) != null) {
        sb.append(line+"\n");
    }
    br.close();
    System.out.println(sb.toString());
    //int s= con.getResponseCode();  }

【问题讨论】:

    标签: java ssl https client-certificates sslhandshakeexception


    【解决方案1】:

    鉴于您已将颁发的 CA 证书(请参阅下面的评论)导入 cacerts 文件,以下应该可以工作,可以在不同的 SO 线程 Here 中找到很多帮助:

    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.URL;
    import java.security.KeyManagementException;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.NoSuchProviderException;
    import java.security.SecureRandom;
    import java.security.UnrecoverableKeyException;
    import java.security.cert.CertificateException;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.KeyManager;
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.TrustManagerFactory;
    
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.conn.ssl.NoopHostnameVerifier;
    
    
    public class TestElk {
    
    public static void main(String[] args) throws ClientProtocolException, IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, UnrecoverableKeyException, NoSuchProviderException {
    
        
        KeyStore clientStore = KeyStore.getInstance("PKCS12");
        clientStore.load(new FileInputStream(new File("C:/path_to_pfx/mypfx.pfx")), "pfxPass".toCharArray());
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(clientStore, "pfxPass".toCharArray());
        KeyManager[] kms = kmf.getKeyManagers();
        
        // Assuming that you imported the CA Cert "Subject: CN=MBIIS CA, OU=MBIIS, O=DAIMLER, C=DE"
        // to your cacerts Store.
        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();
    
        final SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kms,tms,new SecureRandom());
        SSLContext.setDefault(sslContext);
    
        HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;   
        System.setProperty("https.proxyHost", "IP_OF_PROXY_HOST_GOES_HERE");
        System.setProperty("https.proxyPort", "PORT_NUMBER_GOES_HERE");
        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
    
        URL url = new URL("https://server-link");
    
        HttpsURLConnection con =    (HttpsURLConnection)url.openConnection();           
        con.setRequestMethod("POST");
        con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko");
        con.setConnectTimeout(10000);
        con.setSSLSocketFactory(sslContext.getSocketFactory()); 
        con.connect();
    
        BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line+"\n");
        }
        br.close();
        System.out.println(sb.toString());
        //int s= con.getResponseCode();
    }
    
    }
    

    【讨论】:

    • “无法找到到请求目标的有效证书路径”表示根/子 CA 不受信任。在您的情况下,您不信任为目标“CN=*.dvb.corpinter.net”颁发服务器证书的根 (MBIIS CA) ...
    • 更新日志到您的问题,我无法访问您的 C: Drive 上的链接 :)
    • 只添加错误部分......我会发起聊天,但我的声誉还不够
    • 如果“CN=MBIIS CA, OU=MBIIS, O=DAIMLER, C=CN”是“CN=MBIIS CA, OU=MBIIS, O=DAIMLER, C= DE”,那么您的客户端密钥库需要交付整个链...当您从 Internet Explorer 导出 pfx 时,如果我没记错的话,您可以包含该链,请查看 digicert.com/images/code-signing/export/…
    • 我使用了我在邮件中收到的实际 .pfx 证书在我们的程序中从客户端存储创建密钥管理器。它只有1个证书。然后从浏览器我只能使用前 3 个选项导出.. 即 .pfx 导出被禁用。 :(。我们如何知道证书是否是另一个的子 CA,然后如何添加然后一起交付。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多