Bonjour,

Dans mon application j'ai des Web clients pour plusieurs Web Services qui utilisent tous des connections SSL (TLS).
Pour faciliter les mises à jour des certificats utilisés, j'ai fait en sorte que chaque Web Client utilise son propre keystore (cf. Code Partie A).
Ca marche très bien, dès qu'un changement de certificat arrive, je sais quoi modifier et où modifier dans mes keystores.

Par contre, si certains propriétaires de Web Services me préviennent à l'avance du changement de certificat, d'autres ne le font pas.
J'aimerais donc gérer automatiquement (comme nos browsers) le changement de certificat (sans attendre que mes utilisateurs se plaignent).
J'ai pu modifier mon programme pour récupérer les certificats utilisés par le serveur distant en court-circuitant le début de la négociation SSL (handshake ssl) et les ajouter dans le keystore en mémoire qui sera utilisé pour la fin de la négociation SSL (cf. Code Partie B).

Ca marche très bien, sauf que je me demande si c'est très sécure et si le fait d'ajouter les certificats dans le keystore ne court-circuite pas des vérifications de sécutité.
J'avoue que je ne trouve pas de réponse claire à cette question.

Est-ce que je dois faire moi même des check avant d'ajouter ces certificats ? (sur le nom de domaine, la validation de toute la chaine de certification)
Mais du coup comment faire pour ne pas ré-écrire un TrustManager complet ?
Y a t'il des lib pour faire cela ?

J'ai beau chercher, je ne trouve pas de solution....

Meci d'avance pour votre aide.

atom.top

La question subsidiaire qui m'intéresse :

Et vous, comment faites vous pour gérer les certificats dans vos programmes ?
Est-ce que vous mettez les certificats des serveurs dans des keystores à la main et gérez manuellement les mises à jour ?
Est-ce que vous avez une autre façon de faire plus automatique ?



Voici mon code pour initialiser ma socket SSL :

Partie A
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
			// KeyStore
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
			InputStream keyInput = new FileInputStream(keyStorePath);
			keyStore.load(keyInput, keyStorePass.toCharArray());
			keyInput.close();
 
            // CA-Chain
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
			trustManagerFactory.init(keyStore);
 
            // Client-Certificat
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
			keyManagerFactory.init(keyStore, keyStorePass.toCharArray());
 
            // SSL Context
            SSLContext context = SSLContext.getInstance(sslType);
            context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
 
            SSLSocketFactory socketFactory = context.getSocketFactory();
            requestContext.put(JAXWSProperties.SSL_SOCKET_FACTORY, socketFactory);
Partie B
J'implémente un TrustManager pour être appelé pendant la négociation pour pouvoir ajouter les certificats reçus dans le keystore, puis laisser le TrustManager par défaut faire la vérification.

Je remplace l'appel
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
 
            context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
par l'utilisation de mon MyTrustmanager
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
 
            context.init(keyManagerFactory.getKeyManagers(),
                         new X509TrustManager[]{new MyTrustManager(keyStorePath, keyStoreType, keyStorePass.toCharArray(), targetURL)}, null);
Et voici l'implémentation de mon TrustManager qui fini par appeler le TrustManager par défaut après avoir ajouté les certificats du serveur dans le keystore :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
 
 
public class MyTrustManager implements X509TrustManager {
 
    private KeyStore keyStore;
    private String alias;
    private String targetURL;
    private char[] password;
    TrustManagerFactory trustManagerFactory;
 
	// Constructeur à qui on passe les infos du keystore
    public MyTrustManager(String keyStoreFile, String keystoretype, char[] password, String alias, String targetURL)
            throws IOException, GeneralSecurityException {
        this.alias = alias;
        this.password = password;
		this.keyStore = KeyStore.getInstance(keystoretype);
        if (StringUtils.notEmpty(keyStoreFile)) {
            InputStream stream = new FileInputStream(keyStoreFile);
            if (stream!=null) {
                keyStore.load(stream, password);
            }
        }
        this.trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);
    }
 
	[...]
 
    @Override
	// Méthode utilisée au moment de la négociation SSL qui m'intéresse
    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
        for (X509Certificate x509Certificate :x509Certificates) {
            try {
				boolean isValid = true
                // C'est ici que j'aimerai faire mieux en ajoutant uniquement les certificats dont le domaine correspond à l'URL (par exemple)
                 if (isValid) {
                    i++;
                    keyStore.setCertificateEntry(x509Certificate.getSubjectDN()+"_"+i, x509Certificate);
                }
            }
            catch (KeyStoreException e) {
                e.printStackTrace();
                throw new CertificateException("Error loading certificat in the keystore of the CariKeyManager",e);
            }
        }
        try {
			// Ré-initialise le TrustManager avec le keystore qui a maintenant des certificats en plus
            trustManagerFactory.init(keyStore);
        }
        catch (KeyStoreException e) {
            e.printStackTrace();
        }
		// Puis on fini par faire l'appel au TrustManagers par défaut (comme c'était fait avant l'utilisation de cette classe MyTrustManager)
        for (TrustManager t :trustManagerFactory.getTrustManagers()) {
            if (t instanceof X509TrustManager) {
                ((X509TrustManager)t).checkServerTrusted(x509Certificates,s);
            }
        }
 
    }
 
 
	[...]
}