2017-08-11 4 views
1

Je dois me connecter à un site Web à l'aide d'une carte à puce. Je peux obtenir avec succès le keystore de la carte à puce, contenant le certificat de l'utilisateur et une clé privée non exportable (c'est un objet PrivateKey classique, mais la méthode "getEncoded" renvoie null).Authentification du certificat client en Java

Ce site: https://pst.giustizia.it/PST/authentication/it/pst_ar.wp a un lien de connexion qui change chaque fois que vous visitez. Donc, comme le ferait un utilisateur, je fais de même dans mon application Java: je consulte la page une fois pour obtenir ce lien, puis j'effectue l'authentification SSL sur ce lien (Un peu comme simuler la visite de la page et cliquer sur ce lien) .

C'est le code que j'utilise:

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(); 
    } 
} 

J'ai besoin que d'authentifier la première fois, car une fois connecté, les contrôles du site qu'un cookie nommé « JSESSIONID » et la chaîne de l'agent utilisateur du client. J'ai déjà testé ça. Une fois que vous avez ces deux paramètres valides, vous pouvez visiter la page même à partir d'un autre navigateur. Quoi qu'il en soit, la méthode "loadKeyStorePKCS11" vous donne le keystore mentionné ci-dessus, qui contient la chaîne de certification (99%, peut-être 100% sont un seul certificat, car j'ai essayé 26 cartes à puce différentes et un seul certificat: celui de l'utilisateur), et une clé privée non exportable. J'ai essayé de trouver des solutions sur Internet, mais elles concernent toutes le PKCS # 12, dont je n'ai pas besoin.

J'ai essayé d'utiliser différents protocoles (SSL et TLS) et différentes versions, mais rien!

Firefox peut faire l'authentification par carte à puce, et je sais qu'il me manque quelque chose dans la procédure! Lorsque j'appelle la méthode "execute" sur l'objet "httpClient", cela me donne une exception: "handshake_failure" (SSLHandshakeException).

Si j'utilise "loadKeyMaterial" au lieu de "loadTrustMaterial", j'obtiens "unsupported_certificate".

Je ne sais pas vraiment ce que je dois faire à ce stade! Avez-vous un conseil? Merci d'avance!

+1

pour voir la raison de l'échec, ajoutez '-Djavax.net.debug = ssl: handshake' à votre machine virtuelle Java. Ma conjecture est une autorité de certification racine non fiable ou une incompatibilité de chiffrement. –

+0

[ICI] (https://www.dropbox.com/s/94m10zrfhpy4zmb/ConsoleMessage.txt?dl=0) vous pouvez trouver l'intégralité du journal de la console. Les 80 premières lignes sont des messages de débogage du pilote de la carte à puce. Le reste provient du débogage de la poignée de main. Merci d'avance! – FonzTech

+0

Désolé, la boîte de dépôt est bloquée par mon serveur proxy. –

Répondre

1

Merci d'avoir posté le journal, je vais faire une réponse car c'est trop pour un commentaire. Réponse courte: le serveur demande un certificat client et vous n'en possédez pas ou n'êtes pas configuré pour en fournir un qui soit acceptable.

Rechercher dans votre journal pour cela:

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

Ce serveur vous demande un certificat client. Ce qui suit est une liste d'AC acceptables. Vous devez avoir un certificat dans votre fichier de clés émis par l'une de ces autorités de certification et les certificats clients doivent être activés pour la session côté client.

La partie suivante du journal dit alors ceci:

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

Malheureusement, il semble que vous ne disposez pas d'un certificat acceptable pour le serveur, ou ne sont pas configurés pour le mode de certificat client et c'est pourquoi il vous coupe éteint et annule la poignée de main.

+0

Salut! Merci pour votre réponse. [ICI] (http://i.imgur.com/NXyhh68.jpg) vous pouvez trouver mon certificat. Il a été émis par une autorité de certification répertoriée dans les autorités de certification acceptables. Donc, je pense que le problème est autre chose ... Avez-vous des conseils? – FonzTech

+0

J'ai changé "loadTrustMaterial" en "loadKeyMaterial", et maintenant je reçois "unsupported_certificate" juste après "*** CertificateVerify". Qu'est-ce que ça veut dire? Merci d'avance! – FonzTech

+0

Exportez votre certificat de votre fichier de clés dans un fichier, puis utilisez openssl pour le vérifier: 'openssl x509 -in -inform der -text -noout'. Vérifiez les algorithmes de signature et de clé publique. Votre fichier journal indique que les types de certificats pris en charge sont "RSA" et "DSS". –