2012-03-05 39 views
9

Tôi hiện đang cố gắng thiết lập Netty với bắt tay SSL 2 chiều, nơi cả máy khách và máy chủ hiện diện và xác minh chứng chỉ.Thiết lập Netty với SSL Hand-2 chiều (chứng chỉ máy khách và máy chủ)

Điều này dường như không được triển khai trong SslHandler. Có ai làm điều này không? Tôi cho rằng nó sẽ đi vào hoạt động SslHandler.handshake và được ủy quyền cho javax.net.ssl.SSLEngine?

Bất kỳ gợi ý/mẹo/triển khai từ trước nào?

Cảm ơn!


ĐÁP (stackoverflow sẽ không cho phép tôi gửi nó theo cách thông thường) Tôi thấy rằng nếu tôi đặt cờ needClientAuth trên đối tượng SSLEngine trước khi thiết lập SslHandler của tôi, mà sẽ chăm sóc của vấn đề!

Trả lời

10

Đây là giải pháp, dựa trên ví dụ về máy chủ HttpSnoop từ dự án netty.

Khi thiết lập các đường ống dẫn phía khách hàng, động cơ ssl phải được thiết lập như sau:

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

Sau đó SSLContext của bạn phải được sửa đổi như sau để thiết lập một cửa hàng tin tưởng, thêm vào một keystore (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

Tôi muốn nhận xét về câu trả lời của CStepnitz. Từ tài liệu SslEngine: Định cấu hình công cụ để yêu cầu xác thực ứng dụng khách. Tùy chọn này chỉ hữu ích cho các công cụ ở chế độ máy chủ. Không phải là phía khách hàng như ông đã chỉ ra. – user1792307

+0

@CStepnitz: Bạn có biết những loại chứng chỉ mà TrustManager sẽ chấp nhận không? Tôi có kiến ​​trúc rất giống nhau nhưng khách hàng đang gửi một chứng nhận ECC (và cái bắt tay thất bại vì đường cong trên chứng nhận không được công nhận) nhưng các chứng chỉ RSA được chấp nhận. – favicon

4

xác thực lẫn nhau hiện đang được hỗ trợ bởi SslContext (hiện tại chỉ dành riêng cho nhà cung cấp JDK, nhưng OpenSSL hỗ trợ được đến sớm). Xem newClientContextnewServerContext mà cả hai giờ đây đều hỗ trợ sử dụng TrustManagerFactory và KeyManagerFactory. Các phương thức nhà máy tĩnh này cũng hỗ trợ trực tiếp việc lấy các chứng chỉ, khóa và các tệp chuỗi chứng chỉ để xây dựng TrustManagerFactory và KeyManagerFactory cho bạn.

Xem JdkSslEngineTest để biết ví dụ về cách yêu cầu xác thực ứng dụng khách (đối với nhà cung cấp JDK).

+0

Công cụ OpenSSL hiện hỗ trợ xác thực lẫn nhau. Động cơ OpenSSL về cơ bản có tính chẵn lẻ với công cụ SSL của JDK.Xem [SSLEngineTest] (https://github.com/netty/netty/blob/4.1/handler/src/test/java/io/netty/handler/ssl/SSLEngineTest.java) và nếu thiếu các tính năng, vui lòng [tệp một vấn đề] (https://github.com/netty/netty/issues). –

6

Thay vì đặt SSLEngine hãy sử dụng số nettys SslContext để tạo mới SslHandler. Về cơ bản bạn có thể tạo mới SslContext bằng cách thông qua KeyManagerFactory như sau

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

Sau đó, sử dụng tạo SslContext để nhận trình xử lý cho ChannelPipeline.

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

Các vấn đề liên quan