手动遍历证书的签名验证

信息安全 证书 公钥基础设施 证书颁发机构 RSA sha256
2021-08-29 05:23:50

CN=*wikipedia.org由于我对 Web of Trust 和 Public Key-Infrastructure 不太熟悉,我决定按照颁发给(序列号:)的 X.509 证书的签名链来了解它11:21:a2:25:ba:04:02:d7:91:85:48:54:c8:ba:60:68:6a:9b作为第一步,我想准确地遵循信任链一步。

我从浏览器中获得了.PEM格式的证书,并能够使用以下方式查看其纯文本内容

openssl x509 -in -.wikipedia.org -text -noout

然后,我通过从以下部分中列出的 url 检索颁发者证书来获得它:

Authority Information Access: 
    CA Issuers - URI:http://secure.globalsign.com/cacert/gsorganizationvalsha2g2r1.crt
    OCSP - URI:http://ocsp2.globalsign.com/gsorganizationvalsha2g2

使用wget http://secure.globalsign.com/cacert/gsorganizationvalsha2g2r1.crt.

第一个问题:这是获得*.wikipedia.org证书签署证书的正确方法吗?毕竟,我怎么能确定ẁikipedia.org没有向我提供虚假证书并在本节中列出一些虚假 CA 证书的 URL?网址甚至https看起来都不是......


假设我能够以这种方式获得正确的 CA 证书,我现在正在尝试验证-.wikipedia.org证书的真实性。根据RFC 5280

对于签名计算,要签名的数据使用 ASN.1 区分编码规则 (DER) 进行编码

所以我想我必须将格式的*.wikipedia.org证书转换为包含所有要签名的数据的表示?!.PEM.DER

第二个问题:要签名的数据是否与原始.PEM证书包含的数据相同?如果不是,缺少什么数据,即不签名?

第三个问题:哪个openssl命令用于从 CA 签名.PEM.DER表示转换?


假设我能够成功创建一个-.wikipedia.org.DER文件,然后我会尝试验证它的真实性。

据我了解,我将计算该文件的SHA-256哈希(证书显示:)Signature Algorithm: sha256WithRSAEncryption,然后使用 CA 的公共 RSA 密钥解密结果。然后我会获得一个签名并将其与我-.wikipedia.org文件中的签名进行比较。如果两者都匹配,我会确认认证的真实性。

