7 votes

Netty SSL : comment écrire un TrustManager

J'ai lu beaucoup de choses pour configurer mon système client/serveur SSL (pas de HTTP).

Je me suis inspiré de l'exemple du chat sécurisé et l'exemple du serveur ssl websocket . J'ai déjà créé mon fichier cert.jks avec la commande

keytool -genkey -alias app-keysize 2048 -validity 36500
-keyalg RSA -dname "CN=app"
-keypass mysecret-storepass mysecret
-keystore cert.jks

Dans l'exemple du chat sécurisé, il y a cette classe :

public class SecureChatTrustManagerFactory extends TrustManagerFactorySpi {

    private static final TrustManager DUMMY_TRUST_MANAGER = new X509TrustManager() {
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }

        @Override
        public void checkClientTrusted(
                X509Certificate[] chain, String authType) throws CertificateException {
            // Always trust - it is an example.
            // You should do something in the real world.
            // You will reach here only if you enabled client certificate auth,
            // as described in SecureChatSslContextFactory.
            System.err.println(
                    "UNKNOWN CLIENT CERTIFICATE: " + chain[0].getSubjectDN());
        }

        @Override
        public void checkServerTrusted(
                X509Certificate[] chain, String authType) throws CertificateException {
            // Always trust - it is an example.
            // You should do something in the real world.
            System.err.println(
                    "UNKNOWN SERVER CERTIFICATE: " + chain[0].getSubjectDN());
        }
    };

    public static TrustManager[] getTrustManagers() {
        return new TrustManager[] { DUMMY_TRUST_MANAGER };
    }

    @Override
    protected TrustManager[] engineGetTrustManagers() {
        return getTrustManagers();
    }

    @Override
    protected void engineInit(KeyStore keystore) throws KeyStoreException {
        // Unused
    }

    @Override
    protected void engineInit(ManagerFactoryParameters managerFactoryParameters)
            throws InvalidAlgorithmParameterException {
        // Unused
    }
}

Comment implémenter cette classe correctement ?

Et dans ce code (dans la classe SecureChatSslContextFactory) :

    SSLContext serverContext = null;
    SSLContext clientContext = null;
    try {
        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(SecureChatKeyStore.asInputStream(),
                SecureChatKeyStore.getKeyStorePassword());

        // Set up key manager factory to use our key store
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
        kmf.init(ks, SecureChatKeyStore.getCertificatePassword());

        // Initialize the SSLContext to work with our key managers.
        serverContext = SSLContext.getInstance(PROTOCOL);
        serverContext.init(kmf.getKeyManagers(), null, null);
    } catch (Exception e) {
        throw new Error(
                "Failed to initialize the server-side SSLContext", e);
    }

    try {
        clientContext = SSLContext.getInstance(PROTOCOL);
        clientContext.init(null, SecureChatTrustManagerFactory.getTrustManagers(), null);
    } catch (Exception e) {
        throw new Error(
                "Failed to initialize the client-side SSLContext", e);
    }

Pourquoi mettent-ils null au lieu de tmf.getTrustManagers() dans la ligne serverContext.init(kmf.getKeyManagers(), null, null); ?

9voto

Bruno Points 47560

Comment implémenter cette classe correctement ?

Vous devez définir un moyen de vérifier que vous faites confiance au certificat à l'adresse chain[0] d'une manière ou d'une autre. Si tu ne le fais pas, lance un CertificateException . (Ici, le SecureChatTrustManagerFactory ne lance jamais rien, il contourne donc la vérification, ce qui peut rendre la connexion ouverte aux attaques MITM).

Si vous souhaitez effectuer cette vérification de manière semi-manuelle, vous pouvez utiliser la fonction API Java PKI bien que il peut être un peu fastidieux même pour des cas d'utilisation relativement simples.

En général, la bonne chose à faire est no pour mettre en œuvre la vôtre. Laissez cela à la TrustManagerFactory (plus ou moins de la même manière qu'avec la fonction KeyManagerFactory ). D'ailleurs, dans les deux cas, je recommande d'utiliser Key/TrustManagerFactory.getDefaultAlgorithm() pour la valeur de algorithm sauf si vous avez une bonne raison de ne pas le faire. C'est au moins une meilleure valeur par défaut que SunX509 que j'ai vu codé en dur dans de nombreux cas (et qui en fait n'est pas la valeur par défaut de l'algorithme TMF).

Vous pouvez initialiser un TMF à partir de votre propre truststore (une instance de KeyStore que vous pouvez charger spécifiquement pour cette connexion, par exemple).

Pourquoi mettre null à la place de tmf.getTrustManagers() dans la ligne serverContext.init(kmf.getKeyManagers(), null, null) ; ?

null pour les gestionnaires de la fiducie et null pour le SecureRandom reviennent aux valeurs par défaut. Il s'agira d'un gestionnaire de confiance par défaut initialisé avec l'algorithme TMF par défaut (habituellement PKIX ), en utilisant le magasin de confiance par défaut (en utilisant l'emplacement dans javax.net.ssl.trustStore ou de se rabattre sur le jssecacerts ou cacerts ). Plus de détails dans le Guide de référence JSSE .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X