2012-03-05 3 views
9

이제 클라이언트와 서버가 인증서를 제시하고 확인하는 양방향 SSL 핸드 셰이크로 Netty를 설정하려고합니다.양방향 SSL Handsake (클라이언트 및 서버 인증서)로 Netty 설정

이것은 SslHandler에서 구현되지 않은 것처럼 보입니다. 누구든지이 일을 했습니까? SslHandler.handshake 작업에 참여하고 javax.net.ssl.SSLEngine에 위임 될 것이라고 생각합니까?

힌트/팁/기존 구현?

감사합니다.


답변 내가 문제를 돌봐 내 SslHandler을 설정하기 전에 SSLEngine의 개체에 needClientAuth 플래그를 설정하면 내가 발견 (유래는 내가 그것을 정상적인 방법을 게시하지 않습니다)!

답변

10

다음은 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 
} 
} 
+1

저는 CStepnitz의 답변에 대해 의견을 말했습니다. SslEngine 문서에서 : 클라이언트 인증을 요구하도록 엔진을 구성합니다. 이 옵션은 서버 모드의 엔진에만 유용합니다. 그가 말한대로 클라이언트 쪽이 아닙니다. – user1792307

+0

@CStepnitz : TrustManager에서 어떤 종류의 인증서를 사용할 수 있는지 알고 있습니까? 나는 매우 유사한 아키텍처를 가지고 있지만 클라이언트는 ECC 인증서를 보내고있다. (그리고 인증서의 곡선이 인식되지 않기 때문에 핸드 셰이크가 실패한다.) RSA 인증서가 받아 들여진다. – favicon

4

상호 인증은 지금 (단지 JDK 공급자의 현재,하지만 OpenSSL을 지원이 곧 제공 될 예정입니다 제공) SslContext에 의해 지원됩니다. newClientContextnewServerContext을 참조 해주세요. 모두 TrustManagerFactory와 KeyManagerFactory를 지원합니다. 이러한 정적 팩토리 메소드는 또한 인증서, 키 및 인증서 체인 파일을 직접 가져 와서 TrustManagerFactory 및 KeyManagerFactory를 빌드 할 수 있도록 지원합니다.

(JDK 공급자의 경우) 클라이언트 인증을 요구하는 방법의 예는 JdkSslEngineTest을 참조하십시오.

+0

OpenSSL 엔진은 이제 상호 인증을 지원합니다. OpenSSL 엔진은 기본적으로 JDK의 SSL 엔진과 기능 패리티를 가지고 있습니다.[SSLEngineTest] (https://github.com/netty/netty/blob/4.1/handler/src/test/java/io/netty/handler/ssl/SSLEngineTest.java)를 참조하십시오. 누락 된 기능이 있으면 [file 문제] (https://github.com/netty/netty/issues). –

6

SSLEngine을 설정하는 대신 nettys SslContext을 사용하여 SslHandler을 새로 만듭니다. 기본적으로 다음과 같이 KeyManagerFactory을 전달하여 새로운 SslContext을 만들

의 SSLContext의 SSLContext = SslContextBuilder.forServer (의 KeyManagerFactory) .build() 할 수 있습니다;

은 다음 ChannelPipeline에 대한 핸들러를 얻을 수 SslContext을 만들어 사용합니다.

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

관련 문제