第四个问题 这是正确的吗?假设我有,我怎么能手动回溯这个过程

  • 文件 -.wikipedia.org.DER

  • 文本格式的 CA 公钥:

     Subject Public Key Info:
         Public Key Algorithm: rsaEncryption
             Public-Key: (2048 bit)
             Modulus:
                 00:c7:0e:6c:3f:23:93:7f:cc:70:a5:9d:20:c3:0e:
                 53:3f:7e:c0:4e:c2:98:49:ca:47:d5:23:ef:03:34:
                 85:74:c8:a3:02:2e:46:5c:0b:7d:c9:88:9d:4f:8b:
                 f0:f8:9c:6c:8c:55:35:db:bf:f2:b3:ea:fb:e3:56:
                 e7:4a:46:d9:13:22:ca:36:d5:9b:c1:a8:e3:96:43:
                 93:f2:0c:bc:e6:f9:e6:e8:99:c8:63:48:78:7f:57:
                 36:69:1a:19:1d:5a:d1:d4:7d:c2:9c:d4:7f:e1:80:
                 12:ae:7a:ea:88:ea:57:d8:ca:0a:0a:3a:12:49:a2:
                 62:19:7a:0d:24:f7:37:eb:b4:73:92:7b:05:23:9b:
                 12:b5:ce:eb:29:df:a4:14:02:b9:01:a5:d4:a6:9c:
                 43:64:88:de:f8:7e:fe:e3:f5:1e:e5:fe:dc:a3:a8:
                 e4:66:31:d9:4c:25:e9:18:b9:89:59:09:ae:e9:9d:
                 1c:6d:37:0f:4a:1e:35:20:28:e2:af:d4:21:8b:01:
                 c4:45:ad:6e:2b:63:ab:92:6b:61:0a:4d:20:ed:73:
                 ba:7c:ce:fe:16:b5:db:9f:80:f0:d6:8b:6c:d9:08:
                 79:4a:4f:78:65:da:92:bc:be:35:f9:b3:c4:f9:27:
                 80:4e:ff:96:52:e6:02:20:e1:07:73:e9:5d:2b:bd:
                 b2:f1
             Exponent: 65537 (0x10001)
    
  • -wikipedia.org文本格式的证书签名:

     Signature Algorithm: sha256WithRSAEncryption
          b2:c6:af:4b:88:31:c2:44:33:37:20:48:01:71:06:81:39:a5:
          03:bc:16:0f:21:7b:29:23:62:a1:84:fc:d0:f5:f9:2d:0a:26:
          c6:dc:7f:a8:31:99:4f:05:ef:aa:ef:a9:82:b2:c3:68:f7:53:
          3a:0c:b7:ea:e8:a5:82:1d:da:75:98:c6:92:69:1c:15:34:8d:
          1c:1a:02:90:b6:f0:d1:fe:07:ee:0a:4f:75:5a:3b:25:6f:5f:
          fb:c6:6c:a6:bd:a3:bc:e2:6f:c8:0e:d7:c4:e6:a6:99:86:c7:
          24:b5:1a:e6:61:c3:86:13:59:e7:2b:44:57:64:f7:20:21:f6:
          e6:db:8f:e5:16:a5:48:06:1b:42:57:31:0c:9e:68:e6:a6:8e:
          61:0c:c2:08:a7:54:25:8b:33:7c:6a:e6:85:31:5c:da:22:6e:
          8b:65:7e:55:2f:9c:69:b3:2f:7e:59:7c:f5:e6:3e:23:28:91:
          05:2d:9e:fa:73:29:07:bb:c8:98:2e:32:5c:6e:38:74:4f:66:
          1e:a2:65:b7:2a:0d:e5:8f:da:6b:10:c7:2e:e4:a9:69:a2:98:
          77:76:9c:39:f6:e0:f6:dc:3c:b4:09:9e:03:eb:d7:93:26:d4:
          fe:a4:fd:46:82:13:14:3c:84:7f:15:e5:03:1e:b3:50:34:46:
          b0:f9:39:fb
    

我想手动完成这一切,以了解发生了什么。类似的东西

$ cat -.wikipedia.org.DER | sha256sum >> wikipedia.org.sha256
$ some-rsa-decryption-command --key some-key-format --output hex --input wikipedia.org.sha256
1个回答

这是一个很棒的想法 - 手动跟踪证书验证过程!我很喜欢阅读你的步骤,因为我自己从来没有真正做过!

回答您的问题:

第一个问题:这是获取 *.wikipedia.org 证书所用证书的正确方法吗?毕竟,我怎么能确定 ẁikipedia.org 没有向我提供虚假证书并在本节中列出一些虚假 CA 证书的 URL?该网址似乎甚至不是https...

是的,这是正确的方法。我认为您在这里缺少的关键理解是证书文件已经受到 CA签名的加密保护,这涉及计算证书中所有数据的哈希AIA,包括扩展中的 URL 。所以你知道这是维基百科打算让你看到的 URL,它不能被中间人修改,否则 CA 的签名将无法验证。

关于https:我们最近有一个客户试图https在他们的扩展中使用一个链接AIA,我们强迫他们重新颁发证书。原因是您正在尝试验证 的证书*.wikipedia.org,如果这样做需要您建立https连接,secure.globalsign.com那么您还必须验证他们的证书,以及他们的AIA扩展包含什么https链接?该链可能会变得很长,并导致网页需要几分钟才能加载 - 或导致https连接使用您尝试验证的证书的无限循环。不,.crt文件已经受到它们包含的 CA 签名的加密保护,无需在https此基础上添加。


