Lorsqu’un traitement Java fait appel à un site internet sécurisé avec le protocole HTTPS, la JVM vérifie si le certificat SSL est validé par un organisme tiers. Pour cela, il existe dans la JRE une librairie avec des certificats de confiance : $JAVA_HOME/jre/lib/security/cacerts. Voici une erreur possible lors d’un échange entre un client et un serveur SSL :
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Lorsque cette erreur arrive, cela veut dire que le certificat délivré par le serveur n’est pas vérifié par une autorité tierce reconnue par la JVM. Pour résoudre ce problème, il y a deux solutions :
- Annuler la vérification du certificat
- Ajouter le certificat à la liste des certificats reconnus de la JVM
Annuler la vérification des certificats
Je vous propose d’annuler la vérification de façon programmatique. Pour cela, il faut créer un “TrustManager” qui ne va rien vérifier puis l’utiliser dans le contexte de session SSL.
// Créer un "trust manager" qui ne valide pas les certificats
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// Utiliser le manager qui ne valide pas les certificat
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
}
// Accéder à la page en HTTPS
try {
URL url = new URL("https://hostname/index.html");
} catch (MalformedURLException e) {
}
Je rappelle qu’en supprimant l’étape de vérification, le client devient sensible aux attaques du type man-in-the-middle. Je déconseille donc cette solution dans le cas général.
Ajouter le nouveau certificat à la JVM
Pour ajouter le certificat dans la JVM, il faut l’exporter depuis votre navigateur. Par exemple, avec Firefox, il faut se rendre dans la fenêtre des options puis dans le menu Avancé -> Chiffrement cliquer sur le bouton Afficher les certificats. Dans la fenêtre suivante, il est possible d’exporter un certificat.
Enfin pour importer le certificat dans la JVM il faut exécuter cette commande :
keytool -keystore $JAVA_HOME/jre/lib/security/cacerts -file certificat.crt -alias certificat
Le mot de passe par défaut est “changeit”.
Astuce
Pour débugger une conversation SSL, il faut ajouter l’option JVM suivante : -Djavax.net.debug=all