【发布时间】:2012-01-10 11:18:48
【问题描述】:
我正在尝试连接到 HTTPS URL,但我需要使用客户端身份验证和第三方软件放置在我系统上的证书。
我完全不知道我应该如何找到或使用它,我所要做的只是 C# 示例代码,它与我找到的所有 Java 答案都有很大不同。 (例如,KeyStore 显然需要某种密码?)
这是我的 C# 示例代码
System.Security.Cryptography.X509Certificates.X509CertificateCollection SSC_Certs =
new System.Security.Cryptography.X509Certificates.X509CertificateCollection();
Microsoft.Web.Services2.Security.X509.X509CertificateStore WS2_store =
Microsoft.Web.Services2.Security.X509.X509CertificateStore.CurrentUserStore(
Microsoft.Web.Services2.Security.X509.X509CertificateStore.MyStore);
WS2_store.OpenRead();
Microsoft.Web.Services2.Security.X509.X509CertificateCollection WS2_store_Certs = WS2_store.Certificates;
然后它只是遍历 WS2_store_Certs CertificateCollection 并一直检查它们。 再进一步,它会像这样设置证书:
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url_string);
httpWebRequest.ClientCertificates = SSC_Certs;
这一切看起来都很合乎逻辑,即使我不知道它是如何找到证书的,但我仍然无法找到与之对应的 Java。
更新
我正在建立的连接是依赖于 JDK 5 的更大应用程序的一部分,但我设法只使用 sunmscapi jar 来查找我正在寻找的证书。但是,当我尝试使用 Windows 密钥库进行连接时,它会出错,所以我认为我通过从 Windows 商店获取所需的证书并将其插入到默认的 java 中来解决了这个问题。现在我得到一个 EOFException ,然后是一个 SSLHandshakeException 说“握手期间远程主机关闭连接”。 ssl 调试跟踪不会立即向我显示问题,因为我需要的证书显示在此处的证书链中。
它做了整个 ClientKeyExchange 的事情,说它已经完成,然后我从调试日志中得到的最后一条消息是
[write] MD5 and SHA1 hashes: len = 16
0000: 14 00 00 0C D3 E1 E7 3D C2 37 2F 41 F9 38 26 CC .......=.7/A.8&.
Padded plaintext before ENCRYPTION: len = 32
0000: 14 00 00 0C D3 E1 E7 3D C2 37 2F 41 F9 38 26 CC .......=.7/A.8&.
0010: CB 10 05 A1 3D C3 13 1C EC 39 ED 93 79 9E 4D B0 ....=....9..y.M.
AWT-EventQueue-1, WRITE: TLSv1 Handshake, length = 32
[Raw write]: length = 37
0000: 16 03 01 00 20 06 B1 D8 8F 9B 70 92 F4 AD 0D 91 .... .....p.....
0010: 25 9C 7D 3E 65 C1 8C A7 F7 DA 09 C0 84 FF F4 4A %..>e..........J
0020: CE FD 4D 65 8D ..Me.
AWT-EventQueue-1, received EOFException: error
我用来建立连接的代码是
KeyStore jks = KeyStore.getInstance(KeyStore.getDefaultType());
jks.load(null, null);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
jks.setCertificateEntry("alias", cert1); //X509Certificate obtained from windows keystore
kmf.init(jks, new char[0]);
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(kmf.getKeyManagers(), new TrustManager[]{tm}, null);
sslsocketfactory = sslContext.getSocketFactory();
System.setProperty("https.proxyHost", proxyurl);
System.setProperty("https.proxyPort", proxyport);
Authenticator.setDefault(new MyAuthenticator("proxyID", "proxyPassword"));
URL url = new URL(null, urlStr, new sun.net.www.protocol.https.Handler());
HttpsURLConnection uc = (HttpsURLConnection) url.openConnection();
uc.setSSLSocketFactory(sslsocketfactory);
uc.setAllowUserInteraction(true);
uc.setRequestMethod("POST");
uc.connect();
(我还没有尝试过 HttpClient,因为我不知道如何找到证书文件,而且我也不确定这在每个客户端系统上是否总是相同的。)
另一个更新
我已经在 WINDOWS-ROOT 密钥库中找到了我需要的证书的 CA(并使用 .verify() 检查它们是否都已签出),我也已将它们添加到 java 密钥库中但仍然没有什么变化。我猜他们应该进入 TrustStore,但我还没有找到以编程方式执行此操作的方法。 (我宁愿不依赖最终用户来做这种事情,因为我可以向他们保证的是,由于这个可笑的长问题开头提到的第三方软件,证书和 CA 将存在。)
还有更多更新
加上之前的更新,我得出的结论是我的问题一定在于我的 CA 不在 Java 的 cacerts 文件中,因此它从服务器获取受信任的 CA 列表,但没有识别它们并随后不发回导致连接失败的单个证书。 所以问题仍然存在,如何让 Java 将其密钥库用作信任库或以编程方式将证书添加到 cacerts(无需文件路径)?因为如果这些都不可能,那只会给我留下秘密选项 C,voodoo。我会开始用针刺杜克娃娃,以防万一。
【问题讨论】:
-
您的目标是使用用户 Windows 密钥库中的证书吗?我认为在 Java 中没有这样做的方法,但是您可以使用 keytool 创建一个单独的密钥库。
标签: java https x509certificate authentication