OpenSSL!

SSL, TLS

  • SSL(Secure Sockets Layer) 보안 소켓 계층
    • 1990년대 넷스케이프(Netscape)에서 개발한 보안 프로토콜
    • SSL 2.0(1995), SSL 3.0(1996)으로 발전.
  • TLS(Transport Layer Security) 전송 계층 보안
    • SSL 3.0을 기반으로 IETF에서 표준화한 프로토콜.
    • TLS 1.3(2018, 최신 버전)

핸드쉐이크를 통해 세션키(대칭키)를 공유하고 세션키로 암호화 통신 하기 위한 방법이다.
해당 키 교환을 위한 핸드쉐이크를 PKI 기반으로 수행한다.

TLS 1.3 은 여러 키(클라이언트→서버, 서버→클라이언트)를 생성한다.

X.509

ITU-T(국제전기통신연합) 에서 정의한 공개 키 기반 구조(PKI, Public Key Infrastructure) 인증서 구조 표준.
Openssl 로 생성하는 인증서(공개키) 는 모두 대부분 X.509 표준을 따른다.

아래와 같은 구조로 정의되며 ASN.1(Abstract Syntax Notation One) 구조라한다.

Certificate ::= SEQUENCE {
    tbsCertificate       TBSCertificate,
    signatureAlgorithm   AlgorithmIdentifier,
    signatureValue       BIT STRING
}

TBSCertificate ::= SEQUENCE {
    version         [0]  INTEGER,              -- v1(0), v2(1), v3(2)
    serialNumber         INTEGER,              -- 인증서 일련번호
    signature            AlgorithmIdentifier,  -- 서명 알고리즘 (예: SHA256withRSA)
    issuer              Name,                  -- 발급자 정보 (CA의 DN)
    validity            Validity,              -- 유효 기간 (notBefore, notAfter)
    subject             Name,                  -- 소유자 정보 (DN)
    subjectPublicKeyInfo SubjectPublicKeyInfo, -- 공개 키와 알고리즘
    issuerUniqueID  [1]  IMPLICIT BIT STRING OPTIONAL, -- 발급자 고유 ID (선택)
    subjectUniqueID [2]  IMPLICIT BIT STRING OPTIONAL, -- 소유자 고유 ID (선택)
    extensions      [3]  Extensions OPTIONAL  -- 확장 필드 (v3에서 사용)
}

DN은 아래와 같은 정보가 포함된다.

  • Country Name (C): US
  • State or Province Name (ST): California
  • Locality Name (L): San Francisco
  • Organization Name (O): Example Inc.
  • Organizational Unit Name (OU): IT Department
  • Common Name (CN): www.example.com
  • Email Address: admin@example.com

X.509 는 CA 기반에서 동작하는 SSL/TLS 표준이다.
이외에도 이메일, Linux 패키지 서명할 때 사용하는 OpenPGP 같은 인증서 표준이 있다.

OpenSSL 기반 인증서 생성

테스트용으로 인증 기관에서 사용하는것 처럼 사설 루트 인증서(이하 RootCA) 를 생성,

  • ca.key: 루트 개인키
  • ca.crt: 루트 공개키(루트 인증서)

공인 RootCA 를 관리하는 공인 인증 기관(CA: Public Certificate Authority) 목록은 아래와 같다.

  • DigiCert - DigiCert Global Root G2
  • DigiCert - DigiCert Global Root CA
  • DigiCert - DigiCert High Assurance EV Root CA
  • Amazon - Amazon Root CA 1
  • Amazon - Amazon Root CA 2
  • Let’s Encrypt (ISRG) - Let’s Encrypt Authority X3 (이전, 지금은 X1/X2)
  • Let’s Encrypt (ISRG) - ISRG Root X1
  • Let’s Encrypt (ISRG) - ISRG Root X2 (신규)
  • Microsoft - Microsoft Root Certificate Authority 2011
  • Microsoft - Microsoft ECC Root Certificate Authority 2017
  • Google - GTS Root R1
  • Google - GTS Root R2
  • Google - GTS Root R3
  • Google - GTS Root R4
  • Apple - Apple Root CA

RootCA 의 개인키는 물리적 금고에서 보관중이라고 함.

OS 와 브라우저 설치 및 업데이트 과정에서 신뢰 저장소 에 공식 RootCA 를 저장 및 업데이트한다.