第二个问题:要签名的数据是否与原始.PEM证书包含的数据相同?如果不是,缺少什么数据,即不签名?

您需要包含在证书中的所有数据,但是,您需要在计算哈希之前删除签名字段(请参阅我对下面第四个问题的回答)。

如果您从 CA 的角度考虑这一点,这是有道理的:他们在计算签名之前无法知道签名位是什么,因此需要将其从哈希中排除。签名就像信封上的蜡封,印章在外面


第三个问题:什么 openssl 命令用于将 .PEM 转换为从 CA 签署的 .DER 表示?

这个网页似乎很好地解决了这个问题:

DER 与 CRT 与 CER 与 PEM 证书以及如何转换它们

简而言之,使用-inform / -outform标志:

PEM 到 DER

openssl x509 -in cert.crt -outform der -out cert.der

DER 到 PEM

openssl x509 -in cert.crt -inform der -outform pem -out cert.pem

第四个问题:手动计算签名。

您的理解几乎是正确的;您计算自己的证书正文哈希(在本例中为 SHA256),然后使用父 (CA) 公钥验证该哈希与签名值。请注意,如果没有私钥,您将无法生成签名,而您没有也无法获得私钥;此外,虽然有些签名方案是确定性的,包括这里使用的,但有些签名方案不是,甚至私钥持有者(CA)也无法生成与旧签名相同的新签名。

证书的基本结构显示在Internet 上的 X.509 证书规范 rfc5280 中它实际上有四个部分:SEQUENCE 标记的 ASN.1 标头,包含所有命名tbsCertificate为“待签名”的缩写的“真实”信息的部分,AlgorithmIdentifier它指定签名的类型(在这种情况下sha256withRSA),以及实际签名为BIT STRING. 尽管这些字段是 DER 的一部分,但由于您有 openssl,因此可以使用openssl asn1parse默认为 PEM 输入(但混合输出)方便地访问它们。在这种情况下:

$ openssl asn1parse -i -in wikipedia.pem    -- comments added
    0:d=0  hl=4 l=1811 cons: SEQUENCE    -- this is the 'outer' SEQUENCE
    4:d=1  hl=4 l=1531 cons:  SEQUENCE    -- this is the beginning of TBS
    8:d=2  hl=2 l=   3 cons:   cont [ 0 ]
   10:d=3  hl=2 l=   1 prim:    INTEGER           :02     -- version minus one, so this is a v3 cert
   13:d=2  hl=2 l=  18 prim:   INTEGER           :1121A225BA0402D791854854C8BA60686A9B   -- serial 
   33:d=2  hl=2 l=  13 cons:   SEQUENCE    -- COPY of algorithmidentifier, see below
   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= 102 cons:   SEQUENCE    -- issuer (CA) name, in several pieces
   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   :BE
   63:d=3  hl=2 l=  25 cons:    SET
   65:d=4  hl=2 l=  23 cons:     SEQUENCE
   67:d=5  hl=2 l=   3 prim:      OBJECT            :organizationName
   72:d=5  hl=2 l=  16 prim:      PRINTABLESTRING   :GlobalSign nv-sa
   90:d=3  hl=2 l=  60 cons:    SET
   92:d=4  hl=2 l=  58 cons:     SEQUENCE
   94:d=5  hl=2 l=   3 prim:      OBJECT            :commonName
   99:d=5  hl=2 l=  51 prim:      PRINTABLESTRING   :GlobalSign Organization Validation CA - SHA256 - G2
[... much snipped, including the subject name (for Wikipedia), the key, and all the extensions ...]
 1539:d=1  hl=2 l=  13 cons:  SEQUENCE    -- this is the algorithmidentifier for the signature 
 1541:d=2  hl=2 l=   9 prim:   OBJECT            :sha256WithRSAEncryption
 1552:d=2  hl=2 l=   0 prim:   NULL
 1554:d=1  hl=4 l= 257 prim:  BIT STRING    -- this contains the signature value

