如何通过 HttpsURLConnection 使用证书身份验证? [英] How can I use certificate authentication with HttpsURLConnection?

查看:81
本文介绍了如何通过 HttpsURLConnection 使用证书身份验证?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试连接到 HTTPS URL,但我需要使用客户端身份验证和第三方软件放置在我系统上的证书.

I'm trying to connect to an HTTPS URL, but I need to use client authentication with a certificate placed on my system by third party software.

我一点也不知道我应该如何找到或使用它,我所要做的就是 C# 示例代码,这与我找到的所有 Java 答案有很大不同.(例如,KeyStore 显然需要某种密码?)

I haven't the slightest idea how I'm supposed to either find or use it and all I have to go on is C# sample code, which differs significantly with all the Java answers I've found about this. (for instance, the KeyStore needs some sort of password apparently?)

这是我的 C# 示例代码

This is the C# sample code I have

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 并一路检查它们.再进一步,它会像这样设置证书:

And then it just iterates over the WS2_store_Certs CertificateCollection and checks them all that way. A bit further on, it sets the certificates like this:

HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url_string);
httpWebRequest.ClientCertificates = SSC_Certs;

这一切看起来都相当合乎逻辑,即使我不知道它是如何找到证书的,但我仍然无法找到与此等效的 Java.

This all looks fairly logical, even if I have no idea how it finds the certificates, but I still haven't been able to find the Java equivalent of this.

更新

我建立的连接是依赖于 JDK 5 的更大应用程序的一部分,但我设法仅使用 sunmscapi jar 来查找我正在寻找的证书.但是,当我尝试使用 Windows 密钥库进行连接时会出错,所以我认为我通过从 Windows 存储库获取我需要的证书并将其插入到默认的 java 中来解决这个问题.现在我收到一个 EOFException,然后是一个 SSLHandshakeException,说握手期间远程主机关闭了连接".ssl 调试跟踪并没有立即向我揭示问题,因为我需要的证书显示在此处的证书链中.

The connection I'm making is part of a larger application that depends on JDK 5, but I've managed to just use the sunmscapi jar to find the certificate I'm looking for. It errors when I try to connect using the windows keystore though, so I thought I got around the problem by getting the certificate I need from the windows store and inserting it in the default java one. Now I'm getting an EOFException followed by an SSLHandshakeException saying "Remote host closed connection during handshake". The ssl debug trace doesn't reveal an immediate problem to me, since the certificate I need is displayed in the certificate chain here.

它完成了整个 ClientKeyExchange 的事情,说它已经完成,然后我从调试日志中得到的最后一条消息是

It does the whole ClientKeyExchange thing, says it's finished and then the last messages I get from the debug log right after that are

[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

我用来建立连接的代码是

and the code I'm using to set up the connection is

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,因为我不知道如何找到证书文件,我也不确定这是否在每个客户端系统上都是一样的.)

(I haven't tried HttpClient yet because I have no idea how to find the certificate file and I'm also not sure if this will always be the same on every client system.)

另一个更新

我已经在 WINDOWS-ROOT 密钥库中找到了我需要的证书的 CA(并使用 .verify() 检查以查看它们是否全部签出),我也将它们添加到了 java 密钥库中,但仍然没有什么变化.我猜他们应该进入 TrustStore,但我还没有找到一种以编程方式做到这一点的方法.(宁愿不依赖最终用户来做这种事情,因为我只能向他们保证,由于在这个荒谬的长问题开头提到的第三方软件,证书和 CA 将存在.)

I've found the CAs for the certificate I need in the WINDOWS-ROOT keystore (and checked with .verify() to see that they all check out), I've added them to the java keystore as well but still nothing changes. I guess they're supposed to go in the TrustStore, but I have yet to find a way to do that programatically. (Would prefer not to rely on end users to do this kind of thing, as all I can guarantee from them is that the certificate and CAs will be present due to the third party software mentioned at the start of this ridiculously long question.)

更多更新

加上之前的更新,我得出的结论是我的问题一定在于我的 CA 不在 Java 的 cacerts 文件中,所以它从服务器获取受信任的 CA 列表,但没有识别它们,随后不会发回导致连接失败的单个证书.所以问题仍然存在,我如何让 Java 要么使用它的密钥库作为信任库,要么以编程方式将证书添加到 cacerts(不需要文件路径)?因为如果这些都不可能,那么我只能选择秘密选项 C,voodoo.我会开始用针刺杜克娃娃,以防万一.

Adding on the previous update, I've come to the conclusion that my problem must lie in the fact that my CAs are not in Java's cacerts file, so it gets the list of trusted CAs from the server, but doesn't recognise them and subsequently doesn't send a single certificate back causing the connection failure. So the problem remains, how do I get Java to either use it's keystore as truststore or add certificates to cacerts programmatically (without the need for file paths)? Because if those aren't possible that just leaves me with secret option C, voodoo. I'll start stabbing a Duke doll with needles, just in case.

推荐答案

原来是私钥问题,因为它被设置为不可导出.由于这意味着我只能从 Windows 商店中获取私钥,因此我解决并修复"了这个问题,并进行了大量的处理,以使必要的 jdk6 类正常工作,而不会对应用程序的其余部分产生太大影响.

Turned out to be a Private Key issue since it was set as not exportable. As this meant I could only get the private key from the windows store, I caved and "Fixed" the issue with a lot of messing around to get the necessary jdk6 classes working without influencing the rest of the application too much.

这篇关于如何通过 HttpsURLConnection 使用证书身份验证?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