Root CA

아래 명령을 통해 사설 RootCA 를 생성.

openssl genrsa -out root_ca.key 2048
openssl req -x509 -new -key root_ca.key -days 3650 -out root_ca.crt \
  -subj "/C=KR/ST=Gyeonggi-do/L=Seongnam-si/\
O=Demo-Comp/OU=Demo-Service/\
CN=RootCA/emailAddress=kouzie@test.com"

Intermediate CA

보통 인증서는 루트 CA 가 바로 인증해주기 보단 2 단계정도를 레벨로 구성한다.
이때 중간에 있는 CA 기관들을 Intermediate CA 라 부른다.

Intermediate CA 역시 사설로 생성

  • intermediate_ca.key: 중간 CA 개인키
  • intermediate_ca.csr: 서명 요청서(Certificate Signing Request)
    • 중간 CA 의 공개키와 메타데이터를 서명한 파일.
    • 서명을 RootCA 에 제출, RootCA 가 서명한 중간 CA 공개키를 받기 위해 사용함.
  • intermediate_ca.crt: 중간 CA 공개키(중간 CA 인증서)
openssl genrsa -out intermediate_ca.key 2048
openssl req -new -key intermediate_ca.key \
  -out intermediate_ca.csr \
  -subj "/C=KR/ST=Gyeonggi-do/L=Seongnam-si/\
O=Demo-Comp/OU=Demo-Service/\
CN=IntermediateCA/emailAddress=kouzie@test.com"

intermediate_ca.csr 파일을 기반으로 서버 공개키(서버 인증서)를 CA 로 서명 및 생성

openssl x509 -req -in intermediate_ca.csr \
  -CA root_ca.crt \
  -CAkey root_ca.key \
  -CAcreateserial \
  -days 1825 \
  -out intermediate_ca.crt \
  -extensions v3_ca \
  -extfile <(cat <<EOF
[v3_ca]
basicConstraints = critical,CA:TRUE
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
EOF
)
  • -days 1825 RootCA 보단 유효기간을 짧게 설정해야함.
  • -CA root_ca.crt RootCA 공개키로 발급자 정보를 포함, 인증서에 RootCA 정보를 추가(체이닝)
  • -CAkey root_ca.key RootCA 개인키로 csr 파일에 서명
  • -CAcreateserial
    인증서의 고유식별자를 생성, ca.srl 파일에 저장.
  • extensions v3_ca 확장자 섹션 이름. 중간 CA로 동작하도록 설정. extfile <(cat <<EOF ... EOF) 사용하여 확장자 정의를 인라인으로 제공
[v3_ca]
# 인증서가 CA로 동작 가능(인증서 발급 권한 부여).
basicConstraints = critical,CA:TRUE
# digitalSignature: 디지털 서명 가능.
# cRLSign: CRL(인증서 폐지 목록) 서명 가능.
# keyCertSign: 다른 인증서 서명 가능.
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
# 인증서의 공개키에서 고유 식별자 생성.
subjectKeyIdentifier = hash
# 루트 CA의 키 식별자와 정보 포함, 신뢰 체인 추적에 사용.
authorityKeyIdentifier = keyid:always,issuer

명령을 수행하면 root_ca.srl(인증서 고유식별자 파일) 이 생성된다.
향후 Intermediate CA 의 폐기 필요시 인증서 폐기 리스트(Certificate Revocation List) 에 저장될 용도로 사용한다.

Server 인증서

Intermediate CA 를 통해 끝단에 위치하는 서버 인증서를 생성,

  • server.key: 서버 개인키
  • server.csr: 서버 서명 요청서(Certificate Signing Request)
    • 서버 공개키와 메타데이터를 서명한 파일.
    • 서명을 IntermediateCA 에 제출, IntermediateCA 가 서명한 서버 공개키를 받기 위해 사용함.
  • server.crt: 서버 공개키(서버 인증서)
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr \
  -subj "/C=KR/ST=Gyeonggi-do/L=Seongnam-si/\
O=Demo-Comp/OU=Demo-Service/\
CN=ServerCN/emailAddress=kouzie@test.com"

server.csr 파일을 기반으로 서버 공개키(서버 인증서)를 IntermediateCA 로 서명 및 생성

