2012-03-05 14 views
9

Ora sto provando a configurare Netty con un handshake SSL a 2 vie, dove sia il client che il server presentano e verificano i certificati.Configurare Netty con SSL Handsake a 2 vie (certificato client e server)

Questo non sembra essere implementato in SslHandler. Qualcuno lo fa? Suppongo che vada nell'operazione SslHandler.handshake e sia delegato a javax.net.ssl.SSLEngine?

Eventuali suggerimenti/suggerimenti/implementazioni preesistenti?

Grazie!


RISPOSTA (StackOverflow non mi permette di postare il modo normale) ho scoperto che se ho impostato il flag needClientAuth sull'oggetto SSLEngine prima di impostare la mia SslHandler, che si occupa del problema!

risposta

10

Ecco la soluzione, basata sull'esempio del server HttpSnoop dal progetto netty.

Quando si imposta la pipeline lato client, il motore SSL deve essere impostato come segue:

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

Allora il vostro SSLContext deve essere modificato come segue per impostare un negozio di fiducia, oltre a un archivio di chiavi (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

Ho voluto commentare la risposta di CStepnitz. Dai documenti SslEngine: Configura il motore per richiedere l'autenticazione del client. Questa opzione è utile solo per i motori in modalità server. Non il lato client come ha indicato. – user1792307

+0

@CStepnitz: Sai che tipo di certificati accetterà il TrustManager? Ho un'architettura molto simile ma il client sta inviando un certificato ECC (e l'handshake fallisce perché la curva sul certificato non è riconosciuta) ma i certificati RSA sono accettati. – favicon

4

autenticazione reciproca è ora supportato da SslContext (attualmente solo per il provider di JDK, ma OpenSSL fornisce il supporto è in arrivo). Vedere newClientContext e newServerContext che ora supportano entrambi l'acquisizione di TrustManagerFactory e KeyManagerFactory. Questi metodi di produzione statici supportano anche l'acquisizione diretta di file di certificati, chiavi e catene di certificati per creare TrustManagerFactory e KeyManagerFactory.

Vedere JdkSslEngineTest per un esempio di come richiedere l'autenticazione del client (per il provider JDK).

+0

Il motore OpenSSL ora supporta l'autenticazione reciproca. Il motore OpenSSL ha fondamentalmente una parità di funzionalità con il motore SSL di JDK.Vedi [SSLEngineTest] (https://github.com/netty/netty/blob/4.1/handler/src/test/java/io/netty/handler/ssl/SSLEngineTest.java) e se ci sono caratteristiche mancanti per favore [file un problema] (https://github.com/netty/netty/issues). –

6

Invece di impostare SSLEngine utilizzare nettys SslContext per creare un nuovo SslHandler. In pratica è possibile creare nuovi SslContext passando KeyManagerFactory come segue

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

quindi utilizzare creato SslContext per ottenere il gestore per ChannelPipeline.

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

Problemi correlati