请注意,TBS 从偏移量 4 开始,签名包装器从偏移量 1554 开始。现在执行

openssl asn1parse -in wikipedia.pem -strparse 4 -out wikipedia.tbs 

它(再次)显示所有 tbs,但它(以二进制形式)将其写入文件:

$ od -tx1 wikipedia.tbs
0000000 30 82 05 fb a0 03 02 01 02 02 12 11 21 a2 25 ba
0000020 04 02 d7 91 85 48 54 c8 ba 60 68 6a 9b 30 0d 06
0000040 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 66 31 0b
[snip rest]

相似地

$ openssl asn1parse -in wikipedia.pem -strparse 1554 -out wikipedia.sig
Error in encoding
3344:error:0D07207B:asn1 encoding routines:ASN1_get_object:header too long:.\crypto\asn1\asn1_lib.c:157:

显示错误,因为签名不是 ASN.1,但仍将其写入文件:

$ od -tx1 wikipedia.sig
0000000 b2 c6 af 4b 88 31 c2 44 33 37 20 48 01 71 06 81
0000020 39 a5 03 bc 16 0f 21 7b 29 23 62 a1 84 fc d0 f5
0000040 f9 2d 0a 26 c6 dc 7f a8 31 99 4f 05 ef aa ef a9
0000060 82 b2 c3 68 f7 53 3a 0c b7 ea e8 a5 82 1d da 75
0000100 98 c6 92 69 1c 15 34 8d 1c 1a 02 90 b6 f0 d1 fe
0000120 07 ee 0a 4f 75 5a 3b 25 6f 5f fb c6 6c a6 bd a3
0000140 bc e2 6f c8 0e d7 c4 e6 a6 99 86 c7 24 b5 1a e6
0000160 61 c3 86 13 59 e7 2b 44 57 64 f7 20 21 f6 e6 db
0000200 8f e5 16 a5 48 06 1b 42 57 31 0c 9e 68 e6 a6 8e
0000220 61 0c c2 08 a7 54 25 8b 33 7c 6a e6 85 31 5c da
0000240 22 6e 8b 65 7e 55 2f 9c 69 b3 2f 7e 59 7c f5 e6
0000260 3e 23 28 91 05 2d 9e fa 73 29 07 bb c8 98 2e 32
0000300 5c 6e 38 74 4f 66 1e a2 65 b7 2a 0d e5 8f da 6b
0000320 10 c7 2e e4 a9 69 a2 98 77 76 9c 39 f6 e0 f6 dc
0000340 3c b4 09 9e 03 eb d7 93 26 d4 fe a4 fd 46 82 13
0000360 14 3c 84 7f 15 e5 03 1e b3 50 34 46 b0 f9 39 fb
0000400

-text请注意,这与您获得证书时以十六进制显示的值相同。现在从父证书获取公钥,以 PEM 格式与 openssl 一起使用:

