我在使用bouncycastle库开发http客户机时遇到了一个问题。目标版本(但在Java1.8.0\u91中,使用相同版本的bouncycastle时,错误也可以重现。)
jre 1.6.0\ U 45-b06
bouncycastle jdk15to18 167(bcprov-jdk15to18-167.jar、bcpkix-jdk15to18-167.jar、bctls-jdk15to18-167.jar)
httpclient代码:
String strURL = "https://www.<WEBSITE>.com";
// CODE to set default TrustStore, KeyStore to be used
// setup BC as SecurityProvider and SSLSocketFactoryProvider
/*
Security.insertProviderAt(new BouncyCastleProvider(), 1);
Security.insertProviderAt(new BouncyCastleJsseProvider(), 2);
Security.setProperty("ssl.KeyManagerFactory.algorithm", "PKIX");
Security.setProperty("ssl.TrustManagerFactory.algorithm", "PKIX");
Security.setProperty("ssl.SocketFactory.provider", "org.bouncycastle.jsse.provider.SSLSocketFactoryImpl");
System.setProperty("jdk.tls.trustNameService", "true");
* /
URL url = new URL( strURL );
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("GET");
InputStream is = null;
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
System.out.println("OK");
is = conn.getInputStream();
} else if (conn.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR) {
System.out.println("ERROR");
is = conn.getErrorStream();
} else {
System.out.println( conn.getResponseCode() );
System.out.println( conn.getResponseMessage() );
}
if (is != null) {
System.out.println( readFullyAsString(is, "UTF-8") );
}
conn.disconnect();
使用tls1.2在没有客户端身份验证的情况下访问网站上的数据可以正常工作(对于返回握手失败(40)的特定网站存在一些问题,但幸运的是在我们的情况下不是这样)。但是当需要client_auth时,代码会失败,并出现以下错误(有点神秘):
nov. 27, 2020 5:23:10 PM org.bouncycastle.jsse.provider.ProvTlsClient notifyAlertRaised
WARNING: Client raised fatal(2) internal_error(80) alert: Failed to read record
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at org.bouncycastle.tls.RecordStream$Record.fillTo(RecordStream.java:429)
at org.bouncycastle.tls.RecordStream$Record.readHeader(RecordStream.java:468)
at org.bouncycastle.tls.RecordStream.readRecord(RecordStream.java:201)
at org.bouncycastle.tls.TlsProtocol.safeReadRecord(TlsProtocol.java:768)
at org.bouncycastle.tls.TlsProtocol.readApplicationData(TlsProtocol.java:731)
at org.bouncycastle.jsse.provider.ProvSSLSocketDirect$AppDataInput.read(ProvSSLSocketDirect.java:603)
at java.io.BufferedInputStream.fill(Unknown Source)
at java.io.BufferedInputStream.read1(Unknown Source)
at java.io.BufferedInputStream.read(Unknown Source)
at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at java.net.HttpURLConnection.getResponseCode(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
at HttpsClient.main(HttpsClient.java:109)
nov. 27, 2020 5:23:10 PM org.bouncycastle.jsse.provider.ProvTlsClient notifyAlertRaised
WARNING: Client raised fatal(2) internal_error(80) alert: Failed to read record
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at org.bouncycastle.tls.RecordStream$Record.fillTo(RecordStream.java:429)
at org.bouncycastle.tls.RecordStream$Record.readHeader(RecordStream.java:468)
at org.bouncycastle.tls.RecordStream.readRecord(RecordStream.java:201)
at org.bouncycastle.tls.TlsProtocol.safeReadRecord(TlsProtocol.java:768)
at org.bouncycastle.tls.TlsProtocol.readApplicationData(TlsProtocol.java:731)
at org.bouncycastle.jsse.provider.ProvSSLSocketDirect$AppDataInput.read(ProvSSLSocketDirect.java:603)
at java.io.BufferedInputStream.fill(Unknown Source)
at java.io.BufferedInputStream.read1(Unknown Source)
at java.io.BufferedInputStream.read(Unknown Source)
at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at java.net.HttpURLConnection.getResponseCode(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
at HttpsClient.main(HttpsClient.java:109)
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at org.bouncycastle.tls.RecordStream$Record.fillTo(RecordStream.java:429)
at org.bouncycastle.tls.RecordStream$Record.readHeader(RecordStream.java:468)
at org.bouncycastle.tls.RecordStream.readRecord(RecordStream.java:201)
at org.bouncycastle.tls.TlsProtocol.safeReadRecord(TlsProtocol.java:768)
at org.bouncycastle.tls.TlsProtocol.readApplicationData(TlsProtocol.java:731)
at org.bouncycastle.jsse.provider.ProvSSLSocketDirect$AppDataInput.read(ProvSSLSocketDirect.java:603)
at java.io.BufferedInputStream.fill(Unknown Source)
at java.io.BufferedInputStream.read1(Unknown Source)
at java.io.BufferedInputStream.read(Unknown Source)
at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at java.net.HttpURLConnection.getResponseCode(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
at HttpsClient.main(HttpsClient.java:109)
正如所料,代码在Java1.8中运行良好,没有bc作为安全提供者。。。但是在Java1.6中,TLS1.2支持需要bc。
我用wireshark查看了数据包,但是我没有足够的知识来分析服务器的ssl握手操作发生了什么(失败)。
我错过了什么?或者这只是已知的bc限制?谢谢你的建议。
1条答案
按热度按时间trnvg8h31#
经过广泛的研究和测试(我们建立了自己的开发环境来复制端点,我们试图用客户端证书连接到),我们找到了一个解决方案(发布在下面),它在我们的开发环境中对我们有效,但无法在端点上配置。这就是为什么我们去计划b-tls终止代理,在我们的情况下,它就像一个魅力,当我们没有控制服务器环境。
iis解决方案
在我们的例子中,需要客户端身份验证的web服务是在microsoft iis上运行的。如前所述,“不幸的是,我们的tls库不支持重新协商(我们也不打算添加它,尽管我们将添加相应的tls 1.3特性)。”(https://github.com/bcgit/bc-java/issues/593). 在阅读了iis文档和一些测试之后,我们成功地以一种可以使用bc tls lib建立tls会话的方式配置了环境:
第一步:
使用默认设置创建iis站点
使用“最佳实践”模板运行iiscrypto:
第二步:
启用sslalwaysnegoclientcert
将以下文本保存到名为“enable\u ssl\u renegotiate.js”的文件中
从提升的/administrator命令提示符运行以下命令:
我在bouncycastle github上发布了相同的答案-#847