Netty SSL:如何编写TrustManager

Nan*_*com 7 java ssl netty

我已经阅读了很多东西来设置我的SSL客户端/服务器系统(没有HTTP).

我从安全聊天示例websocket ssl服务器示例中获得灵感.已经使用该命令创建了我的cert.jks文件

keytool -genkey -alias app-keysize 2048 -validity 36500
-keyalg RSA -dname "CN=app"
-keypass mysecret-storepass mysecret
-keystore cert.jks
Run Code Online (Sandbox Code Playgroud)

在安全聊天示例中,有这个类:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

你如何正确地实现这个类?

并在此代码中(在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);
    }
Run Code Online (Sandbox Code Playgroud)

他们为什么要null而不是tmf.getTrustManagers()排队serverContext.init(kmf.getKeyManagers(), null, null);

Bru*_*uno 9

你如何正确地实现这个类?

您需要定义一种方法来检查您是否以某种方式信任证书chain[0].如果你不这样做,扔一个CertificateException.(这里SecureChatTrustManagerFactory永远不会抛出任何东西,所以它绕过验证,这可以使连接对MITM攻击开放.)

如果您想半手动执行此验证,可以使用Java PKI API,尽管它可能有点单调乏味,即使在相对简单的用例上也是如此.

一般来说,正确的做法是不要实现自己的.把它留给TrustManagerFactory(或多或少与它完成的方式相同KeyManagerFactory).顺便说一句,在这两种情况下,我建议使用Key/TrustManagerFactory.getDefaultAlgorithm()algorithm,除非你有充分的理由不这样做.它至少是一个比SunX509我在许多情况下看到的硬编码更好的默认值(事实上​​它不是默认的TMF算法值).

您可以从您自己的信任库(例如KeyStore,您可以专门为此连接加载的实例)初始化TMF .

为什么他们在行serverContext.init(kmf.getKeyManagers(),null,null)中放置null而不是tmf.getTrustManagers(); ?

null信托经理和nullSecureRandom回落到默认值.这将是使用默认TMF算法(通常PKIX)初始化的默认信任管理器,使用默认信任库(使用位置javax.net.ssl.trustStore,或回退到jssecacerts文件或cacerts).JSSE参考指南中的更多细节.