使用 2-way SSL Handskake(客户端和服务器证书)设置 Netty
Posted
技术标签:
【中文标题】使用 2-way SSL Handskake(客户端和服务器证书)设置 Netty【英文标题】:Set up Netty with 2-way SSL Handskake (client and server certificate) 【发布时间】:2012-03-23 08:27:47 【问题描述】:我现在正在尝试使用 2 路 SSL 握手设置 Netty,客户端和服务器都存在并验证证书。
这似乎没有在 SslHandler 中实现。有人这样做吗?我想它会进入 SslHandler.handshake 操作并委托给 javax.net.ssl.SSLEngine?
任何提示/提示/预先存在的实现?
谢谢!
回答(*** 不会让我以正常方式发布它)我发现如果我在设置我的 SslHandler 之前在 SSLEngine 对象上设置了 needClientAuth 标志,那么问题就解决了!
【问题讨论】:
【参考方案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
【讨论】:
javax.net.ssl.keyStoreType 属性支持的任何类型的证书都是可接受的。 docs.oracle.com/cd/B19306_01/java.102/b14355/…【参考方案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 支持)。请参阅newClientContext 和newServerContext,它们现在都支持采用 TrustManagerFactory 和 KeyManagerFactory。这些静态工厂方法还支持直接获取证书、密钥和证书链文件为您构建 TrustManagerFactory 和 KeyManagerFactory。
请参阅JdkSslEngineTest 以获取有关如何要求客户端身份验证的示例(对于 JDK 提供程序)。
【讨论】:
OpenSSL 引擎现在支持相互身份验证。 OpenSSL 引擎基本上具有与 JDK 的 SSL 引擎相同的功能。请参阅SSLEngineTest,如果缺少功能,请file an issue。以上是关于使用 2-way SSL Handskake(客户端和服务器证书)设置 Netty的主要内容,如果未能解决你的问题,请参考以下文章
iphone:是不是有任何安全的方法可以从应用程序建立 2-way SSL