Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Netty SSL : how to write a TrustManager

Tags:

java

ssl

netty

I've read plenty of stuff to setup my SSL client/server system (no HTTP).

I inspired myself from the secure chat example and the websocket ssl server example. Already created my cert.jks file with the command

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

In the secure chat example there is this class:

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
    }
}

How do you implement this class properly?

And in this code (in the SecureChatSslContextFactory class):

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

Why do they put null instead of tmf.getTrustManagers() in the line serverContext.init(kmf.getKeyManagers(), null, null); ?

like image 515
Nanocom Avatar asked Jul 09 '12 13:07

Nanocom


1 Answers

How do you implement this class properly?

You need to define a way to check that you trust the certificate at chain[0] one way or another. If you don't, throw a CertificateException. (Here the SecureChatTrustManagerFactory never throws anything, so it bypasses the verification, which can make the connection open to MITM attacks.)

If you want to do this verification semi-manually, you can use the Java PKI API, although it can be a bit tedious, even on relatively simple use cases.

Generally speaking, the right thing to do is not to implement your own. Leave that to the TrustManagerFactory (more or less in the same way as it's done with the KeyManagerFactory). By the way, in both cases, I'd recommend using Key/TrustManagerFactory.getDefaultAlgorithm() for the value of algorithm, unless you have a good reason not to. It's at least a better default value than SunX509 which I've seen hard-coded in many cases (and which in fact isn't the default TMF algorithm value).

You can initialise a TMF from your own truststore (an instance of KeyStore that you can load specifically for this connection, for example).

Why do they put null instead of tmf.getTrustManagers() in the line serverContext.init(kmf.getKeyManagers(), null, null); ?

null for the trust managers and null for the SecureRandom fall back to the default values. This will be a default trust manager initialised with the default TMF algorithm (usually PKIX), using the default trust store (using the location in javax.net.ssl.trustStore, or falling back to the jssecacerts file or cacerts). More details in the JSSE reference guide.

like image 53
Bruno Avatar answered Nov 19 '22 23:11

Bruno