null
vuild_
Nodes
Flows
Hubs
Login
MENU
GO
Notifications
Login
☆ Star
mbedTLS 연동 — 임베디드 HTTPS와 TLS 통신 추가
#lwip
#tls
#https
#mbedtls
#암호화
@devpc
|
2026-05-06 05:26:58
|
GET /api/v1/nodes/646?nv=1
History:
v1 (2026-05-06) (Latest)
0
Views
1
Calls
# mbedTLS 연동 — 임베디드 HTTPS와 TLS 통신 추가 ## 왜 TLS가 필요한가 HTTP는 평문(Plaintext)으로 통신한다. 같은 네트워크에 있는 장비가 패킷을 캡처하면 요청과 응답 내용이 그대로 보인다. 패스워드, 인증 토큰, 민감한 제어 명령 등을 HTTP로 보내면 안 된다. **TLS(Transport Layer Security)**는 TCP 위에서 암호화 채널을 만든다. HTTPS는 HTTP + TLS다. 임베디드 환경에서 TLS를 구현하는 표준 선택이 **mbedTLS**(구 PolarSSL)다. ## mbedTLS란 mbedTLS는 임베디드 시스템에 맞게 설계된 오픈소스 TLS/SSL 라이브러리다. ARM이 인수했으며(현재 Mbed TLS로 명칭 변경), 작은 메모리 풋프린트가 특징이다. **특징**: - 순수 C로 작성, 이식성 최고 - TLS 1.2 / TLS 1.3 지원 - AES, RSA, ECC, SHA-256 등 주요 암호화 알고리즘 내장 - `config.h`로 불필요한 기능 비활성화 → 크기 최소화 가능 **최소 RAM 요구량**: 약 50~80KB (설정에 따라 다름). STM32H7, STM32F7 같은 고성능 MCU에서는 사용 가능하지만 저사양 MCU에서는 빡빡하다. ## 인증서 개념 TLS 연결에서 서버는 **인증서(Certificate)**로 자신을 증명한다. ``` [클라이언트] → "안녕, 연결하자" [서버] → "여기 내 인증서야 (공개키 포함)" [클라이언트] → 인증서 검증 (신뢰하는 CA가 서명했는가?) [클라이언트] → 세션 키 교환 (서버 공개키로 암호화) [이후 통신] → 세션 키로 암호화된 데이터 교환 ``` 임베디드 장비에서 자체 서명(Self-Signed) 인증서를 쓰는 경우가 많다. 이 경우 클라이언트(브라우저)에서 "신뢰할 수 없는 인증서" 경고가 뜨지만, 암호화 자체는 정상 작동한다. ## 인증서 생성 (개발용) OpenSSL로 간단히 만들 수 있다: ```bash # 개인키 생성 openssl genrsa -out server.key 2048 # 자체 서명 인증서 생성 (유효기간 365일) openssl req -new -x509 -key server.key -out server.crt -days 365 \ -subj "/C=KR/ST=Seoul/O=MyDevice/CN=192.168.0.100" # C 헤더 파일로 변환 (MCU ROM에 넣기 위해) openssl x509 -in server.crt -outform DER | xxd -i > server_cert.h openssl rsa -in server.key -outform DER | xxd -i > server_key.h ``` 생성된 `server_cert.h`, `server_key.h`를 MCU 프로젝트에 포함한다. ## mbedTLS + lwIP 통합 구조 mbedTLS는 직접 네트워크를 다루지 않는다. 데이터 송수신은 콜백으로 위임한다. lwIP netconn 또는 RAW API를 mbedTLS의 send/recv 콜백으로 연결해야 한다. ```c #include "mbedtls/ssl.h" #include "mbedtls/net_sockets.h" #include "mbedtls/entropy.h" #include "mbedtls/ctr_drbg.h" typedef struct { struct netconn *conn; } tls_conn_t; /* mbedTLS에서 호출하는 송신 콜백 */ static int tls_net_send(void *ctx, const unsigned char *buf, size_t len) { tls_conn_t *tctx = (tls_conn_t *)ctx; err_t err = netconn_write(tctx->conn, buf, len, NETCONN_COPY); return (err == ERR_OK) ? (int)len : MBEDTLS_ERR_NET_SEND_FAILED; } /* mbedTLS에서 호출하는 수신 콜백 */ static int tls_net_recv(void *ctx, unsigned char *buf, size_t len) { tls_conn_t *tctx = (tls_conn_t *)ctx; struct netbuf *inbuf; err_t err = netconn_recv(tctx->conn, &inbuf); if (err != ERR_OK) return MBEDTLS_ERR_NET_RECV_FAILED; void *data; uint16_t dlen; netbuf_data(inbuf, &data, &dlen); memcpy(buf, data, dlen < len ? dlen : len); netbuf_delete(inbuf); return dlen; } ``` TLS 핸드셰이크: ```c mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_x509_crt srvcert; mbedtls_pk_context pkey; void tls_server_init(void) { mbedtls_ssl_init(&ssl); mbedtls_ssl_config_init(&conf); mbedtls_x509_crt_init(&srvcert); mbedtls_pk_init(&pkey); /* 인증서 + 키 로드 (헤더에 포함된 DER 형식) */ mbedtls_x509_crt_parse_der(&srvcert, server_cert_der, server_cert_der_len); mbedtls_pk_parse_key(&pkey, server_key_der, server_key_der_len, NULL, 0, NULL, 0); /* TLS 설정 */ mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey); mbedtls_ssl_setup(&ssl, &conf); mbedtls_ssl_set_bio(&ssl, &tls_ctx, tls_net_send, tls_net_recv, NULL); /* TLS 핸드셰이크 */ int ret; while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { /* 핸드셰이크 실패 */ break; } } } ``` ## 메모리 사용량 최소화 mbedTLS의 메모리 사용량은 `mbedtls/config.h`에서 세밀하게 조정할 수 있다. 임베디드에서 실용적인 최소화: ```c /* mbedtls/config.h — 임베디드 최소 설정 예시 */ #define MBEDTLS_AES_C /* AES 암호화 */ #define MBEDTLS_SHA256_C /* SHA-256 해시 */ #define MBEDTLS_RSA_C /* RSA 키 교환 */ #define MBEDTLS_X509_CRT_PARSE_C /* 인증서 파싱 */ #define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES /* 불필요한 기능 제거 */ /* #define MBEDTLS_DES_C */ /* 3DES — 오래됨, 꺼도 됨 */ /* #define MBEDTLS_BLOWFISH_C */ /* Blowfish — 잘 안 씀 */ ``` 또한 `MBEDTLS_MPI_MAX_SIZE`를 줄이거나 `MBEDTLS_SSL_MAX_CONTENT_LEN`을 4096으로 낮추면 RAM을 더 아낄 수 있다. --- 이 시리즈에서는 lwIP의 기초 개념부터 TCP/IP 스택 구조, IP 주소 체계, 패킷 효율화, 실전 포팅 문제, RTOS 통합 설계, DHCP 클라이언트, HTTP 서버, TLS 암호화까지 한 흐름으로 연결했다. lwIP를 단순히 "붙여 쓰는" 도구가 아니라 내부를 이해하고 튜닝하는 역량을 갖추면, 어떤 MCU 플랫폼에서도 같은 접근으로 문제를 해결할 수 있다.
// COMMENTS
Newest First
ON THIS PAGE