1. 기본 용어 정리

먼저 헷갈리기 쉬운 저장소 개념부터 잡고 가자.

  • Keystore: 나의 키(Public/Private Key)를 보관하는 곳. 자신의 비밀키와 인증서를 담고 있는 저장소다. 상대방에게 "나 이런 사람이야"라고 증명할 때 여기서 인증서를 꺼내서 보여준다고 생각하면 된다.
  • Truststore: 내가 신뢰할 수 있는 상대방의 인증서나 CA 인증서를 담아두는 곳. 상대방이 보낸 인증서가 믿을 만한지 판별할 때 여기 있는 데이터랑 대조한다.

2. 인증서란?

인증서 = 데이터(공개키 + 주체/발급자 정보 등) + 발급자가 데이터에 서명한 값

인증서는 쉽게 말해서 데이터(공개키 + 발급자 정보 등)와 그 데이터의 해시값을 발급자의 비밀키로 전자서명한 값을 합쳐놓은 것이다. CA(공식 명칭, Certificate Authority)가 서명하면 CA 인증서, 자기가 자기를 서명하면 Self-signed 인증서라고 부른다.


3. 인증서의 두 가지 용도

인증서에는 두 가지 핵심 기능이 있다.

  • 암호화/복호화: 공개키로 암호화하고, 오직 나만 가진 개인키로 복호화해서 데이터를 안전하게 주고받는다.
  • 전자서명: 내가 내 개인키로 서명을 해서 보내면, 상대방이 나의 공개키로 복호화해 보면서 "아, 진짜 네가 보낸 게 맞구나"라고 검증하는 용도이다. (서명을 만들 때는 데이터를 해시 함수에 넣어서 해시값을 만들고 이걸 비밀키로 암호화한다. => 이걸 전자서명이라고 한다. 검증할 때는 받은 서명을 공개키로 복호화해서 해시값 A를 얻고, 받은 데이터를 직접 해시 함수에 넣어서 해시값 B를 만든다. 이 두 해시값이 일치하면 검증 성공이다.)

 

공동 인증서(한국) 파일 구성

  • 전자서명용
    • signCert.der: 전자서명용 인증서 (공개키+메타데이터+전자서명)
    • signPri.key: 전자서명용 개인키 (개인키로 서명)
  • 암호화용
    • kmCert.der: 암호화용 인증서 (공개키+메타데이터+전자서명), km은 Key Management의 약자
    • kmPri.key: 암호화용 개인키 (개인키로 암호화/복호화)

4. SSL과 TLS의 차이

SSL(Secure Sockets Layer)은 보안 취약점이 발견되어서 더 이상 사용하지 않는다. 지금은 TLS(Transport Layer Security)를 사용한다. TLS는 향상된 암호화 알고리즘을 사용해서 중간자 공격(MITM, Man-In-The-Middle)을 방지할 수 있다. 흔히 "SSL 인증서"라고 부르는 것도 실제로는 TLS 프로토콜을 사용한다.


5. 일반적인 SSL/TLS 방식 (단방향 인증)

우리가 흔히 쓰는 HTTPS는 서버만 인증하는 방식. 한국의 공동인증서와 달리 암호화/전자서명을 단일 인증서와 키로 진행 (tls 1.2 방식 기준이며 1.3의 경우 임시 비밀값 복호화 방식이 다르다)

  1. 3-way Handshake: 먼저 TCP 연결을 맺는다.
  2. 클라이언트 인사 (Client Hello): 클라이언트가 서버에 HTTPS 요청을 보낸다.
  3. 서버 인사 + 인증서 전달 (Server Hello + Server Certificate): 서버가 자신의 Keystore에 있는 인증서를 보낸다.
  4. 클라이언트의 서버 인증서 검증: 클라이언트는 Truststore에 미리 등록된 공개키로 서버 인증서를 대조해 본다. 인증서 데이터를 해싱한 값과, 전자서명을 공개키로 복호화한 값이 일치하면 "오케이, 믿을게!"가 된다.
  5. 클라이언트의 임시 비밀값 전달 (Client Key Exchange): 서버를 신뢰할 수 있으니 임시 비밀값을 생성해서 서버의 공개키로 암호화해서 보낸다 
  6. 서버의 임시 비밀값 복호화: 서버는 자기 Keystore에 있는 비밀키로 이 값을 복호화 한다.
  7. 세션키 생성 / TLS 통신 끝 (Finished): 이제 둘만 아는 임시 비밀값으로 실제 통신에 쓸 세션키를 각자 만든다.
  8. 암호화 통신 / 데이터 교환 시작: 세션키로 데이터를 주고받는다.

6. 양방향 인증, mTLS

일반적인 TLS는 클라이언트가 서버만 인증하는 방식이다. 반면 mTLS(Mutual TLS)는 서버도 클라이언트를 인증하는 양방향 인증 방식이다. (tls 1.2 방식 기준이며 1.3의 경우 임시 비밀값 복호화 방식이 다르다)

  1. 3-way Handshake + Client Hello: 위와 같음
  2. 서버 인사 + 인증서 전달 + 인증서 요청 (Server Hello + Server Certificate + Certificate Request): 서버가 자신의 Keystore에 있는 인증서를 보내고 클라이언트의 인증서를 요청한다.
  3. 클라이언트의 서버 검증 + 인증서 전달 + 임시 비밀값 전달 + tls 핸드셰이크 내용 서명
    • 클라이언트가 서버 인증서를 검증하고 성공하면 자기 인증서를 서버에 보낸다. 실패하면 바로 연결을 끊는다.
    • 곧이어 임시 비밀값을 생성해서 서버의 공개키로 암호화해서 보낸다.
    • 지금까지 주고 받은 메시지들을 해시한 값을 전자서명하여 전송한다. (서버는 임시 비밀키 교환 과정에서 복호화를 위해 비밀키를 사용하지만 클라이언트는 비밀키 사용 절차가 따로 없기에 여기서 클라이언트의 비밀키를 사용/검증하기 위한 과정이다)
  4. 서버의 클라이언트 검증 + 임시 비밀값 복호화 (Server Verify) + tls 핸드셰이크 내용 검증
    • 서버도 자신의 Truststore에 저장되어 있는 공개키로 클라이언트 인증서를 검증 한다. 실패하면 Alert를 보내고 연결을 끊는다.
    • 서버는 자기 Keystore에 있는 비밀키로 임시 비밀값을 복호화 한다
    • 받은 전자서명을 클라이언트 공개키로 복호화 한 값과 지금까지 주고 받은 메시지들을 해시한 값을 비교하여 검증한다
  5. 세션키 생성 / TLS 통신 끝 (Finished): 이제 둘만 아는 임시 비밀값으로 실제 통신에 쓸 세션키를 각자 만든다.
  6. 암호화 통신 / 데이터 교환 시작: 세션키로 데이터를 주고받는다.

7. CA 사용 여부에 따른 차이

  • CA(Certificate Authority)를 쓰는 경우: 내 Truststore에 CA 인증서만 넣어두면 된다. 그럼 상대방 인증서를 받았을 때 "이거 우리가 신뢰하는 CA가 서명한 거 맞아?"만 확인하며 CA가 서명한 모든 인증서를 알아서 믿어준다. 새로운 서버가 추가되더라도 같은 CA가 서명했으면 Truststore를 건드릴 필요가 없다.
  • 자가 서명(Self-signed) 인증서인 경우: 내가 직접 상대방의 인증서를 내 Truststore에 수동으로 등록해 줘야 한다.

 

 

+ Recent posts