2012-03-05 9 views
9

Ahora estoy tratando de configurar Netty con un protocolo de enlace SSL bidireccional, donde tanto el cliente como el servidor presentan y verifican los certificados.Configurar Netty con Handsake SSL bidireccional (certificado de cliente y servidor)

Esto no parece implementarse en SslHandler. ¿Alguien ha hecho esto? Supongo que iría en la operación SslHandler.handshake y se delegaría en javax.net.ssl.SSLEngine?

¿Alguna sugerencia/sugerencia/implementaciones preexistentes?

Gracias!


RESPUESTA (stackoverflow no me deja publicar que la forma normal) He descubierto que si me puse la bandera needClientAuth en el objeto SSLEngine antes de la creación de mi SslHandler, que se ocupa del problema!

Respuesta

10

Aquí está la solución, basada en el ejemplo del servidor HttpSnoop del proyecto netty.

Al configurar la tubería del lado del cliente, el motor SSL debe estar configurado de la siguiente manera:

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

Luego, su SSLContext debe ser modificado de la siguiente manera para configurar un almacén de confianza, además de un almacén de claves (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 
} 
} 
+1

Quería comentar sobre la respuesta de CStepnitz. De los documentos de SslEngine: Configura el motor para requerir la autenticación del cliente. Esta opción solo es útil para motores en el modo de servidor. No del lado del cliente como él indicó. – user1792307

+0

@CStepnitz: ¿Sabe qué tipo de certificaciones aceptará TrustManager? Tengo una arquitectura muy similar, pero el cliente está enviando un certificado ECC (y el protocolo de enlace falla porque no se reconoce la curva del certificado), pero se aceptan certificaciones RSA. – favicon

4

autenticación mutua es ahora compatible con SslContext (actualmente sólo para proveedor de JDK, pero OpenSSL proporciona soporte estará disponible en breve). Consulte newClientContext y newServerContext, que ahora son compatibles con TrustManagerFactory y KeyManagerFactory. Estos métodos de fábrica estáticos también admiten directamente tomar certificados, claves y archivos de cadenas de certificados para compilar TrustManagerFactory y KeyManagerFactory por usted.

Consulte el JdkSslEngineTest para ver un ejemplo de cómo solicitar autenticación de cliente (para el proveedor de JDK).

+0

El motor OpenSSL ahora es compatible con la autenticación mutua. El motor OpenSSL básicamente tiene paridad de características con el motor SSL de JDK.Consulte [SSLEngineTest] (https://github.com/netty/netty/blob/4.1/handler/src/test/java/io/netty/handler/ssl/SSLEngineTest.java) y si faltan funciones, por favor [archivo un problema] (https://github.com/netty/netty/issues). –

6

En lugar de establecer SSLEngine utilice nettys SslContext para crear un nuevo SslHandler. Básicamente se puede crear una nueva SslContext pasando KeyManagerFactory de la siguiente manera

SSLContext SSLContext = SslContextBuilder.forServer (keyManagerFactory) .build();

Luego use creado SslContext para obtener el controlador para ChannelPipeline.

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

Cuestiones relacionadas