📦

[Network] TLS 통신 소스코드 예제 | C언어

Table of contents
TCP에 이어 암호화 통신을 지원하는 TLS 소스코드 예제이다.

TLS Transport Layer Security

TCP위에서 동작
네트워크에서 Data를 안전하게 송신하기 위한 암호화 프로토콜
TLS 주요 특징
데이터 암호화 → 대칭/비대칭( AES, RSA, ECC, ..) 암호화를 사용하여 기밀성(Confidentiality) 보장 (데이터 보호, 도청 방지)
무결성 (Integrity) → 전송 중 데이터가 변경되지 않도록 HMAC을 사용하여 검증
인증 (Authentication) → X.509 인증서를 사용하여 Server와 Client가 신뢰 할 수 있는지 확인
TLS Handshake → 공개 키 기반 암호화(Public Key Cryptography)로 보안 세션 설정

TLS 상호인증 (Mutual TLS, mTLS)

Server뿐만 아니라 클라이언트도 인증서를 사용하여 자신을 인증하는 방식
Server와 Client가 서로 신뢰할 수 있는 경우에만 연결을 허용
예제는.. Root CA가 다른 경우 연결 거부하도록 구현
1.
Server와 Client는 서로의 인증서를 검증하기 위해 신뢰할 수 있는 CA(Certificate Authority, 인증기관)를 사용한다.
2.
Server는 Client의 인증서를 검증하고, Client는 Server의 인증서를 검증한다.
3.
서로의 인증서가 동일한 Root CA에서 발급되었는지 확인
a.
Root CA가 동일하다면 ? 연결
b.
Root CA가 다르다면 ? 연결
Server 인증서 : CA1에서 발급
Client 인증서 : CA2에서 발급
CA1 ≠ CA2 → 인증 실패 → 연결 거부

TLS Server - Client 함수 흐름

TLS는 Handshake 과정에서 Key를 교환한 후, 대칭키 암호화를 통해 Data를 전송한다.
TCP에서 암호화 하는 과정이 추가되는 것이며, 암호화를 위해 SSL/TLS 라이브러리 (OpenSSL)을 사용한다.
TLS는 1-Way Authentication(단방향 인증)과 Mutual Authentication(상호인증) 방식이 있는데, 이 글의 예제에서는 상호인증(Mutual TLS, mTLS)을 다루고 있다.
Server
initialize_openssl() OpenSSL 라이브러리를 초기화
SSL_library_init() -
SSL_load_error_strings() -
OpenSSL_add_ssl_algorithms() -
create_context() TLS Server 컨텍스트(SSL_CTX)를 생성
SSL_CTX_new(TLS_server_method()) -
configure_context() Server 인증서 및 키 설정, Root CA 로드, 인증서 체인 검증
SSL_CTX_use_certificate_file() -
SSL_CTX_use_PrivateKey_file() -
SSL_CTX_check_private_key() -
SSL_CTX_load_verify_locations() -
SSL_CTX_set_verify() -
X509_STORE_new() -
X509_STORE_load_locations(ca) -
SSL_CTX_get0_certificate(server) -
X509_STORE_CTX_new() -
X509_STORE_CTX_init(dServer) -
X509_verify_cert(dServer) -
X509_STORE_CTX_free(dServer) -
X509_STORE_free(server) -
socket() - (TCP)Socket 생성
bind() - 특정 IP와 Port에 Socket Binding
listen() - Client 연결 요청을 대기
accept() - Client 연결 수락 & 새로운 Socket 반환
SSL_new() - TLS 세션(SSL 객체) 생성
SSL_set_fd() - SSL 객체와 소켓을 연결
SSL_accept() - TLS 핸드셰이크 수행 (클라이언트와 상호 인증)
SSL_read() - 클라이언트로부터 데이터 수신
recv() - Client로 부터 Data 수신
SSL_write() - 클라이언트에게 데이터 전송
send() - Client에게 Data 송신
SSL_free() - SSL 객체 해제
close() - Socket을 닫고 연결 종료
SSL_CTX_free() - SSL 컨텍스트 해제
EVP_cleanup() - OpenSSL 정리
Client
initialize_openssl() OpenSSL 라이브러리를 초기화
SSL_library_init() -
SSL_load_error_strings() -
OpenSSL_add_ssl_algorithms() -
create_context() TLS Server 컨텍스트(SSL_CTX)를 생성
SSL_CTX_new(TLS_server_method()) -
SSL_CTX_use_certificate_file() - 클라이언트 인증서 로드 (mTLS)
SSL_CTX_use_PrivateKey_file() - 클라이언트 개인 키 로드
SSL_CTX_load_verify_locations(ca) - 신뢰할 수 있는 CA 인증서 설정
SSL_CTX_set_verify(client) - Server 인증서 검증 설정
socket() - Socket 생성
connect() - Server에 연결 요청
SSL_new() - TLS 세션(SSL 객체) 생성
SSL_set_fd() - SSL 객체와 소켓을 연결
SSL_connect() - TLS 핸드셰이크 수행
SSL_write() - Server에 Data 송신
send() - Server에 Data 송신
SSL_read() - Server로 부터 Data 수신
recv() - Server로 부터 Data 수신
SSL_free() - SSL 객체 해제
close() - Socket을 닫고 연결 종료
SSL_CTX_free() - SSL 컨텍스트 해제
EVP_cleanup() - OpenSSL 정리

TLS Handshake

1.
Client가 Server에 연결 요청 Client → Server : ClientHello 메시지를 보냄 (지원하는 암호화 방식 포함)
2.
Server가 응답 (Server 인증) Server → Client : ServerHello, Certificate 메시지를 보냄 Server 인증서 검증 (Client가 신뢰할 수 있는 CA인지 확인)
3.
Client 인증 (mTLS) Client → Server : Client 인증서 전송 Server가 Client 인증서 검증 (Root CA 체크) Root CA가 다르면 연결 거부
4.
세션 키 교환 및 암호화 설정 Client와 Server가 세션 키를 공유하여 대칭키 암호화로 전환
5.
안전한 TLS 통신 시작 이후 모든 데이터는 암호화된 채로 송수신 !

TLS - Source Code

테스트 환경 참고
Ubuntu 22.04.3 LTS
Linux DESKTOP-711RRPG 5.15.167.4-microsoft-standard-WSL2 #1 SMP Tue Nov 5 00:21:55 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)
예제코드는 리눅스 기반으로 작성
1.
내 PC 8080 포트를 사용하여 server를 띄워두고
2.
client로 server(127.0.0.1:8080)에 message를 하나 보내고
3.
server도 client로 message를 하나 보내고,
4.
client는 종료, server는 listen상태로 대기
tls_server.c
tls_client.c
Makefile
위 코드를 그대로 저장 후 make tls 명령으로 컴파일하면, 테스트 해볼 수 있다