【问题标题】:Set up Netty with 2-way SSL Handskake (client and server certificate)使用 2-way SSL Handskake(客户端和服务器证书)设置 Netty
【发布时间】:2012-03-23 08:27:47
【问题描述】:

我现在正在尝试使用 2 路 SSL 握手设置 Netty,客户端和服务器都存在并验证证书。

这似乎没有在 SslHandler 中实现。有人这样做吗?我想它会进入 SslHandler.handshake 操作并委托给 javax.net.ssl.SSLEngine?

任何提示/提示/预先存在的实现?

谢谢!


回答(stackoverflow 不会让我以正常方式发布它)我发现如果我在设置我的 SslHandler 之前在 SSLEngine 对象上设置了 needClientAuth 标志,那么问题就解决了!

【问题讨论】:

    标签: java ssl netty handshake


    【解决方案1】:

    这是基于 netty 项目的 HttpSnoop 服务器示例的解决方案。

    设置客户端管道时,ssl引擎必须设置如下:

    public ChannelPipeline getPipeline() throws Exception {
        // Create a default pipeline implementation.
        ChannelPipeline pipeline = pipeline();
    
        // Uncomment the following line if you want HTTPS
        SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
        engine.setUseClientMode(false);
        engine.setNeedClientAuth(true);
        pipeline.addLast("ssl", new SslHandler(engine));
    
        pipeline.addLast("decoder", new HttpRequestDecoder());
        pipeline.addLast("logger", new RequestAuditLogger());
        // Uncomment the following line if you don't want to handle HttpChunks.
        pipeline.addLast("aggregator", new HttpChunkAggregator(1048576));
        pipeline.addLast("outputLogger", new ResponseAuditLogger());
        pipeline.addLast("encoder", new HttpResponseEncoder());
        // Remove the following line if you don't want automatic content compression.
        pipeline.addLast("deflater", new HttpContentCompressor());
        pipeline.addLast("handler", new HttpSnoopServerHandler());
        return pipeline;
    }
    }
    

    那么您的 SSLContext 必须进行如下修改,以设置除了密钥库(SecureChatSslContextFactory)之外的信任库:

    public final class SecureChatSslContextFactory {
    
    
    private static Logger logger = LoggerFactory.getLogger(SecureChatSslContextFactory.class);
    
    private static final String PROTOCOL = "TLS";
    private static final SSLContext SERVER_CONTEXT;
    private static final SSLContext CLIENT_CONTEXT;
    
    static {
    
        SSLContext serverContext = null;
        SSLContext clientContext = null;
    
            // get keystore and trustore locations and passwords
        String keyStoreLocation = System.getProperty("javax.net.ssl.keyStore");
        String keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword");
        String trustStoreLocation = System.getProperty("javax.net.ssl.trustStore");
        String trustStorePassword = System.getProperty("javax.net.ssl.trustStorePassword");
        try {
    
            KeyStore ks = KeyStore.getInstance("JKS");
            ks.load(KeyStoreStreamManager.asInputStream(keyStoreLocation),
                    keyStorePassword.toCharArray());
    
            // Set up key manager factory to use our key store
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(ks, keyStorePassword.toCharArray());
    
              // truststore
            KeyStore ts = KeyStore.getInstance("JKS");
            ts.load(KeyStoreStreamManager.asInputStream(trustStoreLocation),
                    trustStorePassword.toCharArray());
    
            // set up trust manager factory to use our trust store
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(ts);
    
            // Initialize the SSLContext to work with our key managers.
            serverContext = SSLContext.getInstance(PROTOCOL);
            serverContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), 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);
        }
    
        SERVER_CONTEXT = serverContext;
        CLIENT_CONTEXT = clientContext;
    }
    
    public static SSLContext getServerContext() {
        return SERVER_CONTEXT;
    }
    
    public static SSLContext getClientContext() {
        return CLIENT_CONTEXT;
    }
    
    private SecureChatSslContextFactory() {
        // Unused
    }
    }
    

    【讨论】:

    【解决方案2】:

    不要设置SSLEngine,而是使用nettys SslContext来创建一个新的SslHandler。基本上你可以通过传递KeyManagerFactory 来创建新的SslContext,如下所示

    SslContext sslContext = SslContextBuilder.forServer(keyManagerFactory).build();

    然后使用创建的SslContext 获取ChannelPipeline 的处理程序。

    ChannelPipeline.addLast("ssl", sslContext.newHandler(socketChannel.alloc()));

    【讨论】:

      【解决方案3】:

      SslContext 现在支持相互身份验证(目前仅适用于 JDK 提供程序,但即将提供 OpenSSL 支持)。请参阅newClientContextnewServerContext,它们现在都支持采用 TrustManagerFactory 和 KeyManagerFactory。这些静态工厂方法还支持直接获取证书、密钥和证书链文件为您构建 TrustManagerFactory 和 KeyManagerFactory。

      请参阅JdkSslEngineTest 以获取有关如何要求客户端身份验证的示例(对于 JDK 提供程序)。

      【讨论】:

      • OpenSSL 引擎现在支持相互身份验证。 OpenSSL 引擎基本上具有与 JDK 的 SSL 引擎相同的功能。请参阅SSLEngineTest,如果缺少功能,请file an issue
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-20
      • 2013-06-20
      • 2011-06-11
      • 1970-01-01
      • 2014-02-23
      • 1970-01-01
      • 2013-09-08
      相关资源
      最近更新 更多