使用OpenSLL
手工模拟证书验证
证书验证的公式为:
加密算法(证书主体)=pow(证书签名值, CA证书公钥参数exponent, CA证书公钥modulus)
1. 看一下证书的信息
首先,我们有一个证书cppreference.crt
,这是我们验证的目标证书。
openssl x509 -in cppreference.crt -text -noout # 查看证书内容
Certificate: Data: Version: 3 (0x2) Serial Number: 03:aa:56:73:8b:17:c7:40:02:94:df:ee:f9:35:cc:96:cc:55 Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, O=Let's Encrypt, CN=R11 Validity Not Before: Jul 15 07:30:51 2024 GMT Not After : Oct 13 07:30:50 2024 GMT Subject: CN=*.cppreference.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:e1:32:c1:05:92:7a:16:4c:eb:37:b3:bb:91:c1: 1f:9e:f7:41:16:8d:58:a6:1e:45:d9:a4:ca:93:1c: fd:2b:f2:97:f1:e6:49:41:5a:2a:b3:75:07:79:96: a5:60:da:68:4d:1e:df:60:22:16:11:80:30:c2:bf: 87:41:3c:d3:d6:91:80:de:b9:3b:e2:30:68:66:fe: 86:98:cd:e5:98:78:97:b2:0f:7e:ea:e8:c3:8d:c1: a7:8e:2f:f9:61:f6:e4:14:51:2a:64:91:0f:dd:3e: 7a:70:aa:65:68:f2:e0:7c:91:65:33:d2:e1:cf:2a: 58:74:9c:4d:a5:19:e9:43:eb:94:eb:c5:33:ce:95: c8:72:c2:8f:9d:b7:11:c5:25:f2:a1:fd:1c:ae:60: 4e:e4:10:2b:89:da:84:c3:0a:40:47:2a:07:3e:ea: 8b:92:e0:6b:79:87:65:6c:83:c7:62:6f:46:f9:49: 84:c8:8a:e6:f0:ae:e9:ae:c2:7b:b2:c0:82:5f:9d: a4:b5:f5:c6:1f:c5:40:69:44:1d:16:3b:16:28:01: a3:6b:77:06:03:f4:74:ea:fa:52:9d:c7:dc:14:ce: fc:5c:7e:24:8f:18:c3:7e:91:c2:b2:3e:f2:73:c8: 58:08:ed:d3:f0:50:ca:65:c8:d5:da:6a:6e:0e:1f: 5a:cb Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Key Identifier: 18:3F:BF:B7:5F:E7:98:31:29:1A:79:CE:0F:F4:C0:B0:83:74:5B:B6 X509v3 Authority Key Identifier: C5:CF:46:A4:EA:F4:C3:C0:7A:6C:95:C4:2D:B0:5E:92:2F:26:E3:B9 Authority Information Access: OCSP - URI:http://r11.o.lencr.org CA Issuers - URI:http://r11.i.lencr.org/ X509v3 Subject Alternative Name: DNS:*.cppreference.com, DNS:cppreference.com X509v3 Certificate Policies: Policy: 2.23.140.1.2.1 CT Precertificate SCTs: Signed Certificate Timestamp: Version : v1 (0x0) Log ID : 3F:17:4B:4F:D7:22:47:58:94:1D:65:1C:84:BE:0D:12: ED:90:37:7F:1F:85:6A:EB:C1:BF:28:85:EC:F8:64:6E Timestamp : Jul 15 08:30:51.371 2024 GMT Extensions: none Signature : ecdsa-with-SHA256 30:46:02:21:00:B4:D0:2D:4F:66:04:41:A2:22:99:4C: 2A:51:CE:C5:FE:26:7C:56:5B:12:3B:A0:33:A6:6B:FF: D7:7E:92:C6:49:02:21:00:EE:F0:0D:9E:A3:AB:62:22: DF:BE:75:89:2E:1D:CE:48:76:AC:EC:0E:A9:0F:B0:A7: AB:BA:28:89:58:5E:E1:19 Signed Certificate Timestamp: Version : v1 (0x0) Log ID : 19:98:10:71:09:F0:D6:52:2E:30:80:D2:9E:3F:64:BB: 83:6E:28:CC:F9:0F:52:8E:EE:DF:CE:4A:3F:16:B4:CA Timestamp : Jul 15 08:30:51.389 2024 GMT Extensions: none Signature : ecdsa-with-SHA256 30:45:02:21:00:C7:8A:32:CE:6E:DC:F4:56:2E:09:A5: 5E:E0:C1:B8:82:C8:62:6C:AD:95:D5:E7:16:AA:46:E0: DB:CA:21:DA:89:02:20:1D:61:E2:DF:81:97:63:99:A0: 07:AB:BB:EC:0E:1F:12:7E:FA:E7:2C:8E:FA:73:60:D5: 30:66:A7:7F:C7:B7:A5 Signature Algorithm: sha256WithRSAEncryption Signature Value: 26:6e:e3:c2:ad:e0:ea:0b:57:67:45:31:4d:6f:4a:0c:04:bb: 84:7c:04:6d:77:ff:43:8f:73:92:29:44:05:2d:18:b5:18:2d: ce:a2:32:44:fc:0a:ec:79:e8:68:05:be:51:85:b8:ef:e7:8c: 45:86:8d:30:c2:69:a1:b3:6d:0e:4f:7d:0b:37:64:18:1a:c5: 78:c2:ca:d1:22:1d:67:5f:4d:57:54:ac:44:9f:e4:10:f1:22: 4f:76:e3:f7:1d:cd:43:b7:a4:0f:5b:83:5f:d5:ae:23:38:09: c9:1c:76:20:e9:80:0d:d0:6f:02:5d:17:aa:3b:76:39:b7:f3: d9:f3:e2:50:6e:df:8d:a5:87:88:65:5c:c7:ba:8c:d4:e1:4e: b8:8f:70:22:7e:41:68:22:34:5a:fd:02:52:c8:eb:46:e7:06: e7:dd:15:7a:e2:39:39:3c:c5:80:0e:66:23:e1:c0:fc:d7:db: 3c:03:8b:1d:6e:8c:56:11:41:e4:4e:93:79:70:48:d4:e0:73: 85:71:56:3f:ae:9c:31:99:3c:04:f0:ac:bd:01:a5:e5:04:0c: 38:eb:0b:27:c7:98:8f:66:d4:60:a1:c2:b3:4a:81:3d:2b:4d: a1:c5:c3:c3:2f:3b:35:29:81:dd:34:aa:41:63:74:10:49:f3: 20:31:bb:fa
其中对我们有用的字段:
Signature Algorithm
:sha256WithRSAEncryption
。这表示此证书的签名算法是SHA256
和RSA
。Signature Value
: 证书的签名值。我们需要验证这个签名值是否正确。CA Issuers
:http://r11.i.lencr.org/
。证书签发者的信息。我们需要获取签发者的公钥来验证证书的签名值。
2. 获取证书主体
根据第一步,我们知道了证书的加密算法是SHA256
和RSA
,所以我们需要获取证书的主体信息。证书的主体信息是一个DER
编码的数据,我们可以通过openssl
工具来获取证书主体的偏移量和长度,将它保存到文件中。
openssl asn1parse -inform PEM -in cppreference.crt
通过openssl
命令,查看PEM
格式的证书的DER
编码数据。
0:d=0 hl=4 l=1287 cons: SEQUENCE 4:d=1 hl=4 l=1007 cons: SEQUENCE 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= 18 prim: INTEGER :03AA56738B17C7400294DFEEF935CC96CC55 33:d=2 hl=2 l= 13 cons: SEQUENCE 35:d=3 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 46:d=3 hl=2 l= 0 prim: NULL 48:d=2 hl=2 l= 51 cons: SEQUENCE 50:d=3 hl=2 l= 11 cons: SET 52:d=4 hl=2 l= 9 cons: SEQUENCE 54:d=5 hl=2 l= 3 prim: OBJECT :countryName 59:d=5 hl=2 l= 2 prim: PRINTABLESTRING :US 63:d=3 hl=2 l= 22 cons: SET 65:d=4 hl=2 l= 20 cons: SEQUENCE 67:d=5 hl=2 l= 3 prim: OBJECT :organizationName 72:d=5 hl=2 l= 13 prim: PRINTABLESTRING :Let's Encrypt 87:d=3 hl=2 l= 12 cons: SET 89:d=4 hl=2 l= 10 cons: SEQUENCE 91:d=5 hl=2 l= 3 prim: OBJECT :commonName 96:d=5 hl=2 l= 3 prim: PRINTABLESTRING :R11 101:d=2 hl=2 l= 30 cons: SEQUENCE 103:d=3 hl=2 l= 13 prim: UTCTIME :240715073051Z 118:d=3 hl=2 l= 13 prim: UTCTIME :241013073050Z 133:d=2 hl=2 l= 29 cons: SEQUENCE 135:d=3 hl=2 l= 27 cons: SET 137:d=4 hl=2 l= 25 cons: SEQUENCE 139:d=5 hl=2 l= 3 prim: OBJECT :commonName 144:d=5 hl=2 l= 18 prim: UTF8STRING :*.cppreference.com 164:d=2 hl=4 l= 290 cons: SEQUENCE 168:d=3 hl=2 l= 13 cons: SEQUENCE 170:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption 181:d=4 hl=2 l= 0 prim: NULL 183:d=3 hl=4 l= 271 prim: BIT STRING 458:d=2 hl=4 l= 553 cons: cont [ 3 ] 462:d=3 hl=4 l= 549 cons: SEQUENCE 466:d=4 hl=2 l= 14 cons: SEQUENCE 468:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Key Usage 473:d=5 hl=2 l= 1 prim: BOOLEAN :255 476:d=5 hl=2 l= 4 prim: OCTET STRING [HEX DUMP]:030205A0 482:d=4 hl=2 l= 29 cons: SEQUENCE 484:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Extended Key Usage 489:d=5 hl=2 l= 22 prim: OCTET STRING [HEX DUMP]:301406082B0601050507030106082B06010505070302 513:d=4 hl=2 l= 12 cons: SEQUENCE 515:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Basic Constraints 520:d=5 hl=2 l= 1 prim: BOOLEAN :255 523:d=5 hl=2 l= 2 prim: OCTET STRING [HEX DUMP]:3000 527:d=4 hl=2 l= 29 cons: SEQUENCE 529:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Subject Key Identifier 534:d=5 hl=2 l= 22 prim: OCTET STRING [HEX DUMP]:0414183FBFB75FE79831291A79CE0FF4C0B083745BB6 558:d=4 hl=2 l= 31 cons: SEQUENCE 560:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Authority Key Identifier 565:d=5 hl=2 l= 24 prim: OCTET STRING [HEX DUMP]:30168014C5CF46A4EAF4C3C07A6C95C42DB05E922F26E3B9 591:d=4 hl=2 l= 87 cons: SEQUENCE 593:d=5 hl=2 l= 8 prim: OBJECT :Authority Information Access 603:d=5 hl=2 l= 75 prim: OCTET STRING [HEX DUMP]:3049302206082B060105050730018616687474703A2F2F7231312E6F2E6C656E63722E6F7267302306082B060105050730028617687474703A2F2F7231312E692E6C656E63722E6F72672F 680:d=4 hl=2 l= 47 cons: SEQUENCE 682:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Subject Alternative Name 687:d=5 hl=2 l= 40 prim: OCTET STRING [HEX DUMP]:302682122A2E6370707265666572656E63652E636F6D82106370707265666572656E63652E636F6D 729:d=4 hl=2 l= 19 cons: SEQUENCE 731:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Certificate Policies 736:d=5 hl=2 l= 12 prim: OCTET STRING [HEX DUMP]:300A3008060667810C010201 750:d=4 hl=4 l= 261 cons: SEQUENCE 754:d=5 hl=2 l= 10 prim: OBJECT :CT Precertificate SCTs 766:d=5 hl=3 l= 246 prim: OCTET STRING [HEX DUMP]:0481F300F10077003F174B4FD7224758941D651C84BE0D12ED90377F1F856AEBC1BF2885ECF8646E00000190B58417EB0000040300483046022100B4D02D4F660441A222994C2A51CEC5FE267C565B123BA033A66BFFD77E92C649022100EEF00D9EA3AB6222DFBE75892E1DCE4876ACEC0EA90FB0A7ABBA2889585EE1190076001998107109F0D6522E3080D29E3F64BB836E28CCF90F528EEEDFCE4A3F16B4CA00000190B58417FD0000040300473045022100C78A32CE6EDCF4562E09A55EE0C1B882C8626CAD95D5E716AA46E0DBCA21DA8902201D61E2DF81976399A007ABBBEC0E1F127EFAE72C8EFA7360D53066A77FC7B7A5 1015:d=1 hl=2 l= 13 cons: SEQUENCE 1017:d=2 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 1028:d=2 hl=2 l= 0 prim: NULL 1030:d=1 hl=4 l= 257 prim: BIT STRING
第一部分是证书主体:
4:d=1 hl=4 l=1007 cons: SEQUENCE
证书主体的偏移为4
,头部长度为4
,长度为1007
。它的总长度是4 + 1007 = 1011
。接下来我们保存这个主体信息到文件中。
openssl asn1parse -inform PEM -in cppreference.crt -strparse 4 -out cppreference.tbs
3. 计算证书主体的哈希值
我们需要计算证书主体的哈希值,以便后续验证证书的签名值。我们使用SHA256
算法来计算证书主体的哈希值。
sha256sum cppreference.tbs
得到输出:
6789b428b183bb801f58f13a0b49ccc06f155e49d14cddfd0e82fa1abdc398ec cppreference.tbs
自此,我们得到了公式的左侧,接下来我们要使用CA证书来计算公式的右侧。
4. 下载CA证书
在第一步中,我们得到了CA证书的下载地址http://r11.i.lencr.org/
。我们可以通过curl
工具来下载CA证书。
curl http://r11.i.lencr.org/ -o ca.der
5. 获取CA证书的公钥
我们需要获取CA证书的公钥,以便后续验证证书的签名值。我们可以通过openssl
工具来获取CA证书的公钥。
CA证书的公钥部分通过先找到rsaEncryption
字段,然后找到它下方的BIT STRING
字段,这个字段就是CA证书的公钥。
openssl asn1parse -i -inform DER -in ca.der | grep -A 2 "rsaEncryption"
得到:
219:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption 230:d=4 hl=2 l= 0 prim: NULL 232:d=3 hl=4 l= 271 prim: BIT STRING
其中BIT STRING
字段的偏移量为232
,长度为271
。我们可以通过openssl
工具来提取CA证书的公钥。
openssl asn1parse -inform DER -in ca.der --strparse 232 -noout -out ca.rsa # 提取CA证书的公钥
openssl asn1parse -i -inform DER -in ca.rsa # 查看CA证书的公钥部分
查看后得到输出:
0:d=0 hl=4 l= 266 cons: SEQUENCE 4:d=1 hl=4 l= 257 prim: INTEGER :BA87BC5C1B0039CBCA0ACDD46710F9013CA54EA561CB26CA52FB1501B7B928F5281EED27B324183967090C08ECE03AB03B770EBDF3E53954410C4EAE41D69974DE51DBEF7BFF58BDA8B713F6DE31D5F272C9726A0B8374959C4600641499F3B1D922D9CDA892AA1C267A3FFEEF58057B089581DB710F8EFBE33109BB09BE504D5F8F91763D5A9D9E83F2E9C466B3E106664348188065A037189A9B843297B1B2BDC4F815009D2788FBE26317966C9B27674BC4DB285E69C279F0495CE02450E1C4BCA105AC7B406D00B4C2413FA758B82FC55C9BA5BB099EF1FEEBB08539FDA80AEF45C478EB652AC2CF5F3CDEE35C4D1BF70B272BAA0B4277534F796A1D87D9 265:d=1 hl=2 l= 3 prim: INTEGER :010001
其中:
- 第一个
INTEGER
字段是CA证书的公钥Modulus
。 - 第二个
INTEGER
字段是CA证书的公钥Exponent
。
6. 获取证书的签名值
接下来回到第一步中,我们得到了证书的签名值。我们需要提取证书的签名值。
openssl x509 -in cppreference.crt -text -noout | sed -n '/Signature Value:/,/^$/p' | sed 's/^ *//' | grep -v "Signature Value:" | tr -d ': \n'
获得输出:
266ee3c2ade0ea0b576745314d6f4a0c04bb847c046d77ff438f73922944052d18b5182dcea23244fc0aec79e86805be5185b8efe78c45868d30c269a1b36d0e4f7d0b3764181ac578c2cad1221d675f4d5754ac449fe410f1224f76e3f71dcd43b7a40f5b835fd5ae233809c91c7620e9800dd06f025d17aa3b7639b7f3d9f3e2506edf8da58788655cc7ba8cd4e14eb88f70227e416822345afd0252c8eb46e706e7dd157ae239393cc5800e6623e1c0fcd7db3c038b1d6e8c561141e44e93797048d4e0738571563fae9c31993c04f0acbd01a5e5040c38eb0b27c7988f66d460a1c2b34a813d2b4da1c5c3c32f3b352981dd34aa4163741049f32031bbfa
这个就是我们需要的证书的签名值。
7. 计算匹配
通过公式:
加密算法(证书主体)=pow(证书签名值, CA证书公钥参数exponent, CA证书公钥modulus)
我们编写一个python脚本来计算:
m=0xBA87BC5C1B0039CBCA0ACDD46710F9013CA54EA561CB26CA52FB1501B7B928F5281EED27B324183967090C08ECE03AB03B770EBDF3E53954410C4EAE41D69974DE51DBEF7BFF58BDA8B713F6DE31D5F272C9726A0B8374959C4600641499F3B1D922D9CDA892AA1C267A3FFEEF58057B089581DB710F8EFBE33109BB09BE504D5F8F91763D5A9D9E83F2E9C466B3E106664348188065A037189A9B843297B1B2BDC4F815009D2788FBE26317966C9B27674BC4DB285E69C279F0495CE02450E1C4BCA105AC7B406D00B4C2413FA758B82FC55C9BA5BB099EF1FEEBB08539FDA80AEF45C478EB652AC2CF5F3CDEE35C4D1BF70B272BAA0B4277534F796A1D87D9e=0x010001sig=0x266ee3c2ade0ea0b576745314d6f4a0c04bb847c046d77ff438f73922944052d18b5182dcea23244fc0aec79e86805be5185b8efe78c45868d30c269a1b36d0e4f7d0b3764181ac578c2cad1221d675f4d5754ac449fe410f1224f76e3f71dcd43b7a40f5b835fd5ae233809c91c7620e9800dd06f025d17aa3b7639b7f3d9f3e2506edf8da58788655cc7ba8cd4e14eb88f70227e416822345afd0252c8eb46e706e7dd157ae239393cc5800e6623e1c0fcd7db3c038b1d6e8c561141e44e93797048d4e0738571563fae9c31993c04f0acbd01a5e5040c38eb0b27c7988f66d460a1c2b34a813d2b4da1c5c3c32f3b352981dd34aa4163741049f32031bbfaprint("%x"%pow(sig, e, m))
输出结果:
1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004206789b428b183bb801f58f13a0b49ccc06f155e49d14cddfd0e82fa1abdc398ec
输出的结果中包含子串:
6789b428b183bb801f58f13a0b49ccc06f155e49d14cddfd0e82fa1abdc398ec
,此时证书的签名值和证书主体的哈希值是一致的,证明了证书的签名值是正确的。