openssl x509 -req -in server.csr \
  -CA intermediate_ca.crt \
  -CAkey intermediate_ca.key \
  -CAcreateserial \
  -days 365 -out server.crt

명령을 수행하면 intermediate_ca.srl(인증서 고유식별자 파일) 이 생성된다.
향후 서버 인증서의 폐기 필요시 인증서 폐기 리스트(Certificate Revocation List) 에 저장될 용도로 사용한다.

인증서 파일 포맷 종류

-----BEGIN CERTIFICATE-----
MIIEDjCCAvagAwIBAgIUAMXlft1kCF7moTjpZsTFQi90OBgwDQYJKoZIhvcNAQEL
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE REQUEST-----
MIIC3TCCAcUCAQAwgZcxCzAJBgNVBAYTAktSMRQwEgYDVQQIDAtHeWVvbmdnaS1k
...
-----END CERTIFICATE REQUEST-----
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDUKO4G4+2QfGjP
...
-----END PRIVATE KEY-----

인증서 파일을 만들다 보면 위와같은 포멧, .crt, .pem 같은 확장자 암호 관련 파일이 생성된다.

  • crt(Certificate)
    • X.509 포멧 인증서 파일,
    • PEM 또는 DER 형식으로 인코딩됨.
    • 파일을 열었는데 깨진 문자열 혹은 이진 구조일 경우 DER, 16진수 형태일경우 PEM.
  • pem (Privacy Enhanced Mail)
    • 인증서/키 같은 보안 객체를 Base64로 인코딩하여 저장한 파일.
    • 대부분 crt 파일이 pem 형태로 인코딩되어있음.
  • cer
    • crt 파일과 동일한 역할을 한다.
    • Windows 기반 인증서 파일임을 구분하기 위해서 사용되는 확장자, crt 는 주로 유닉스/리눅스에서 사용.
  • .p12/.pfx
    • 인증서, 개인 키, CA 체인을 하나의 암호화된 파일에 저장하는 형식.
    • PKCS#12 포멧으로 바이너리 형식으로 저장.
    • 백업 또는 이동용으로 주로 사용.

공개 키 암호 표준(Public-Key Cryptography Standard, PKCS)

PKCS#1, PKCS#8, PKCS#10, PKCS#12 포멧은 PKI 에서 매우 자주 사용됨.

.key 확장자의 경우 PKCS#1 혹은 PKCS#8 .p12 확장자의 경우 PKCS#12

  • PKCS#1
    • RSA 개인키를 저장하는 가장 기본적인 형식
    • -----BEGIN RSA PRIVATE KEY----- 로 시작함
    • 아래 정보가 저장됨
version           INTEGER,  -- 0
modulus           INTEGER,  -- n
publicExponent    INTEGER,  -- e
privateExponent   INTEGER,  -- d
prime1            INTEGER,  -- p
prime2            INTEGER,  -- q
exponent1         INTEGER,  -- d mod (p-1)
exponent2         INTEGER,  -- d mod (q-1)
coefficient       INTEGER   -- (q^-1) mod p
  • PKCS#8
    • 개인 키를 저장하는 일반화된 표준, RSA뿐만 아니라 EC, DSA 등 다양한 알고리즘을 지원
    • PKCS#8 가 더 최신 포멧
    • -----BEGIN PRIVATE KEY----- 로 시작함
    • 아래 정보가 저장됨
version         INTEGER,              -- 0
algorithm       AlgorithmIdentifier,  -- 예: rsaEncryption
privateKey      OCTET STRING          -- PKCS#1 RSAPrivateKey 또는 다른 키 데이터
  • PKCS#10
    • 인증서 서명 요청 표준
    • -----BEGIN CERTIFICATE REQUEST----- 로 시작함
  • PKCS#12
    • 개인 정보 교환 구문 표준
    • 인증서, 개인 키, CA 체인을 하나의 암호화된 파일에 저장.
    • 바이너리 포멧

인증서 체인

대부분의 인증서는 RootCA, IntermediateCA 를 기반으로 보안성, 관리성을 위해 체인 형태로 제공된다.

1

실제 End-entity Certificate(Leaf Certificate) 파일을 openssl 명령어로 출력하면 아래와 같은데