$ openssl x509 -in globalsignv2.pem -noout -pubkey >globalsignov2.pub
$ openssl pkey -in globalsignv2.pub -pubin -text
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxw5sPyOTf8xwpZ0gww5T
P37ATsKYScpH1SPvAzSFdMijAi5GXAt9yYidT4vw+JxsjFU127/ys+r741bnSkbZ
EyLKNtWbwajjlkOT8gy85vnm6JnIY0h4f1c2aRoZHVrR1H3CnNR/4YASrnrqiOpX
2MoKCjoSSaJiGXoNJPc367RzknsFI5sStc7rKd+kFAK5AaXUppxDZIje+H7+4/Ue
5f7co6jkZjHZTCXpGLmJWQmu6Z0cbTcPSh41ICjir9QhiwHERa1uK2OrkmthCk0g
7XO6fM7+FrXbn4Dw1ots2Qh5Sk94ZdqSvL41+bPE+SeATv+WUuYCIOEHc+ldK72y
8QIDAQAB
-----END PUBLIC KEY-----
Public-Key: (2048 bit)
Modulus:
    00:c7:0e:6c:3f:23:93:7f:cc:70:a5:9d:20:c3:0e:
    53:3f:7e:c0:4e:c2:98:49:ca:47:d5:23:ef:03:34:
    85:74:c8:a3:02:2e:46:5c:0b:7d:c9:88:9d:4f:8b:
    f0:f8:9c:6c:8c:55:35:db:bf:f2:b3:ea:fb:e3:56:
    e7:4a:46:d9:13:22:ca:36:d5:9b:c1:a8:e3:96:43:
    93:f2:0c:bc:e6:f9:e6:e8:99:c8:63:48:78:7f:57:
    36:69:1a:19:1d:5a:d1:d4:7d:c2:9c:d4:7f:e1:80:
    12:ae:7a:ea:88:ea:57:d8:ca:0a:0a:3a:12:49:a2:
    62:19:7a:0d:24:f7:37:eb:b4:73:92:7b:05:23:9b:
    12:b5:ce:eb:29:df:a4:14:02:b9:01:a5:d4:a6:9c:
    43:64:88:de:f8:7e:fe:e3:f5:1e:e5:fe:dc:a3:a8:
    e4:66:31:d9:4c:25:e9:18:b9:89:59:09:ae:e9:9d:
    1c:6d:37:0f:4a:1e:35:20:28:e2:af:d4:21:8b:01:
    c4:45:ad:6e:2b:63:ab:92:6b:61:0a:4d:20:ed:73:
    ba:7c:ce:fe:16:b5:db:9f:80:f0:d6:8b:6c:d9:08:
    79:4a:4f:78:65:da:92:bc:be:35:f9:b3:c4:f9:27:
    80:4e:ff:96:52:e6:02:20:e1:07:73:e9:5d:2b:bd:
    b2:f1
Exponent: 65537 (0x10001)

你可以明确地做哈希并检查:

$ openssl sha256 <wikipedia.tbs -binary >hash
$ od -tx1 hash
0000000 71 fe 9a 8d 6a e2 85 7e f7 b4 be 22 a8 9e fb 4b
0000020 88 a2 e1 c9 c4 72 ef 65 40 07 77 54 4d 89 ef 38
0000040
$ openssl pkeyutl -verify -in hash -sigfile wikipedia.sig -inkey globalsignov2.pub -pubin -pkeyopt digest:sha256
Signature Verified Successfully

或者 openssl 可以作为一个单一的操作来完成

$ openssl sha256 <wikipedia.tbs -verify globalsignov2.pub -signature wikipedia.sig
Verified OK

请注意,这甚至适用于 RSA 以外的其他签名算法,特别是 DSAECDSA

祝你这样做,祝你未来学习好运!


我知道您只是在询问签名验证,但为了完整起见,我还应该提到您需要检查证书的有效期以确保它没有过期。并且您需要检查它没有被撤销,这要复杂得多:您需要获得相关的 CRL 或 OCSP 响应,这可能是另一个(http)请求,尽管有些服务器(包括en.wikipedia.org) 确实在握手中提供 OCSP 响应,称为“装订”。这两个也是签名对象,因此您需要使用 CRL 或 OCSP 颁发者的证书链来解析和验证它们,这通常与服务器证书的链不同。并且您需要为每个中间证书重复此过程,直到您到达您或某人(如 Microsoft、Apple 或 Mozilla 或 Debian)在您的系统中配置为受信任的根或其他“锚”。并且您需要检查链中的每个证书是否具有适当的 KeyUsage(和 ExtendedKeyUsage,如果存在)和适当的 BasicConstraints,并且可能检查 Policies 和 PolicyConstraints(如果使用),NameConstraints(如果使用)等等。再看rfc5280用于验证证书的基本算法:这是 19 页加上 5 页用于撤销旧方式 (CRL) 以及更多用于新方式 (OCSP) 的其他地方。你不高兴我们有浏览器来为我们做这件事吗?