본문 바로가기
IT/JAVA

Netty(6) - TCP Server with SSL

by 최고영회 2021. 2. 19.
728x90
반응형
SMALL

Netty를 이용하여 TCP Server를 개발하고 있다.

정해진 프로토콜에 맞게 통신하고 데이터 일부는 파일로 저장하고 저장된 파일을 분석하는 모듈이다.

프로토타입의 개발이 완료되는 시점에 암호화 통신이 필요하다는 요구사항이 추가 되었다.

Netty는 아주 쉽게 이를 처리할 수 있다.

Netty의 구조를 잘 생각해 보면 pipeline 에 ssl 통신처리 handler 를 넣어주면 되지 않을까? 생각이 든다.

일단 인증서를 만들어 보자.

java 의 keytool 을 이용해 만들수 있고 sign 알고리즘은 SHA256withRSA 를 이용하도록 했다.

keytool -genkey -v -keystore server.jks -alias server_private -keyalg RSA -sigalg SHA256withRSA -keysize 2048 -validity 365

 

test용 client 에도 적용해야 하니 client.jks 파일도 만들자.

keytool -genkey -v -keystore client.jks -alias client_private -keyalg RSA -sigalg SHA256withRSA -keysize 2048 -validity 365

csr을 keytool 로 생성한다.

keytool -export -alias server_private -keystore server.jks -rfc -file trustServer.cer 
keytool -export -alias server_private -keystore client.jks -rfc -file trustClient.cer

server.jks 에 trustClient.cer 을, client.jks 에 trustServer.cer를 import 해 준다.

keytool -import -alias trustClient -file trustClient.cer -keystore server.jks 
keytool -import -alias trustServer -file trustServer.cer -keystore client.jks

준비 끝

이제 channel init 할 때 io.netty.handler.ssl.SslContext 를 pipline 에 넣어주기만 하면 된다.

@Override 
protected void initChannel(SocketChannel ch) throws Exception { 
  ChannelPipeline pipeline = ch.pipeline(); 
  if (prop.isUseSsl()) { 
    KeyStore ks = KeyStore.getInstance("JKS"); 
    ks.load(new FileInputStream(ResourceUtils.getFile("classpath:server.jks")), "password".toCharArray()); 
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 
    kmf.init(ks, "password".toCharArray()); 
    
    SslContext sslCtx = SslContextBuilder.forServer(kmf).build(); 
    pipeline.addLast(sslCtx.newHandler(ch.alloc())); 
  } 
  
  pipeline.addLast(stringEncoder); 
  pipeline.addLast(new FileSaveHandler(prop, scheduler)); 
}

Client 에서는

KeyStore ks = KeyStore.getInstance("JKS"); 
InputStream is = new FileInputStream("D:\\certificate\\client.jks"); 
ks.load(is, "password".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 
tmf.init(ks); 
SSLContext sslcontext = SSLContext.getInstance("TLS");
TrustManager[] trustManagers = tmf.getTrustManagers(); 
sslcontext.init(null, trustManagers, new SecureRandom()); 
factory = sslcontext.getSocketFactory(); 
... 
sslSocket = (SSLSocket) factory.createSocket(socket, null, PORT, false); 
sslSocket.setEnabledCipherSuites(factory.getSupportedCipherSuites()); 
...
OutputStream os = sslSocket.getOutputStream(); 
os.write(buffer, 0. readBytes); 
os.flush();
...

잘된다.

netty를 사용하면

pipline 에 handler 를 추가하고 필요시 decoder, encoder를 추가하면서

복잡한 raw level의 socket 과 관련된 처리는 신경쓸 필요 없이

필요한 business logic 에 집중할 수 있어서 좋다.

 

728x90
반응형
LIST