我试图从Java应用程序向precision.epayworldwide.com
发送HTTPS请求。
这是我使用的代码:
URL url = new URL("https://precision.epayworldwide.com/up-interface");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String responseLine = reader.readLine();
while (responseLine != null)
{
System.out.printf("%s\n", responseLine);
responseLine = reader.readLine();
}
这是我得到的例外:
Exception in thread "main" org.bouncycastle.tls.TlsFatalAlert: certificate_unknown(46)
at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.checkServerTrusted(Unknown Source)
at org.bouncycastle.jsse.provider.ProvTlsClient$1.notifyServerCertificate(Unknown Source)
at org.bouncycastle.tls.TlsUtils.processServerCertificate(Unknown Source)
at org.bouncycastle.tls.TlsClientProtocol.handleServerCertificate(Unknown Source)
at org.bouncycastle.tls.TlsClientProtocol.handleHandshakeMessage(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.processHandshakeQueue(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.processRecord(Unknown Source)
at org.bouncycastle.tls.RecordStream.readRecord(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.safeReadRecord(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.blockForHandshake(Unknown Source)
at org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:523)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1296)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at Main.main(Main.java:17)
Caused by: java.security.cert.CertificateException: No subject alternative name found matching IP address 195.145.98.203
at org.bouncycastle.jsse.provider.HostnameUtil.checkHostname(Unknown Source)
at org.bouncycastle.jsse.provider.ProvX509TrustManager.checkEndpointID(Unknown Source)
at org.bouncycastle.jsse.provider.ProvX509TrustManager.checkEndpointID(Unknown Source)
at org.bouncycastle.jsse.provider.ProvX509TrustManager.checkExtendedTrust(Unknown Source)
at org.bouncycastle.jsse.provider.ProvX509TrustManager.checkTrusted(Unknown Source)
at org.bouncycastle.jsse.provider.ProvX509TrustManager.checkServerTrusted(Unknown Source)
... 18 more
我已正确导入该主机名的TLS证书:
Owner: C=GB,L=Billericay,O=Epay Limited,CN=*.epayworldwide.com
Issuer: C=US,O=DigiCert Inc,CN=DigiCert TLS RSA SHA256 2020 CA1
Serial number: 97cc7ab5601ca15b1e65530f3a3e8a3
Valid from: Mon Oct 10 02:00:00 CEST 2022 until: Sun Nov 05 00:59:59 CET 2023
Certificate fingerprints:
MD5: AF:C4:FA:F6:A2:99:D8:C3:C3:9A:1D:B7:A4:6D:D7:21
SHA1: 4D:55:B9:2B:69:67:2E:AA:2A:B4:3B:B6:D1:BC:35:77:B0:FD:50:A0
SHA256: 96:AF:91:70:80:F6:F1:9E:30:18:CC:97:53:10:B4:7E:B2:CC:37:31:77:CB:C1:E1:1C:14:BC:CF:19:08:04:3B
Signature algorithm name: SHA256WITHRSA
Version: 3
Trust this certificate? [no]: yes
Certificate was added to keystore
我不明白为什么代码会抛出这个异常。我在StackOverflow上搜索过,发现了类似的问题(1,2,3),但这些人使用IP地址连接到服务器,而不是FQDN。
我不控制服务器,所以我不能以任何方式更改证书。
有没有什么我可以做的客户端,而不禁用主机名验证?
3条答案
按热度按时间vjhs03f71#
基于this bug report HttpURLConnection将只使用SNI与SunJSSE作为JSSE提供程序,但不使用其他如BouncyCastle -您正在使用的。这就是为什么它会尝试根据IP地址而不是FQDN检查证书的原因:
原因:java.security.cert.CertificateException:未找到与IP地址匹配的主题替代名称195.145.98.203
ryoqjall2#
这是HttpURLConnection在第三方JSSE实现中不能正常工作的一个潜在问题。
由于您直接打开URL(而不是通过一些难以修改的框架),最简单的解决方案可能是使用BCJSSE实用程序类
org.bouncycastle.jsse.util.URLConnectionUtil
:如果BCJSSE未配置为默认提供程序,则还可以将特定的SSLSocketFactory传递给URLConnectionUtil构造函数。
有关基本问题的背景信息,请参阅各种问题:
2nbm6dog3#
由于我不想更改代码,我在BouncyCastle的Githb问题跟踪器中挖掘了一下,发现了这个JVM属性:
从v1.70开始,如果您想使用选项1,请首选**
-Dorg.bouncycastle.jsse.client.assumeOriginalHostName=true
**,而不是-Djdk.tls.trustNameService=true
(see issue 460和链接问题以获取更多参考)
因此,我将此属性添加到JVM参数列表中,现在
precision.epayworldwide.com
的TLS握手工作正常。