【问题标题】:Curl cacert equivalent in Java HttpClientJava HttpClient 中的 Curl cacert 等效项
【发布时间】:2018-03-18 14:36:07
【问题描述】:

我可以毫无问题地执行以下 curl 命令:

curl -s --cacert cert_ca.pem -X POST --data-urlencode name=abcde https://abcd.com/resource

你能帮我想出一些关于 Java 的东西来实现同样的目标吗?我看过类似的帖子,但他们谈论的是完整的 SSL 握手。在这里,我只是提供 CA 证书以使用指定的证书文件来验证对等方。

另一个问题,我的理解是否正确 --> 在这里,我只需要使用 CA 证书配置信任库来验证对等方,而不一定是任何密钥库,因为我没有代表我提供任何证书?

谢谢

我也有 CA 证书的 jks 文件

在使用以下代码尝试罗伯特的建议时:

    SSLContext sslContext = SSLContexts.custom()                          
         .loadTrustMaterial(new File("test_ca.jks")
         .build();
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
    httpClient = HttpClients.custom()
         .setSSLSocketFactory(sslsf)
         .build();
    String openEndpoint = "URL";
    HttpPost httpPost = new HttpPost(openEndpoint);
    httpPost.setEntity(new UrlEncodedFormEntity(reqBodyParams)); 
    CloseableHttpResponse httpResponse = ( CloseableHttpResponse ) httpClient.execute(httpPost);

我收到以下异常:

    javax.net.ssl.SSLException: Received fatal alert: unexpected_message
at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2023)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1125)
at sun.security.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1769)
at sun.security.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:124)
at sun.security.ssl.Handshaker.sendChangeCipherSpec(Handshaker.java:1130)
at sun.security.ssl.ClientHandshaker.sendChangeCipherAndFinish(ClientHandshaker.java:1216)
at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:1128)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:348)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:961)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:396)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:355)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:359)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:381)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)

【问题讨论】:

    标签: java ssl curl apache-httpclient-4.x truststore


    【解决方案1】:

    您可以在构建 Apache Commons Http SSLContext 时指定一个 Java 密钥库文件作为“信任材料”(信任库):

        SSLContext sslContext = SSLContexts.custom()
                .loadTrustMaterial(new File("keystore.jks"), "trust-password".toCharArray()) // trust
                .build();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
    

    【讨论】:

    • 我收到javax.net.ssl.SSLException: Received fatal alert: unexpected_message at sun.security.ssl.Alerts.getSSLException(Alerts.java:208) 我在加载信任材料时没有指定密码,这是唯一的区别。不知道这里有什么错误
    • 不要将代码放入 cmets - 它完全不可读。改为编辑您的问题。 SO 不是论坛!
    • 抱歉,我已经用我的更改和我看到的结果更新了这个问题。这个例外并不冗长,也没有给我任何有用的信息。正如您在我的 curl 命令中看到的那样,我只需指定 CA 证书并拨打电话即可。我也应该能够使用 java 实现相同的目标。如果我在这里有任何误解,请告诉我
    • @user3688037:您的代码可以正常工作。如果它不起作用,那就是服务器问题(例如错误的 url)。
    • 我上面没有添加的那一行有问题。在构建 URLEncodedEntity 时,我添加了导致 400 错误请求的 base64 编码键值对。你的建议是正确的。欣赏它。谢谢
    最近更新 更多