使用给定的p12证书连接到https站点

Nam*_*ela 31 java https certificate

服务器端给了我一个.p12证书文件,我点击并安装在我的机器上然后我可以HTTPS通过浏览器访问该站点.现在他们希望我用给出的证书抓取他们的网站.我卡在它的第一个阶段,试图让inputStreamhttpsURLConnection.该网站没有登录.它只会检查您是否拥有证书.

到目前为止我所做的是使用Firefox以.crt文件格式导出证书.然后我使用keytool命令将它(.crt文件,而不是.p12)导入java密钥库.然后在代码中:

KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
File ksFile = new File(keystorePath);
in = new FileInputStream(ksFile);
ks.load(in, "changeit".toCharArray());
X509Certificate cert = (X509Certificate) ks.getCertificate(certificateAlias);

SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

HttpsURLConnection con = (HttpsURLConnection) (new URL(urlString)).openConnection();
con.connect();
con.getInputStream();
con.disconnect();
Run Code Online (Sandbox Code Playgroud)

getInputStream()将给我403错误禁止访问.我搜索了其他相关主题,实际上比阅读之前更加困惑.非常感谢答案.

额外细节:

  • 我只是实例化了证书,并且没有让程序知道任何类型的密钥(私有,公共等).所以我认为我必须将这些密钥提供给服务器,让它知道我实际上持有证书.我完全不知道如何做到这一点,无论是逻辑还是语法.
  • 我已经尝试过keytool命令将.p12证书文件导入密钥库但不知何故,keytool无法识别-pkcs12选项.关于如何直接使用这个.p12证书的任何想法都会很棒.
  • trustAllCert是TrustMangers的一个元素数组,它不验证任何东西(全部信任).我不知道我是否应该继续使用它.事实上,现在我实际上只有一个证书可以信任.在这种情况下编写trustManger的正确方法是什么?
  • 我无法控制服务器端.我所获得的只是访问其网站的URL,它是在HTTPS协议下的,以及.p12证书.该网站没有登录.如果安装了证书,我可以进去.

bob*_*z32 33

如果要尝试对SSL配置进行编码,可以使用提供给您的P12文件,而无需将其转换为JKS.此外,您需要使用P12中的私钥,而不仅仅是您复制到JKS中的证书.不确定这是否能直接满足您的需求,但这可能会让您走上正确的道路:

        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();
Run Code Online (Sandbox Code Playgroud)

以这种方式配置trustStore是可选的.您可以使用P12链中的所有证书创建一个JKS,或者只是确保它们在您的JRE的cacerts文件中.至于keytool,作为参考,您可以在P12上运行keytool命令(指定-storetype pkcs12),但不能将P12导入JKS.您也无法使用keytool命令仅从P12导出密钥.

我目前没有设置服务器来测试这段代码,所以试一试,看看你是否仍然收到403错误.


Aug*_*sto 5

添加这个作为答案,因为我需要更多的空间来写。

首先,一个问题:证书是由威瑞信等可信机构签署的吗?如果不是,则信任库应具有使 p12 证书“有效”的 CA 证书(通常是 .pem 文件)。默认的 Java 信任存储包含来自大公司(例如 Verisign 和 Thawte)的大部分(如果不是全部)CA 证书。

此外,您可以测试您的应用程序以连接到安全服务器,而无需对 SSL 配置进行编码,但使用一些命令行参数,例如:

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]
Run Code Online (Sandbox Code Playgroud)

然后你的代码就变成了

HttpsURLConnection con = (HttpsURLConnection) (new URL(urlString)).openConnection();
con.connect();
con.getInputStream();
con.disconnect();
Run Code Online (Sandbox Code Playgroud)

如果您感到受虐狂,JSSE 参考指南非常有趣。


Epi*_*rce 5

这对我有用:

   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();
    }
}
Run Code Online (Sandbox Code Playgroud)