2017-08-11 184 views
1

我需要使用智能卡登錄網站。我可以成功從智能卡獲取密鑰庫,其中包含用戶證書和不可導出私鑰(這是一個常規的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」。

我真的不知道我在這一點上必須做什麼! 你有什麼建議嗎? 在此先感謝!

+1

要查看失敗的原因,請將'-Djavax.net.debug = ssl:handshake'添加到您的JVM。我的猜測是不可信的根CA或密碼不匹配。 –

+0

[這裏](https://www.dropbox.com/s/94m10zrfhpy4zmb/ConsoleMessage.txt?dl=0)可以找到整個控制檯日誌。前80行是來自智能卡驅動程序的調試消息。其餘的來自握手調試。提前致謝! – FonzTech

+0

抱歉dropbox被我的代理服務器阻止。 –

回答

1

感謝發佈日誌,我會做出這個答案,因爲它太多了評論。

簡答:服務器要求客戶端證書,並且您沒有或沒有配置爲提供可接受的客戶端證書。

在日誌搜索這樣的:

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 

不幸的是,似乎不必接受的服務器證書,或者未配置爲客戶證書模式,這就是爲什麼它減少你關閉並中止握手。

+0

嗨!感謝您的回覆。 [這裏](http://i.imgur.com/NXyhh68.jpg)你可以找到我的證書。它由可接受的CA中列出的CA頒發。所以我認爲這個問題是另一回事......你有什麼建議嗎? – FonzTech

+0

我將「loadTrustMaterial」更改爲「loadKeyMaterial」,現在我在「*** CertificateVerify」之後立即收到「unsupported_certificate」。這是什麼意思?提前致謝! – FonzTech

+0

將您的證書從您的密鑰庫導出到文件,然後使用openssl檢查它:'openssl x509 -in -inform der -text -noout'。檢查簽名和公鑰算法。您的日誌文件指出支持的證書類型是「RSA」和「DSS」。 –