Java中的客户端证书身份验证

时间:2017-08-11 13:38:03

标签: java ssl smartcard pkcs#11

我需要使用智能卡登录网站。我可以从智能卡成功获取密钥库,其中包含用户证书和不可导出的私钥(它是常规的PrivateKey对象,但“getEncoded”方法返回null)。

此网站: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”。

我真的不知道此时我要做什么! 你有什么建议吗? 提前谢谢!

1 个答案:

答案 0 :(得分:1)

Thanks for posting the log, I'll make this an answer since it's too much for a comment.

Short answer: the server is asking for a client certificate and you don't have one or are not configured to provide one that's acceptable.

Search in your log for this:

main, READ: TLSv1 Handshake, length = 11296
*** CertificateRequest
Cert Types: RSA, DSS
Cert Authorities:

This is the server asking you for a client certificate. What follows is a list of acceptable CAs. You must have a certificate in your keystore issued by one of those CAs and client certificates must be enabled for the session on the client side.

The next part of the log then says this:

*** ServerHelloDone
Warning: no suitable certificate found - continuing without client 
authentication

Unfortunately it seems you don't have a certificate acceptable to the server, or are not configured for client certificate mode and that's why it cuts you off and aborts the handshake.