HTTPS의 인증방식 → 인증서 만들기 → 인증서 서명의 정체에 대해 궁금해서 오게 되었습니다.
인증서를 서명할 때 어떤 데이터를 개인키로 암호화하는지?
인증서 서명을 공개키로 복호화하면 정말로 데이터를 해쉬한 값과 같은 해쉬값이 나오는지?
궁금하신 분들이 읽으면 좋습니다.
전자 서명 과정
위 그림은 전자 서명에 대한 그림입니다.
서명(Signing)은 Data를 해쉬(HASH)된 값으로 나타낸 뒤, 개인키로 RSA로 암호화하는 과정을 수행합니다.
검증(verification)에서는 공개키를 사용해 암호화를 복호화시킨 해쉬값과 Data를 해쉬로 변환한 값을 비교하여 검증합니다.
네이버 d2에 나와있는 이 그림이 가장 x509 인증서 서명을 잘 나타내고 있다고 생각해서 가져왔습니다.
인증서 발급 과정을 예로 든다면,
- 일련번호, 발급자, 공개키 등이 담긴 데이터(Data)를 Hash값으로 변환합니다.
- 공인된 기관이 "내가 이 데이터를 증명할게"라고 Hash값을 자신의 개인키로 서명(signing)합니다.
- 그리고 서명한 값(Signature) + 데이터(Data)를 합쳐서 인증서를 발급합니다.
인증서 검증 단계에서는,
- 웹브라우저가 서버로부터 전달된 인증서를 받습니다.
- 인증서는 상위 기관의 공개키를 가지고, 서명을 복호화하여 Hash값을 구합니다.
- 인증서 안에 존재하는 데이터(Data)를 Hash 함수를 통해 Hash값을 구합니다.
- 둘의 Hash값을 비교하여 인증서 검증(Verification)을 합니다.
그렇다면 도대체 어떤 데이터를 가지고 Hash값을 만들어서 비교를 하는 걸까요?
네이버의 인증서 가져오기
간단하게 naver의 인증서로 실습을 해보겠습니다.
HTTPS 인증을 사용하는 어느 사이트든 상관없습니다.
www.naver.com에 접속합니다. 그리고 크롬(chrome) 브라우저의 자물쇠 클릭⇒ 인증서(유효) 클릭에서 인증서의 정보를 손쉽게 볼 수 있습니다.
각기 다른 총 3개의 인증서와 함께 *. www.naver.com 인증서에서 서명이 보입니다.
- NAVER의 인증서에서 Hash로 변환하기 위한 데이터(Data)를 추출한 다음 Hash값으로 변환해보겠습니다.
- 그다음 DigCert SHA2 Secure Server CA의 공개키를 이용해 www.naver.com 서명을 복호화하겠습니다.
- 마지막으로 둘의 Hash값을 비교해 보겠습니다.
인증서 받기
제일 먼저 NAVER 인증서들을 파일로 저장해야 합니다.
$ openssl s_client -connect naver.com:443 -showcerts
다음 명령어를 치게 되면 PEM(Privacy Enhanced Mail) 형식으로 된 인증서들 뿐만 아니라 SSL-session 정보 등 HTTPS 인증 과정에 필요한 다양한 정보들을 터미널에 출력하게 됩니다.
여기에서 우리가 필요한 것은 NAVER 인증서와 상위 CA기관의 인증서 정보이므로 인증서 PEM 포맷 정보만 추출해야합니다.
Certificate chain
0 s:/C=KR/ST=Gyeonggi-do/L=Seongnam-si/O=NAVER Corp./CN=*.www.naver.com
i:/C=US/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA
-----BEGIN CERTIFICATE-----
MIIGqjCCBZKgAwIBAgIQBXW1HMsl/Jzvy25j/hpFKTANBgkqhkiG9w0BAQsFADBN
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E
aWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMjAwNTMwMDAwMDAwWhcN
[생략]
-----END CERTIFICATE-----
1 s:/C=US/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA
i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA
-----BEGIN CERTIFICATE-----
MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCB
[생략]
-----END CERTIFICATE-----
이와 같이 생긴 인증서 정보들이 보일 텐데, -----BEGIN CERTIFICATE----- 에서부터 -----END CERTIFICATE----- 까지 복사를 해줍니다.
0으로 시작하는 아래 부분이 NAVER의 인증서이며, 1로 시작하는 부분이 Secure Server CA의 인증서 부분입니다.
naver.crt, SecureServerCA.crt 두 개의 PEM형식의 인증서 파일을 만들었습니다.
x.509 v3 인증서의 기본 구조 살펴보기
먼저 x.509 v3 인증서의 기본 구조부터 살펴보겠습니다.
$ openssl x509 -text -noout -in naver.crt
openssl x509 명령어를 사용하여 사람이 이해하기 쉽게 인증서 내용을 볼 수 있습니다.
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
05:75:b5:1c:cb:25:fc:9c:ef:cb:6e:63:fe:1a:45:29
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, O=DigiCert Inc, CN=DigiCert SHA2 Secure Server CA
Validity
Not Before: May 30 00:00:00 2020 GMT
Not After : Jun 8 12:00:00 2022 GMT
Subject: C=KR, ST=Gyeonggi-do, L=Seongnam-si, O=NAVER Corp., CN=*.www.naver.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:db:54:be:14:9b:3c:13:a7:3b:da:2a:9b:e0:11:
생략
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Authority Key Identifier:
keyid:0F:80:61:1C:82:31:61:D5:2F:28:E7:8D:46:38:B4:2C:E1:C6:D9:E2
X509v3 Subject Key Identifier:
41:12:1A:42:FF:38:86:ED:2D:A0:29:66:E5:52:79:C6:FD:B4:A7:48
X509v3 Subject Alternative Name:
DNS:*.www.naver.com, DNS:www.naver.com
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://crl3.digicert.com/ssca-sha2-g6.crl
Full Name:
URI:http://crl4.digicert.com/ssca-sha2-g6.crl
X509v3 Certificate Policies:
Policy: 2.16.840.1.114412.1.1
CPS: https://www.digicert.com/CPS
Policy: 2.23.140.1.2.2
Authority Information Access:
OCSP - URI:http://ocsp.digicert.com
CA Issuers - URI:http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt
X509v3 Basic Constraints: critical
CA:FALSE
1.3.6.1.4.1.11129.2.4.2:
...k.i.v.F.U.u.. 0...i..}.,At..I.....p.mG...rfWx......G0E.!...9.iY.+f.-.y.[.....i..+..!.N.;.. zJ.....m.&....+..]].,E..5F.:T....w."EE.YU$V.?./..m..#&c..K.]..\n......rfWx......H0F.!....[.....1.^sI.......dFO......7:.!..U.B...C.......R3.4...=A..!......./g..ay..`.=&.T.`.Z8f.......
Signature Algorithm: sha256WithRSAEncryption
52:cd:2d:09:69:eb:10:56:d0:a1:aa:1c:a5:a6:c7:86:6d:58:
생략
서명 알고리즘이나, 발급자, version 등 인증서에 있는 실제 정보들을 볼 수 있습니다.
여기에서 사용되는 x.509 v3 인증서는 ASN.1(Abstract Syntax Notion number.1, 추상 구문 표기법을 따르고 있습니다.
ASN.1 은 데이터의 구성을 표현하는 문법으로 컴퓨터의 환경에 의존성이 없는 표기법 입니다. 추상적인 언어를 여러 인코딩(Encoding) 규칙으로 변환할 수 있는데, BER, DER, 등의 포맷으로 실제 물리적 데이터를 변활 할 수 있습니다.
x.509 인증서의 서명 데이터는 ASN.1 DER Encoding 규칙을 따르고 있습니다.
For signature calculation, the data that is to be signed is encoded using the ASN.1 distinguished encoding rules (DER) [X.690].
(참고 링크: https://tools.ietf.org/html/rfc5280#section-4.1)
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING }
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
extensions [3] EXPLICIT Extensions OPTIONAL
-- If present, version MUST be v3
}
Version ::= INTEGER { v1(0), v2(1), v3(2) }
CertificateSerialNumber ::= INTEGER
Validity ::= SEQUENCE {
notBefore Time,
notAfter Time }
Time ::= CHOICE {
utcTime UTCTime,
generalTime GeneralizedTime }
UniqueIdentifier ::= BIT STRING
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING }
Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
Extension ::= SEQUENCE {
extnID OBJECT IDENTIFIER,
critical BOOLEAN DEFAULT FALSE,
extnValue OCTET STRING
-- contains the DER encoding of an ASN.1 value
-- corresponding to the extension type identified
-- by extnID
}
다음은 https://tools.ietf.org/html/rfc5280#section-4.1 에 나와있는 x.509 v3 기본 인증서 형식입니다.
인증서 표준 규격 살펴보기
간단하게 필요한 부분만 간략하게 살펴보겠습니다.
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate, // 서명에 사용할 실제 데이터
signatureAlgorithm AlgorithmIdentifier, // 서명시 사용하는 알고리즘
signatureValue BIT STRING //실제 서명부분
}
X.509 v3 인증서(Certificate)는 3개의 필수 필드(tbsCertificate, signatureAlgorithm, signatureValue)로 이루어져 있습니다.
필수 필드를 차례대로 살펴보겠습니다.
tbsCertificate TBSCertificate,
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
extensions [3] EXPLICIT Extensions OPTIONAL
-- If present, version MUST be v3
}
TBSCertificate는 실제 서명에 사용하는 데이터 부분입니다. 주체(NAVER) 및 발급자(SecureServerCA)의 이름, 주체의 공개키(NAVER의 공개키)가 포함되어 있습니다. (참고 링크: https://tools.ietf.org/html/rfc5280#section-5.1.1.1)
실제로 이 데이터를 서명을 하는데, ASN.1 DER로 인코딩 된 데이터를 서명합니다. (TBS는 To Be Signed의 약자입니다.)
signatureAlgorithm AlgorithmIdentifier
signatureAlgorithm 필드는 인증서 발급자가 서명하는 데 사용하는 알고리즘의 식별자를 가지고 있습니다.
서명에서 어떤 RSA, DSA, ECDSA과 같은 단방향 Hash 함수를 사용했는지, Hash값을 어떤 암호 알고리즘으로 암호화했는지 식별할 수 있는 필드입니다.
위에서 -text옵션을 주고 살펴봤던 Signature Algorithm: sha256WithRSAEncryptio 에서 sha256WithRSAEncryptio 부분이 되겠네요. (참고 링크: https://tools.ietf.org/html/rfc5280#section-5.1.1.2)
signatureValue BIT STRING
실제 서명 값이 들어가는 필드입니다. HASH값이 RSA로 암호화되어 있는 값들이 존재하게 됩니다.
-text 옵션에서 보았던 52:cd:2d:09:69:eb:10:56:d0:a1:aa:1c:a5:a6:c7:86:6d:58:생략 이 부분입니다
(참고 링크: https://tools.ietf.org/html/rfc5280#section-5.1.1.3)
naver 인증서를 ASN.1 으로 살펴보기
그렇다면 우리가 다운받은 naver의 인증서를 ASN.1으로 나타내면 어떻게 구성되어 있을까요?
ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules(DER).
이를 위해서 먼저 PEM포맷의 인증서 파일을 DER(Distinguished Encoding Rules)로 변환을 해주는 게 ASN.1 인코딩 형식을 정의하는 x.690 표준입니다만,
$ openssl asn1parse -i -in naver.crt
openssl asn1parse를 사용하면 PEM 포맷을 알아서 해석하여 OFFSET 정보들을 볼 수 있습니다.
0:d=0 hl=4 l=1706 cons: SEQUENCE --- 외부 SEQUENCE
4:d=1 hl=4 l=1426 cons: SEQUENCE --- TBS(To Be Signed) 시작
8:d=2 hl=2 l= 3 cons: cont [ 0 ]
10:d=3 hl=2 l= 1 prim: INTEGER :02
13:d=2 hl=2 l= 16 prim: INTEGER :0575B51CCB25FC9CEFCB6E63FE1A4529
31:d=2 hl=2 l= 13 cons: SEQUENCE -- 어떤 알고리즘으로 서명했는지
33:d=3 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption
44:d=3 hl=2 l= 0 prim: NULL
46:d=2 hl=2 l= 77 cons: SEQUENCE -- CA기관의 이름
48:d=3 hl=2 l= 11 cons: SET
50:d=4 hl=2 l= 9 cons: SEQUENCE
52:d=5 hl=2 l= 3 prim: OBJECT :countryName
57:d=5 hl=2 l= 2 prim: PRINTABLESTRING :US
61:d=3 hl=2 l= 21 cons: SET
63:d=4 hl=2 l= 19 cons: SEQUENCE
65:d=5 hl=2 l= 3 prim: OBJECT :organizationName
70:d=5 hl=2 l= 12 prim: PRINTABLESTRING :DigiCert Inc
84:d=3 hl=2 l= 39 cons: SET
86:d=4 hl=2 l= 37 cons: SEQUENCE
88:d=5 hl=2 l= 3 prim: OBJECT :commonName
93:d=5 hl=2 l= 30 prim: PRINTABLESTRING :DigiCert SHA2 Secure Server CA
125:d=2 hl=2 l= 30 cons: SEQUENCE
127:d=3 hl=2 l= 13 prim: UTCTIME :200530000000Z
142:d=3 hl=2 l= 13 prim: UTCTIME :220608120000Z
157:d=2 hl=2 l= 105 cons: SEQUENCE
159:d=3 hl=2 l= 11 cons: SET
161:d=4 hl=2 l= 9 cons: SEQUENCE
163:d=5 hl=2 l= 3 prim: OBJECT :countryName
168:d=5 hl=2 l= 2 prim: PRINTABLESTRING :KR
172:d=3 hl=2 l= 20 cons: SET
174:d=4 hl=2 l= 18 cons: SEQUENCE
176:d=5 hl=2 l= 3 prim: OBJECT :stateOrProvinceName
181:d=5 hl=2 l= 11 prim: PRINTABLESTRING :Gyeonggi-do
194:d=3 hl=2 l= 20 cons: SET
196:d=4 hl=2 l= 18 cons: SEQUENCE
198:d=5 hl=2 l= 3 prim: OBJECT :localityName
203:d=5 hl=2 l= 11 prim: PRINTABLESTRING :Seongnam-si
216:d=3 hl=2 l= 20 cons: SET
218:d=4 hl=2 l= 18 cons: SEQUENCE
220:d=5 hl=2 l= 3 prim: OBJECT :organizationName
225:d=5 hl=2 l= 11 prim: PRINTABLESTRING :NAVER Corp.
238:d=3 hl=2 l= 24 cons: SET
240:d=4 hl=2 l= 22 cons: SEQUENCE
242:d=5 hl=2 l= 3 prim: OBJECT :commonName
247:d=5 hl=2 l= 15 prim: UTF8STRING :*.www.naver.com
264:d=2 hl=4 l= 290 cons: SEQUENCE
생략.
1434:d=1 hl=2 l= 13 cons: SEQUENCE --- 서명에 대한 정보
1436:d=2 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption
1447:d=2 hl=2 l= 0 prim: NULL
1449:d=1 hl=4 l= 257 prim: BIT STRING ---- 실제 서명 값 부분
d는 depth 깊이입니다. 0이면 가장 외부, 1이면 그 안에 있는 깊이, 2는 1안에 있는 깊이라고 생각하면 됩니다.
hl은 헤더의 길이, l은 내용의 길이입니다.
TBS는 OFFSET 4에서부터 depth 1로 시작합니다. 1426byte의 크기의 내용의 길이를 차지고 있습니다.
signatureAlgorithm은 OFFSET 1434에서부터 depth 1로 시작하고, 13byte 크기를 가지고 있습니다.
실제 서명이 들어가는 signatureValue은 OFFSET 1449에서 시작하고 257byte 크기를 가지고 있습니다.
d=1을 기준으로 인증서 파일을 나누어 본다면 총 3부분으로 나누어볼 수 있겠네요. 우리가 위에서 보았던 인증서의 필수 필드와 구조가 같습니다.
여기에서 의심해 봐야 할 부분은 signatureValue필드인 BIT STRING부분입니다. RSA알고리즘의 크기는 256byte 즉, 2048bit의 키로 암호화가 되었기 때문에 같은 크기인 256byte가 나와야 합니다.
그렇지만 여기에서는 257이라고 적혀 있네요. 콘텐츠가 8bit 배수가 아닐 때 00으로 패딩을 한다고 하는데, 자세한 건 모르겠네요.
여기에서 우리가 필요한 부분은 뒤의 52CD2D09EB1056D0...[생략] 입니다. 이 값은 실제 서명, 즉 signatureValue와 정확히 일치합니다.
NAVER 인증서에서 TBS 데이터 추출하기
TBS(To Be Sigend) 데이터는 그림에서 빨간 원형으로 표시해놓은 Data 부분과 일치합니다.
4:d=1 hl=4 l=1426 cons: SEQUENCE --- TBS(To Be Signed) 시작
TBS가 시작하는 OFFSET은 4입니다.
$ openssl asn1parse -in naver.crt -strparse 4 -out naver.tbs
-strparse offset 옵션을 쓰게 되면 구문을 분석해줍니다. TBS offset인 4를 옵션으로 넣어 줍니다.
다음 명령어로 정확히 TBS부분만 추출을 하여 DER 포맷으로 naver.tbs 파일로 저장합니다. 궁금하신 분은 hexdump나 hex editor로 열어서 확인을 해보면 됩니다.
$ hexdump naver.tbs
0000000 30 82 05 92 a0 03 02 01 02 02 10 05 75 b5 1c cb
0000010 25 fc 9c ef cb 6e 63 fe 1a 45 29 30 0d 06 09 2a
0000020 86 48 86 f7 0d 01 01 0b 05 00 30 4d 31 0b 30 09
[생략]
NAVER 인증서에서 서명 추출하기
서명(Signature)은 그림에서 빨간 원형으로 표시해 놓은 Signature 부분과 일치합니다.
1449:d=1 hl=4 l= 257 prim: BIT STRING ---- 실제 서명 값 부분
실제 서명이 들어가는 offset은 1449입니다.
$ openssl asn1parse -in naver.crt -strparse 1449 -out naver.sig
해당 offset을 가져옵니다. Error in encoding이라고 뜨지만(서명이 ASN.1 구문을 따르지 않기 때문), 파일을 확인해보면 패딩 값 0x00이 없는 256byte 크기로 저장이 됩니다.
$ hexdump naver.sig
0000000 52 cd 2d 09 69 eb 10 56 d0 a1 aa 1c a5 a6 c7 86
0000010 6d 58 c6 eb d0 b7 38 f2 cd ea a8 63 dc 96 d4 fd
0000020 d8 f5 84 04 ec c1 17 8c 42 a3 77 78 c5 77 a4 8f
[생략]
TBS 데이터를 Hash값으로 변환하기
위의 그림에서 TBS(To Be Signed) = Data 라고 생각하시면 됩니다.
그렇다면 어떤 Hash 함수를 써야 할까요?
우리는 위에서 이미 어떤 Hash를 써서 서명을 했는지 알고 있습니다.
1434:d=1 hl=2 l= 13 cons: SEQUENCE --- 서명에 대한 정보
1436:d=2 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption
sha256 Hash 함수를 사용했다고 나와 있습니다.
서명에서 사용한 데이터는 sha256 Hash 함수로 Hash화 했으며 RSA 암호화 알고리즘을 사용하였다고 생각하면 됩니다. (여기에서 RSA 암호화에 사용된 키는 SecureServerCA 서버의 개인키입니다)
$ openssl dgst -sha256 naver.tbs
SHA256(naver.tbs)= 008ece6bf752634e165b7fde2cdf6b786e4d98f7598468b666b343872c97428e
naver.tbs의 해쉬값이 나타나게 됩니다.
openssl sha256 <naver.tbs -binary >hash
hexdump hash
0000000 00 8e ce 6b f7 52 63 4e 16 5b 7f de 2c df 6b 78
0000010 6e 4d 98 f7 59 84 68 b6 66 b3 43 87 2c 97 42 8e
0000020
이 방식으로 hash값을 바이너리 파일로 저장할 수도 있습니다.
정말 맞는지 검증(Verification) 하기 위해 우리가 추출한 서명 파일인 naver.sig를 SecureServerCA.crt 인증서에 있는 공개키로 복호화해보겠습니다.
상위 CA기관의 공개키 추출하기
naver.sig라는 서명 파일을 저장하였고, 이제 복호화(Decrypt) 하기 위한 공개키가 필요합니다.
Self-Signed 인증서(예를 들면 Root CA)의 경우 자신의 공개키를 사용하면 되지만, 인증서 체인 구조에 따라 상위 기관의 공개키가 필요합니다.
$ openssl x509 -in SecureServerCA.crt -noout -pubkey > SecureServerCA.key
상위 기관의 공개키를 꺼내서 PEM 포맷으로 공개키를 저장을 해줍니다.
$ openssl pkey -in SecureServerCA.key -pubin -text -noout
키를 확인해보겠습니다.
openssl pkey -in SecureServerCA.key -pubin -text -noout
Public-Key: (2048 bit)
Modulus:
00:dc:ae:58:90:4d:c1:c4:30:15:90:35:5b:6e:3c:
82:15:f5:2c:5c:bd:e3:db:ff:71:43:fa:64:25:80:
생략.
58:9b
Exponent: 65537 (0x10001)
웹 브라우저에서 본 공개키 값과 정확히 일치합니다. 제대로 상위 기관의 공개키가 추출이 되었네요.
서명을 공개키로 해독하기
$ openssl rsautl -verify -pubin -inkey SecureServerCA.key -in naver.sig | hexdump
openssl rsautl을 사용하여 공개키로 서명을 검증할 수 있습니다.
-verfiy : 공개키와 함께 검증 (반대는 -sign 옵션)
-pubin: 공개키를 인풋으로 사용
-inkey: 키파일은 SecureServerCA.key
-in: 인풋 파일
0000000 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05
0000010 00 04 20 00 8e ce 6b f7 52 63 4e 16 5b 7f de 2c
0000020 df 6b 78 6e 4d 98 f7 59 84 68 b6 66 b3 43 87 2c
0000030 97 42 8e
0000033
파이프 라인으로 hexdump 사용했기 때문에 경우 위와 같이 바이너리 파일이 보이게 됩니다.
잘 찾아보면 00 8e ce 6b f7... 으로 시작하는 부분을 볼 수 있습니다.
SHA256(naver.tbs)= 008ece6bf752634e165b7fde2cdf6b786e4d98f7598468b666b343872c97428e
위에서 구한 hash값과 정확히 일치합니다.
openssl rsautl -verify -pubin -inkey SecureServerCA.key -in naver.sig \
| openssl asn1parse -inform der
0:d=0 hl=2 l= 49 cons: SEQUENCE
2:d=1 hl=2 l= 13 cons: SEQUENCE
4:d=2 hl=2 l= 9 prim: OBJECT :sha256
15:d=2 hl=2 l= 0 prim: NULL
17:d=1 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:008ECE6BF752634E165B7FDE2CDF6B786E4D98F7598468B666B343872C97428E
해당 바이너리 파일 또한 ASN.1 구문을 따르고 있기 때문에 asn1parse를 사용해서 보면 더 확실하게 보입니다.
offset 17에서 [HEX DUMP]의 값으로 naver.sig 서명의 HASH값이 보입니다.
TBS를 sha256 Hash 함수를 사용하여 나온 Hash값과 naver.sig 서명 파일을 상위 CA 기관의 공개키로 복호화하여 나온 Hash 값이 정확히 일치하는 것을 증명할 수 있습니다.
추가. openssl sha256로 검증하기
openssl sha256 <naver.tbs -verify SecureServerCA.key -signature naver.sig Verified OK
$ openssl sha256 <naver.tbs -verify SecureServerCA.key -signature naver.sig
Verified OK
이렇게 바로 검증해볼 수 있습니다.
참고 링크
https://medium.com/@ebuschini/a-journey-into-verifying-signatures-on-x-509-certificates-168a5bafaa14 - 참고 블로그
https://coinz.tistory.com/21 - ASN.1
https://d2.naver.com/helloworld/744920 - 네이버 어플리케이션의 전자 서명 원리
https://tools.ietf.org/html/rfc5280 rfc5280 문서
'전공 공부' 카테고리의 다른 글
[스위치 허브] ipTIME H508 - 개봉기 (0) | 2016.07.13 |
---|