Настройка Netty с двухсторонним SSL Handsake (сертификат клиента и сервера) - PullRequest
13 голосов
/ 06 марта 2012

Я сейчас пытаюсь настроить Netty с помощью двухстороннего SSL-рукопожатия, когда и клиент, и сервер представляют и проверяют сертификаты.

Это не реализовано в SslHandler.Кто-нибудь делает это?Я полагаю, что это войдет в операцию SslHandler.handshake и будет делегировано javax.net.ssl.SSLEngine?

Любые подсказки / советы / уже существующие реализации?

Спасибо!


ОТВЕТ (stackoverflow не позволяет мне публиковать его обычным способом) Я обнаружил, что если я установлю флаг needClientAuth на объекте SSLEngine перед установкой моего SslHandler, это решит проблему!

Ответы [ 3 ]

11 голосов
/ 06 марта 2012

Вот решение, основанное на примере сервера HttpSnoop из проекта netty.

При настройке конвейера на стороне клиента механизм 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
}
}
6 голосов
/ 06 ноября 2015

Вместо настройки SSLEngine используйте nettys SslContext для создания нового SslHandler.По сути, вы можете создать новый SslContext, передав KeyManagerFactory следующим образом

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

Затем используйте созданныйSslContext для получения обработчика для ChannelPipeline.

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

4 голосов
/ 10 ноября 2014

Взаимная аутентификация теперь поддерживается SslContext (в настоящее время только для провайдера JDK, но поддержка OpenSSL обеспечит в ближайшее время). См. newClientContext и newServerContext , которые теперь поддерживают получение TrustManagerFactory и KeyManagerFactory. Эти статические фабричные методы также поддерживают непосредственное получение файлов сертификатов, ключей и цепочек сертификатов для создания для вас TrustManagerFactory и KeyManagerFactory.

См. JdkSslEngineTest для примера того, как требовать аутентификацию клиента (для провайдера JDK).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...