【问题标题】:Getting SSLHandshakeException while testing SOAP web service测试 SOAP Web 服务时出现 SSLHandshakeException
【发布时间】:2014-03-27 11:49:22
【问题描述】:

我正在尝试使用 apache http client 连接 SOAP Web 服务。它是安全的(由 https 标识)。我还为 keystore 文件添加了代码。 代码如下:

CloseableHttpClient httpclient = null;
try {
    KeyStore trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());
    FileInputStream instream = new FileInputStream(new File("C:\\SOAP\\qa.keystore"));
    try {
        trustStore.load(instream, "test1234".toCharArray());
    } 
    catch(Exception e){
        e.printStackTrace();
    }
    finally {
        instream.close();
    }

    SSLContext sslcontext = SSLContexts.custom()
            .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
            .build();

     httpclient = HttpClients.custom()
            .setSslcontext(sslcontext)
            .build();

    HttpPost httppost = new HttpPost("https://dev env hostname:7443/wsx/services/reiveFile_WS_VT_SECURED_INBOUND");
    FileBody bin = new FileBody(new File("C:\\Payment Check8jan3.dat"));
    StringBody fileName = new StringBody("Payment Check8jan3.dat", ContentType.TEXT_PLAIN);
    StringBody fileType = new StringBody("111", ContentType.TEXT_PLAIN);
    StringBody messageId = new StringBody("3454", ContentType.TEXT_PLAIN);
    StringBody senderId = new StringBody("ekrjekrj", ContentType.TEXT_PLAIN);
    StringBody checksum = new StringBody("b2ee8af554ab6933085d341b71765bc8", ContentType.TEXT_PLAIN);
    StringBody timestamp = new StringBody("3434", ContentType.TEXT_PLAIN);
    StringBody transportServiceVersion = new StringBody("4343", ContentType.TEXT_PLAIN);


    HttpEntity reqEntity = MultipartEntityBuilder.create()
            .addPart("FileName", fileName)
            .addPart("FileType", fileType)
            .addPart("messageId", messageId)
            .addPart("senderId", senderId)
            .addPart("checksum", checksum)
            .addPart("timestamp", timestamp)
            .addPart("transportServiceVersion", transportServiceVersion)
            .addPart("payload", bin)
            .build();

    httppost.setEntity(reqEntity);

    System.out.println("executing request " + httppost.getRequestLine());

    CloseableHttpResponse response = httpclient.execute(httppost);
    try {
        System.out.println("----------------------------------------");
        System.out.println(response.getStatusLine());
        HttpEntity resEntity = response.getEntity();
        if (resEntity != null) {
            System.out.println("Response content length: " + resEntity.getContentLength());
        }
        EntityUtils.consume(resEntity);
    } finally {
        response.close();
    }
} finally {
    httpclient.close();
}

我收到以下异常:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
    at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:275)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:254)
    at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:117)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:314)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
    at Test.test(Test.java:113)
    at Test.main(Test.java:229)
Caused by: java.io.EOFException: SSL peer shut down incorrectly
    at sun.security.ssl.InputRecord.read(Unknown Source)
    ... 18 more

编辑: 正如其中一个答案所建议的,我也将证书导入了 cacerts 文件。但仍然得到同样的例外。 请提出建议。

【问题讨论】:

  • 您是否尝试过运行命令行 openssl 来查看服务器呈现的内容? openssl s_client -debug -showcerts -connect "dev env hostname:7443"

标签: web-services ssl soap keystore apache-httpclient-4.x


【解决方案1】:

这只是一个猜测,但鉴于 SSL 握手在其初始阶段失败,我怀疑协议版本不兼容。尝试强制使用较旧的协议版本,例如 SSLv3 或 SSLv2,看看是否有什么不同。

SSLContext sslcontext = SSLContexts.custom()
    .loadTrustMaterial(trustStore)
    .build();
SSLConnectionSocketFactory sslcsf = new SSLConnectionSocketFactory(
    sslcontext, new String[] {"SSLv3"}, null, null);
CloseableHttpClient client = HttpClients.custom()
    .setSSLSocketFactory(sslcsf)
    .build();

一般来说,在处理任何类型的 SSL 问题时,SSL 初始握手的调试日志通常足以查明问题的原因。详情见this troubleshooting guide

【讨论】:

    【解决方案2】:

    尝试将证书导入cacerts 文件或创建一个新文件,并将其指向托管/使用 Web 服务的服务器。

    还要检查是否完整的证书链导入truststore。 同样可以通过编程方式或通过导入cacerts 来实现。 导入trusstore 的更好方法,如果导入正确,还要检查公钥和私钥。

    【讨论】:

    • 您能解释一下吗?或者让我提供我可以关注的任何链接
    • 您能否解释一下您的架构、使用的服务器、托管和使用的 Web 服务以及您的测试方式
    • 正如你所建议的,我也将证书导入“cacerts”文件,但仍然是同样的例外。我通过提供密钥库文件使用 Soap UI 测试了该服务,但通过 Java 调用不起作用。“正确检查,是否将完整的证书链导入到信任库中”是什么意思?如何检查?
    • 您可以在记事本中打开“cacerts”文件,您可以通过引用您在导入过程中提供的别名来查看证书。另外我建议你参考“Keytool”来获取所有相关的命令,它非常有用。还要检查提供给您的证书,必须是 p7b 格式、der 格式或 pk7 格式的密钥。可能需要转换为正确的格式才能导入 cacerts。此外,当您通过服务器运行时,服务器需要将其发送到另一台服务器以进行握手。
    • 另外,你读的越多,它就会越清楚,我在这个 SSL 上也有个人经验,即使你可以通过我在 SSL 上提出的问题,即使我很挣扎,但至少我确实成功了。看看我的问题,它可能会对你有更多帮助。
    猜你喜欢
    • 1970-01-01
    • 2019-06-23
    • 2019-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-04
    • 1970-01-01
    相关资源
    最近更新 更多