openssl x509 -in _.tistory.com.pem -text -noout
# Certificate:
#    Data:
#        Version: 3 (0x2)
#        Serial Number:
#            0c:bd:1f:4c:fc:57:68:e7:92:4e:32:d2:2b:7d:c2:0f
#        Signature Algorithm: sha256WithRSAEncryption
#        Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=Thawte TLS RSA CA G1
#        Validity
#            Not Before: Mar  4 00:00:00 2025 GMT
#            Not After : Mar 30 23:59:59 2026 GMT
#        Subject: C=KR, ST=Jeju-do, L=Jeju-si, O=Kakao Corp., CN=*.tistory.com
#        Subject Public Key Info:
#            Public Key Algorithm: rsaEncryption
#                Public-Key: (2048 bit)
#                Modulus:
#                    00:8d:f3:6f:64:5d:94:72:bf:8e:0b:58:5c:f7:2c:
#                    ...
#                    e2:61
#                Exponent: 65537 (0x10001)
#        X509v3 extensions:
#            X509v3 Authority Key Identifier:
#                A5:8C:FE:32:CC:EB:0F:2C:D4:19:C6:08:B8:00:24:88:5D:C3:C5:B7
#            X509v3 Subject Key Identifier:
#                B6:CB:E6:47:D0:60:C3:CE:F3:C5:85:92:AA:6D:81:99:10:99:78:23
#            X509v3 Subject Alternative Name:
#                DNS:*.tistory.com, DNS:tistory.com
#            X509v3 Certificate Policies:
#                Policy: 2.23.140.1.2.2
#                  CPS: http://www.digicert.com/CPS
#            X509v3 Key Usage: critical
#                Digital Signature, Key Encipherment
#            X509v3 Extended Key Usage:
#                TLS Web Server Authentication, TLS Web Client Authentication
#            X509v3 CRL Distribution Points:
#                Full Name:
#                  URI:http://cdp.thawte.com/ThawteTLSRSACAG1.crl
#            Authority Information Access:
#                OCSP - URI:http://status.thawte.com
#                CA Issuers - URI:http://cacerts.thawte.com/ThawteTLSRSACAG1.crt
#            X509v3 Basic Constraints: critical
#                CA:FALSE
#            CT Precertificate SCTs:
#                Signed Certificate Timestamp:
#                    Version   : v1 (0x0)
#                    Log ID    : 96:97:64:BF:55:58:97:AD:F7:43:87:68:37:08:42:77:
#                                E9:F0:3A:D5:F6:A4:F3:36:6E:46:A4:3F:0F:CA:A9:C6
#                    Timestamp : Mar  4 00:09:58.545 2025 GMT
#                    Extensions: none
#                    Signature : ecdsa-with-SHA256
#                                30:45:02:21:00:D1:26:55:02:8F:84:2E:97:A4:69:06:
#                                ...
#                                22:DE:F9:E0:5D:DF:10
#                Signed Certificate Timestamp:
#                    Version   : v1 (0x0)
#                    Log ID    : 64:11:C4:6C:A4:12:EC:A7:89:1C:A2:02:2E:00:BC:AB:
#                                4F:28:07:D4:1E:35:27:AB:EA:FE:D5:03:C9:7D:CD:F0
#                    Timestamp : Mar  4 00:09:58.527 2025 GMT
#                    Extensions: none
#                    Signature : ecdsa-with-SHA256
#                                30:44:02:20:62:9C:4D:27:A9:A2:57:B5:17:F4:21:AC:
#                                ...
#                                D0:92:D0:5E:2B:A1
#                Signed Certificate Timestamp:
#                    Version   : v1 (0x0)
#                    Log ID    : 49:9C:9B:69:DE:1D:7C:EC:FC:36:DE:CD:87:64:A6:B8:
#                                5B:AF:0A:87:80:19:D1:55:52:FB:E9:EB:29:DD:F8:C3
#                    Timestamp : Mar  4 00:09:58.548 2025 GMT
#                    Extensions: none
#                    Signature : ecdsa-with-SHA256
#                                30:44:02:20:53:1A:08:2A:88:F4:CA:80:38:5E:3B:33:
#                                ...
#                                3D:2F:84:F0:63:43
#    Signature Algorithm: sha256WithRSAEncryption
#    Signature Value:
#        62:cf:3c:47:aa:92:6d:8c:b1:e4:60:df:a6:ac:1b:d0:18:9c:
#        ...
#        d1:4b:50:81

