정말 오랜만에 포스팅한다.
이 문서에서 사용하는 OpenSSL 버전은 1.0.1u 이다.
사설 인증서 생성
openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem
OpenSSL 초기화 / 해제
우선 OpenSSL을 사용하기 위해서 아래와 같이 초기화를 한다.
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
그리고 SSL을 사용하기 위한 context 객체가 필요하다.
아래와 같이 사용할 SSL 버전을 선택하고 SSL Context를 생성한다.
여기서는 TLS 1.2 버전을 지정했다.
SSLCtx = SSL_CTX_new(TLSv1_2_server_method());
이제 위에서 생성한 사설 인증서를 로딩하도록 아래와 같이 설정하고 SSL_CTX_check_private_key으로 검증한다.
SSL_CTX_use_certificate_file(SSLCtx, "mycert.pem", SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(SSLCtx, "mycert.pem", SSL_FILETYPE_PEM);
SSL_CTX_check_private_key(SSLCtx);
SSL_CTX_check_private_key이 에러를 리턴한다면 인증서에 문제가 있는 것이다.
SSL의 사용이 끝나면 SSL_CTX_free을 사용해서 정리하고, 아래와 같이 사용한 모든 자원을 해제한다.
SSL_CTX_free(SSLCtx);
ERR_remove_state(0);
ENGINE_cleanup();
CONF_modules_unload(1);
ERR_free_strings();
EVP_cleanup();
sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
CRYPTO_cleanup_all_ex_data();
SSL Accept 처리
SSL Accept 처리는 TCP Accept가 처리된 이후에 진행한다.
SSL 커넥션을 관리에 필요한 SSL 구조체를 SSL_new()를 통해서 생성하고 SSL 핸드쉐이크 처리를 SSL_accept()에 위임하기 위해서 TCP socket handle과 연결해야 한다.
연결되는 TCP socket handle은 이미 TCP accept가 완료된 socket의 handle이어야 하며 SSL_accept() 호출 전에 socket을 blocking mode로 설정하고 SSL_accept() 완료 후에 다시 non-blocking mode로 돌리는 것이 편할 것이다.
SSL* ssl = SSL_new(SSLCtx); // SSLCtx는 위에서 SSL_CTX_new()로 생성한 것이다.
SSL_set_fd(ssl, static_cast<int>(socketHandle));
SSL_accept(ssl);
SSL non-Blocking 통신
SSL_ERROR_WANT_READ에 대한 처리는 추가로 들어오는 패킷을 받아서 BIO_write()에 계속 써주면 된다.
간단히 말해서 SSL_ERROR_WANT_READ가 발생하면 위의 처리를 그대로 다시 해주면 된다.
암호화된 내용이 모두 모이지 않으면 복호화할 수 없어서 발생하는 것으로 당연한 처리이지 예외 사항이 아니다.
SSL Close 처리
아래와 같이 정리하면 된다.
SSL_shutdown(ssl);
SSL_free(ssl); // 이때 연결된 BIO도 모두 해제된다.
간단한 SSL 인증과 송수신 Test
OpenSSL을 설치하면 같이 포함되어 있는 openssl command line tool을 사용하여 간단한 테스트를 진행할 수 있다.
위의 내용을 구현한 SSL server를 실행하고 아래와 같이 openssl command line tool을 실행한다. (ssl port는 443이라고 가정한다.)
openssl s_client -connect 127.0.0.1:443 -debug -tls1_2
위에 사용한 아규먼트들은 ssl client 모드로 로컬 호스트의 443포트에 TLS 1.2 프로토콜을 사용하여 debug 모드로 접속하겠다는 것이다.
debug 모드는 추가 정보들을 보여준다.
실행하고 접속에 성공하면 SSL Handshake 과정과 인증서 정보가 출력되며 사용자 입력을 기다린다.
이때 동작은 간단한 채팅 클라이언트 처럼 동작한다. 콘솔에 입력된 내용은 엔터를 치면 서버로 전송되고 서버로 부터 받은 내용은 콘솔에 그대로 출력된다.
간단한 ssl echo server를 구현하여 테스트하기에 편리하다.
이상으로 정리를 마칩니다.
위 내용에서 잘못된 내용은 꼭 알려주시기를 부탁드립니다.
-------------------------------------------------------------------------------------
이 글이 TOAST Meetup에 소개되었습니다.
non-blocking socket에 OpenSSL 적용하기
'Dev' 카테고리의 다른 글
테스트 용이성(Testability) 향상을 위한 DI(Dependency Injection) (0) | 2017.06.19 |
---|---|
BDD (Behaviour-Driven Development)에 대한 간략한 정리 (0) | 2017.04.16 |
하스켈로 배우는 프로그래밍 도서 후기 (1) | 2013.11.19 |
IntelliJ IDEA / WebStome 에서 자주 사용하는 단축키들 (1) | 2013.11.17 |
x86, x64에서 동시에 HOOK을 걸면 하나는 동작을 안한다. (0) | 2012.08.19 |