Utilisation d'un truststore personnalisé en java ainsi que celui par défaut


J'écris une application en Java qui se connecte à deux serveurs Web via HTTPS. L'un a obtenu un certificat approuvé via la chaîne de confiance par défaut, l'autre utilise un certificat auto-signé. Bien sûr, la connexion au premier serveur a fonctionné immédiatement, alors que la connexion au serveur avec le certificat auto-signé n'a pas fonctionné jusqu'à ce que j'ai créé un trustStore avec le certificat de ce serveur. Cependant, la connexion au serveur de confiance par défaut ne fonctionne plus, car apparemment, le magasin de confiance par défaut doit être ignoré une fois que j'ai créé le mien.

Une solution que j'ai trouvée était d'ajouter les certificats du trustStore par défaut au mien. Cependant, je n'aime pas cette solution, car elle m'oblige à continuer à gérer ce magasin de confiance. (Je ne peux pas supposer que ces certificats restent statiques dans un avenir prévisible, non?)

En dehors de cela, j'ai trouvé deux threads de 5 ans avec un problème similaire:

Enregistrement de plusieurs keystores dans JVM

Comment puis-je avoir plusieurs certificats SSL sur un serveur Java

Ils vont tous deux profondément dans l'infrastructure SSL Java. J'espérais qu'il existe maintenant une solution plus pratique que je peux expliquer facilement dans un examen de sécurité de mon code.

Author: Community, 2014-07-03

1 answers

Vous pouvez utiliser un modèle similaire à ce que j'ai mentionné dans une réponse précédente (pour un problème différent).

Essentiellement, mettez la main sur le gestionnaire de confiance par défaut, créez un deuxième gestionnaire de confiance qui utilise votre propre magasin de confiance. Enveloppez-les tous les deux dans une implémentation de gestionnaire de confiance personnalisée que les délégués appellent aux deux (retombant sur l'autre en cas d'échec).

TrustManagerFactory tmf = TrustManagerFactory
    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
// Using null here initialises the TMF with the default trust store.
tmf.init((KeyStore) null);

// Get hold of the default trust manager
X509TrustManager defaultTm = null;
for (TrustManager tm : tmf.getTrustManagers()) {
    if (tm instanceof X509TrustManager) {
        defaultTm = (X509TrustManager) tm;
        break;
    }
}

FileInputStream myKeys = new FileInputStream("truststore.jks");

// Do the same with your trust store this time
// Adapt how you load the keystore to your needs
KeyStore myTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
myTrustStore.load(myKeys, "password".toCharArray());

myKeys.close();

tmf = TrustManagerFactory
    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(myTrustStore);

// Get hold of the default trust manager
X509TrustManager myTm = null;
for (TrustManager tm : tmf.getTrustManagers()) {
    if (tm instanceof X509TrustManager) {
        myTm = (X509TrustManager) tm;
        break;
    }
}

// Wrap it in your own class.
final X509TrustManager finalDefaultTm = defaultTm;
final X509TrustManager finalMyTm = myTm;
X509TrustManager customTm = new X509TrustManager() {
    @Override
    public X509Certificate[] getAcceptedIssuers() {
        // If you're planning to use client-cert auth,
        // merge results from "defaultTm" and "myTm".
        return finalDefaultTm.getAcceptedIssuers();
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain,
            String authType) throws CertificateException {
        try {
            finalMyTm.checkServerTrusted(chain, authType);
        } catch (CertificateException e) {
            // This will throw another CertificateException if this fails too.
            finalDefaultTm.checkServerTrusted(chain, authType);
        }
    }

    @Override
    public void checkClientTrusted(X509Certificate[] chain,
            String authType) throws CertificateException {
        // If you're planning to use client-cert auth,
        // do the same as checking the server.
        finalDefaultTm.checkClientTrusted(chain, authType);
    }
};


SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { customTm }, null);

// You don't have to set this as the default context,
// it depends on the library you're using.
SSLContext.setDefault(sslContext);

Vous n'avez pas besoin de définir ce contexte comme contexte par défaut. La façon dont vous l'utilisez dépend de la bibliothèque cliente vous utilisez (et d'où il tire ses usines de socket).


Ceci étant dit, en principe, vous devrez toujours mettre à jour le truststore comme requis de toute façon. Le Guide de référence Java 7 JSSE avait une" note importante " à ce sujet, maintenant rétrogradé à juste une "note" dans la version 8 du même guide :

Le JDK est livré avec un nombre limité de certificats racine de confiance dans le fichier java-home/lib/security / cacerts. Comme documenté dans keytool les pages de référence, il est votre responsabilité de maintenir (c'est-à-dire ajouter et supprimer) les certificats contenus dans ce fichier si vous utilisez cette fichier en tant que truststore.

En fonction de la configuration du certificat des serveurs que vous contact, vous devrez peut-être ajouter des certificats racine supplémentaires. Obtenir le besoin de certificats racine spécifiques du fournisseur approprié.

 45
Author: Bruno, 2017-05-23 12:18:17