인증서 하나는 issure(서명자) 와 subject(주제) 로 구성된다.

Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=Thawte TLS RSA CA G1
Subject: C=KR, ST=Jeju-do, L=Jeju-si, O=Kakao Corp., CN=*.tistory.com

서버는 SSL 핸드셰이크(Handshake) 과정중에 전체 인증서 체인을 제공해야한다.
IntermeidateCA 인증서가 누락될 경우 클라이언트는 인증서 체인을 완성할 수 없어 검증에 실패하게 된다.

클라이언트는 ServerCA, IntermediaCA 를 순서대로 받으며 서명을 검증하고 최종적으로 신뢰 저장소에 있는 RootCA 를 통해 모든 인증서는 검증한다.

아래 명령을 통해 인증서 체인 목록을 확인할 수 있다.

openssl s_client -connect google.com:443 -showcerts
#Connecting to 142.250.206.206
#CONNECTED(00000005)
#depth=2 C=US, O=Google Trust Services LLC, CN=GTS Root R4
#verify return:1
#depth=1 C=US, O=Google Trust Services, CN=WE2
#verify return:1
#depth=0 CN=*.google.com
#verify return:1
#---
#Certificate chain
# 0 s:CN=*.google.com
#   i:C=US, O=Google Trust Services, CN=WE2
#   a:PKEY: id-ecPublicKey, 256 (bit); sigalg: ecdsa-with-SHA256
#   v:NotBefore: Mar 31 08:54:37 2025 GMT; NotAfter: Jun 23 08:54:36 2025 GMT
#-----BEGIN CERTIFICATE-----
#MIINZDCCDQmgAwIBAgIRANBmClal7OtcCYWduPzonj0wCgYIKoZIzj0EAwIwOzEL
#...
#Y8ukaMiA4vzXMLEIXueiK1Acw54EZnxp
#-----END CERTIFICATE-----
# 1 s:C=US, O=Google Trust Services, CN=WE2
#   i:C=US, O=Google Trust Services LLC, CN=GTS Root R4
#   a:PKEY: id-ecPublicKey, 256 (bit); sigalg: ecdsa-with-SHA384
#   v:NotBefore: Dec 13 09:00:00 2023 GMT; NotAfter: Feb 20 14:00:00 2029 GMT
#-----BEGIN CERTIFICATE-----
#MIICnjCCAiWgAwIBAgIQf/Mta0CdFdWWWwWHOnxy4DAKBggqhkjOPQQDAzBHMQsw
#...
#ONo=
#-----END CERTIFICATE-----
# 2 s:C=US, O=Google Trust Services LLC, CN=GTS Root R4
#   i:C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA
#   a:PKEY: id-ecPublicKey, 384 (bit); sigalg: RSA-SHA256
#   v:NotBefore: Nov 15 03:43:21 2023 GMT; NotAfter: Jan 28 00:00:42 2028 GMT
#-----BEGIN CERTIFICATE-----
#MIIDejCCAmKgAwIBAgIQf+UwvzMTQ77dghYQST2KGzANBgkqhkiG9w0BAQsFADBX
#...
#vepuoxtGzi4CZ68zJpiq1UvSqTbFJjtbD4seiMHl
#-----END CERTIFICATE-----
#---
#Server certificate
#subject=CN=*.google.com
#issuer=C=US, O=Google Trust Services, CN=WE2
#---
#No client certificate CA names sent
#Peer signing digest: SHA256
#Peer signature type: ECDSA
#Server Temp Key: X25519, 253 bits
#---
#SSL handshake has read 5315 bytes and written 401 bytes
#Verification: OK
#---
#New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
#Protocol: TLSv1.3
#Server public key is 256 bit
#This TLS version forbids renegotiation.
#Compression: NONE
#Expansion: NONE
#No ALPN negotiated
#Early data was not sent
#Verify return code: 0 (ok)
#---

google.com 의 경우 아래와 같이 [Server Cert] -> [Intermediate CA] -> [Root CA] 구조를 가진다.

depth=2 C=US, O=Google Trust Services LLC, CN=GTS Root R4
depth=1 C=US, O=Google Trust Services, CN=WE2
depth=0 CN=*.google.com

카테고리:

업데이트: