Java中的客户端证书认证
我需要使用智能卡登录网站。我可以成功从智能卡获取密钥库,其中包含用户证书和不可导出私钥(这是一个常规的PrivateKey对象,但“getEncoded”方法返回null)。Java中的客户端证书认证
此网站:https://pst.giustizia.it/PST/authentication/it/pst_ar.wp 有一个登录链接,这个链接更改您可以访问。所以,就像用户所做的那样,我在我的Java应用程序中也这样做:我访问该页面一次以获取该链接,然后在该链接上执行SSL身份验证(有点像模拟访问页面并单击该链接) 。
这是我使用的代码:
public class SSLAuth
{
private static String LOGIN_PAGE = "https://pst.giustizia.it/PST/authentication/it/pst_ar.wp";
private static String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0";
private TrustStrategy trustStrategy = new TrustStrategy()
{
public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
{
// Temporary work-around. I already know how to fix this
return true;
}
};
public String authenticate(String pin) throws Exception
{
// Request KeyStore from smart card
KeyStore keyStore = Utility.digitalSigner.loadKeyStorePKCS11();
SSLContext sslContext = SSLContexts.custom().useProtocol("TLSv1.2").loadTrustMaterial(keyStore, trustStrategy).build();
// Get login token first
String loginToken = null;
{
Document document = Jsoup.connect(LOGIN_PAGE).ignoreContentType(true).userAgent(USER_AGENT).timeout(10000).followRedirects(true).get();
Elements link = document.select("div > fieldset > p > a");
loginToken = link.get(0).attr("abs:href");
}
// Try to authenticate
HttpClient httpClient = HttpClients.custom().setUserAgent(USER_AGENT).setSSLContext(sslContext).build();
HttpResponse response = httpClient.execute(new HttpGet(loginToken));
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
return null;
return response.toString();
}
}
我只需要在第一时间进行身份验证,因为一旦登录,网站只检查一个名为“JSESSIONID” cookie和客户端的用户代理字符串。我已经测试过了。一旦你有了这两个有效的参数,你甚至可以从另一个浏览器访问该页面。无论如何,“loadKeyStorePKCS11”方法为您提供了上述密钥库,其中包含证书链(99%,也许100%只有一个证书,因为我试过26个不同的智能卡,而且他们只有一个证书:用户的)和一个不可导出的私钥。 我试图在互联网上寻找解决方案,但它们都是关于PKCS#12的,我不需要它。
我试过使用不同的协议(SSL和TLS)和它的不同版本,但没有任何!
Firefox可以做智能卡身份验证,我知道我在程序中丢失了一些东西!当我在“httpClient”对象上调用“execute”方法时,它给了我一个例外:“handshake_failure”(SSLHandshakeException)。
如果我使用“loadKeyMaterial”而不是“loadTrustMaterial”,则会得到“unsupported_certificate”。
我真的不知道我在这一点上必须做什么! 你有什么建议吗? 在此先感谢!
感谢发布日志,我会做出这个答案,因为它太多了评论。
简答:服务器要求客户端证书,并且您没有或没有配置为提供可接受的客户端证书。
在日志搜索这样的:
main, READ: TLSv1 Handshake, length = 11296
*** CertificateRequest
Cert Types: RSA, DSS
Cert Authorities:
这是服务器要求你的客户端证书。以下是可接受的CA列表。您必须在您的密钥库中有一个由其中一个CA颁发的证书,并且必须为客户端的会话启用客户端证书。
日志的下一部分则这样说:
*** ServerHelloDone
Warning: no suitable certificate found - continuing without client
authentication
不幸的是,似乎不必接受的服务器证书,或者未配置为客户证书模式,这就是为什么它减少你关闭并中止握手。
嗨!感谢您的回复。 [这里](http://i.imgur.com/NXyhh68.jpg)你可以找到我的证书。它由可接受的CA中列出的CA颁发。所以我认为这个问题是另一回事......你有什么建议吗? – FonzTech
我将“loadTrustMaterial”更改为“loadKeyMaterial”,现在我在“*** CertificateVerify”之后立即收到“unsupported_certificate”。这是什么意思?提前致谢! – FonzTech
将您的证书从您的密钥库导出到文件,然后使用openssl检查它:'openssl x509 -in
要查看失败的原因,请将'-Djavax.net.debug = ssl:handshake'添加到您的JVM。我的猜测是不可信的根CA或密码不匹配。 –
[这里](https://www.dropbox.com/s/94m10zrfhpy4zmb/ConsoleMessage.txt?dl=0)可以找到整个控制台日志。前80行是来自智能卡驱动程序的调试消息。其余的来自握手调试。提前致谢! – FonzTech
抱歉dropbox被我的代理服务器阻止。 –