从数学到密码学(十八)

数字证书、CA及PKI(一)

经过前面几节的铺垫,我们终于可以对数字证书好好剖析一番了。

再次回顾,什么是数字证书?答曰:证明某某人拥有某公钥的一份数字文件。既然是证明文件,证明人(又称证书颁发者)的身份是必不可少的,即数字证书中也要包含颁发者的信息。当然,文件中还必须包括:被证明人的身份(是谁,叫什么名字)和持有的公钥,即要证明的主要内容。此外,还可能包括其他的一些辅助信息。

下面就以笔者PC上的一个证书文件sslclientcert.pem为例,进行说明。其实际内容如下(用Windows自带的记事本NotePad打开)

-----BEGIN CERTIFICATE-----
MIICkzCCAfygAwIBAgIJAJ2iQkqialHfMA0GCSqGSIb3DQEBBQUAMEsxCzAJBgNV
BAYTAkNOMQswCQYDVQQIEwJCSjEUMBIGA1UEChMLTmV0U2VjdXJpdHkxDDAKBgNV
BAsTA1NTTDELMAkGA1UEAxMCQ0EwHhcNMTExMTAzMTY1MDUxWhcNMTIxMTAyMTY1
MDUxWjBPMQswCQYDVQQGEwJDTjELMAkGA1UECBMCQkoxFDASBgNVBAoTC05ldFNl
Y3VyaXR5MQwwCgYDVQQLEwNTU0wxDzANBgNVBAMTBkNsaWVudDCBnzANBgkqhkiG
9w0BAQEFAAOBjQAwgYkCgYEAse122kpIc84wlQz9KU6Rn5bmsGyROkk/54yBoda3
U3Bz1UxMPYzyZyZA0Plfjl60mLWLsX2viIpD78ZqzXuchBQ62eEufu7T0H3MJ/Sw
Kmgh0/Abezbmb3TJG3ZBvM335zUi8yP4uSLDxWKIXlpllkaBoMxRdN8tKKhe1sfQ
7TcCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH
ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFBNzwfdnDvwbcADgp60y00vt
VRajMB8GA1UdIwQYMBaAFE/E6zIXLFGHCuph0HA3K7BEmV+aMA0GCSqGSIb3DQEB
BQUAA4GBABPUy3yKdjo/eloidLPJ+GtdWVl8l9I8dKU/hQLb83gv25sC3eOrkOoC
Oyq82fyAImrOZyRyh7p9Tc1ueT9jwLGdKRkSlgnbvfeoBZhvLkKep7HS5RTjitmQ
cU808MqVDkISmGOau6SAeSj+SS0mXpOFDjOc1nXTocEoAtiwMbIs
-----END CERTIFICATE-----

能看出上面的内容吗?看不出。我们再次请出密码学工具中的瑞士军刀----openssl,让它以另外一种格式展现给我们。执行下列命令

openssl base64 -d -in sslclientcert.pem > sslclientcert.cer
(还有一种办法,Windows下双击sslclientcert.pem,选择"复制到文件",在随后出现的证书导出对话框中,选择"DER编码",保存文件,最终也能得到同样的结果)

上述命令的结果保存在文件 sslclientcert.cer 中。用记事本打开该文件,更加看不明白,都变成了乱码。
下面就是其中一部分的十六进制显示(仅显示前面和后面的部分)

00000000h: 30 82 02 93 30 82 01 FC A0 03 02 01 02 02 09 00
00000010h: 9D A2 42 4A A2 6A 51 DF 30 0D 06 09 2A 86 48 86
00000020h: F7 0D 01 01 05 05 00 30 4B 31 0B 30 09 06 03 55
00000030h: 04 06 13 02 43 4E 31 0B 30 09 06 03 55 04 08 13
00000040h: 02 42 4A 31 14 30 12 06 03 55 04 0A 13 0B 4E 65
00000050h: 74 53 65 63 75 72 69 74 79 31 0C 30 0A 06 03 55
00000060h: 04 0B 13 03 53 53 4C 31 0B 30 09 06 03 55 04 03
           ......
00000200h: 44 99 5F 9A 30 0D 06 09 2A 86 48 86 F7 0D 01 01
00000210h: 05 05 00 03 81 81 00 13 D4 CB 7C 8A 76 3A 3F 7A
00000220h: 5A 22 74 B3 C9 F8 6B 5D 59 59 7C 97 D2 3C 74 A5
00000230h: 3F 85 02 DB F3 78 2F DB 9B 02 DD E3 AB 90 EA 02
00000240h: 3B 2A BC D9 FC 80 22 6A CE 67 24 72 87 BA 7D 4D
00000250h: CD 6E 79 3F 63 C0 B1 9D 29 19 12 96 09 DB BD F7
00000260h: A8 05 98 6F 2E 42 9E A7 B1 D2 E5 14 E3 8A D9 90
00000270h: 71 4F 34 F0 CA 95 0E 42 12 98 63 9A BB A4 80 79
00000280h: 28 FE 49 2D 26 5E 93 85 0E 33 9C D6 75 D3 A1 C1
00000290h: 28 02 D8 B0 31 B2 2C

为什么会这样?好象搞得越来越复杂。事实是,这使我们离真相更近了一步。

接下来,我们请出另一个工具asn1dump,试图把真相的面纱完全揭开。用asn1dump打开前面得到的文件sslclientcert.cer,出现如下界面  

看出什么没有?原来证书(即sslclientcert.cer)的内容,从表面上看,是没有什么规律的乱码,实际上具有树形的内在结构(见上图的左边树形目录)。

那文件sslclientcert.cer的内容究竟是怎么组织的?
原来它遵循大名鼎鼎的X.509证书格式----这是数字证书的标准,请参考RFC 2459《Internet X.509 Public Key Infrastructure Certificate and CRL Profile》
该标准可以在RFC官方网站免费下载,这里就不详细说明。我们所要做的就是,对比RFC标准和证书的树形结构,来看看证书中不同部分所对应的内容。

由上图可以看到,证书文件的内容分为三部分。第一部分,包括证书的基本信息(即被证明的内容),比如:证书版本、证书序列号、证书颁发者、证书有效期、公钥、公钥持有人身份等主要信息。见下图

第二部分,是生成签名的算法,证书中显示,签名算法是sha1WithRSAEncryption。见下图

这里解释下sha1WithRSAEncryption。RSA我们知道可以作为一种签名算法,那这个sha1又代表什么,它有什么作用?
这与公钥签名算法的具体实现密切相关,此处做一个简单的介绍。理论上,要签名的消息依赖于具体内容长短不一,可以短到一个字节,也可以长到几K,几M,甚至几G几T字节。如果很长(比如几M),则消息内容会超出签名的运算长度。比如用RSA算法做一次签名计算,其实是做一次模指数运算,它所接受消息的长度必须<=模的长度(模的长度是RSA密钥的一个重要参数,比如RSA1024等),不熟悉的朋友可以参考以前的章节。那计算长消息的签名怎么办?一个办法就是分段计算,以RSA模长1024为例,将待签名的消息按1024位分为一段一段,每段消息都分别计算对应的签名(最后一段如果不足1024位则直接计算),然后将所有的分段签名连起来作为一个签名整体。与此对应,验证签名的时候也分段验证,所有的签名段都验证通过后才算整个消息验证通过。

以上方法的缺点显而即见,签名和消息一样长,显得很不方便。想想我们平常生活中的签名,不管是一本书或一项纸,签名的内容要么龙飞凤舞写几个字,要么一个章就搞定,决不会出现签名和待签名消息一样长的问题。此外还有一个比较实际的问题,就是一般而言,签名运算都比较耗费CPU的运算时间。

能不能做到:不管待签名的消息多长,生成的签名都一样长?
密码学家又给我们提供了工具,HASH算法。常用的HASH算法包括:MD5/SHA1/SHA256等。BTW,HASH算法都是公开的。

从数学角度上看,HASH函数不过是一个特殊点的函数y=f(x):输入任意长度的内容x,都输出固定长度内容y。比如MD5输出是128位,SHA1是160位。
除了任意长输入、固定长输出外,它还具有以下特性
1、根据x计算y,很快很容易---- 正向计算容易
2、随机(请注意措词)给出一个y,找到x满足f(x)=y很困难。---- 反向求解困难
    说明:你不能先选定x,求解y,再告诉我说找到x满足f(x)=y很容易。所以才着重随机二字。
            你如果不信,我现给出MD5值:a3ab18fd048c2f330a72af1f7c916f71,你能找到对应的x是什么吗----我们在本节尾给出答案
            顺便说下,MD5算法已经不算安全了(违反了下面第3点)----请GOOGLE王小云。这里只是举个例子。
3、要找到一对不同的x1、x2,满足f(x1)=f(x2)很困难。也就是说,任意两个不同的x,对应的y几乎肯定不相同----几乎没有碰撞
    说明:理论上,肯定存在两条不同的消息产生碰撞,比如你计算所有21字节长的消息的MD5值,根据抽屉原理,至少有2条消息,其HASH值相同。
            从这个意义上说,一条消息的HASH值,就像人类的指纹一样,消息内容不同,HASH值也几乎不同。

满足以上3个条件的HASH算法非常少,当然一旦满足,则在密码学上具有非常重要的意义,下面我们举几个例子进行说明
1、完整性校验。网站上一些免费光盘镜像,通常都附有整个镜像文件的HASH值。我们把文件下载后,利用工具(自然是openssl)计算其HASH值。再对比网站上公布的HASH值,就知道下载的文件是不是完整的。这利用了第3个特性:在很难找到产生碰撞的背景下,如果x1和x2的HASH值相同,则x1=x2几乎肯定成立。
2、设立遗嘱。一个老人生前就把他的遗嘱拟好了(内容一般包括子女财产分割等敏感内容),因为现实原因,生前不好提前公开,只有等老人过世后才把遗嘱内容公开。这时可以把遗嘱的HASH在生前公开,同时将遗嘱内容秘密交由公证机构保管。等他去世后,公证机构公开遗嘱内容,老人的子女都可以通过计算比较HASH值来判断遗嘱内容是否为真。
这利用了HASH算法的第2个特性----通过HASH值不能反推原内容。这个特性也可以保护用户登录密码的安全,在管理员无法查看用户密码的情况下用户也可以登录,关键就在于不比较密码的内容,而是比较密码的HASH值。有兴趣的同学可以GOOGLE之。

那么在证书中出现的HASH算法起什么作用呢?答案是:我们把它当作被签名消息的指纹,不直接对原消息进行签名,而是对该消息的HASH值进行签名。也就是说,先把待签名的消息HASH一把,再对HASH值进行签名运算。由于HASH值长度通常小于公钥长度,所以进行RSA签名运算成为可能,这就达到了我们的目的,不必对原消息直接签名。

那么引入HASH后,签名算法的安全性有没有保障呢?下面我们以RSA算法为例进行说明(事实上适用于所有公钥签名算法)。
根据前面的结论,正确的RSA消息、签名对(m,s)满足
se=m(mod n),其中e,n分别是加密指数和模,按刚才的描述,该验证公式改为
se=HASH(m)(mod n)
我们分析一下,求解消息m的签名s,攻击者需要先计算HASH(m),然后再得到HASH值的e次根,这是RSA算法安全的数学基础,到目前为止还未被攻破。
这说明攻击者的难度丝毫没有减少。对于密钥对持有人,签名计算过程也变化不大:原来是计算s=md(mod n),现在改为计算s=HASH(m)d(mod n)
综上所述,RSA签名算法引入安全的HASH算法后,安全性是有保障的。
---- 为什么要强调安全的HASH算法,因为如果两条消息m1,m2的HASH值相同,则其签名值相同,这会造成困扰,其弱点请参考维基百科中的MD5条目。

关于HASH算法,我们就此打住,回到前文,继续分析证书结构。

第三部分,则是证书中最重要的签名部分。见下图


根据RFC,如果签名人(即CA)的公钥可信,则可以通过验证证书的签名部分(即第三部分signatureValue)来确认证书基本信息部分(即第一部分tbsCertificate)的真伪。
而CA生成签名是依据第二部分(signatureAlgorithm)中指定的签名算法,此例中是sha1WithRSAEncryption。

以上是对证书的大概介绍,我们再通过openssl详细看一下证书包含什么内容,命令如下
openssl x509 -in sslclientcert.pem -text
下面文字中黑色部分和蓝色部分是openssl命令输出,红色部分是解释说明,蓝色部分是对应的内容。
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            9d:a2:42:4a:a2:6a:51:df
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=CN, ST=BJ, O=NetSecurity, OU=SSL, CN=CA  -- 证书颁发者名称,即CA名称
        Validity                                              类似 /CN/BJ/NetSecurity/SSL/CA 目录结构
            Not Before: Nov  3 16:50:51 2011 GMT           -- 证书的有效期限,本质上是使用公钥的有效期
            Not After : Nov  2 16:50:51 2012 GMT              包括起始和结束时间,注意:是格林威治时间
        Subject: C=CN, ST=BJ, O=NetSecurity, OU=SSL, CN=Client -- 公钥持有人名称,是被证明的主体
        Subject Public Key Info:                               -- 类似 /CN/BJ/NetSecurity/SSL/Client 目录结构
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                    00:b1:ed:76:da:4a:48:73:ce:30:95:0c:fd:29:4e: -- RSA 公钥模数
                    91:9f:96:e6:b0:6c:91:3a:49:3f:e7:8c:81:a1:d6:
                    b7:53:70:73:d5:4c:4c:3d:8c:f2:67:26:40:d0:f9:
                    5f:8e:5e:b4:98:b5:8b:b1:7d:af:88:8a:43:ef:c6:
                    6a:cd:7b:9c:84:14:3a:d9:e1:2e:7e:ee:d3:d0:7d:
                    cc:27:f4:b0:2a:68:21:d3:f0:1b:7b:36:e6:6f:74:
                    c9:1b:76:41:bc:cd:f7:e7:35:22:f3:23:f8:b9:22:
                    c3:c5:62:88:5e:5a:65:96:46:81:a0:cc:51:74:df:
                    2d:28:a8:5e:d6:c7:d0:ed:37
                Exponent: 65537 (0x10001) -- RSA 公钥指数
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE                 -- 表示Subject不是CA
            Netscape Comment:               对于CA的自签名证书,由于Subject等于Issuer(都是CA),所以该字段为 CA:TRUE
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                13:73:C1:F7:67:0E:FC:1B:70:00:E0:A7:AD:32:D3:4B:ED:55:16:A3
            X509v3 Authority Key Identifier:
                keyid:4F:C4:EB:32:17:2C:51:87:0A:EA:61:D0:70:37:2B:B0:44:99:5F:9A

    Signature Algorithm: sha1WithRSAEncryption                 -- 签名算法,前面已经解释
        13:d4:cb:7c:8a:76:3a:3f:7a:5a:22:74:b3:c9:f8:6b:5d:59: -- 签名内容
        59:7c:97:d2:3c:74:a5:3f:85:02:db:f3:78:2f:db:9b:02:dd:
        e3:ab:90:ea:02:3b:2a:bc:d9:fc:80:22:6a:ce:67:24:72:87:
        ba:7d:4d:cd:6e:79:3f:63:c0:b1:9d:29:19:12:96:09:db:bd:
        f7:a8:05:98:6f:2e:42:9e:a7:b1:d2:e5:14:e3:8a:d9:90:71:
        4f:34:f0:ca:95:0e:42:12:98:63:9a:bb:a4:80:79:28:fe:49:
        2d:26:5e:93:85:0e:33:9c:d6:75:d3:a1:c1:28:02:d8:b0:31:
        b2:2c

根据上面的说明,我们可以将证书内容翻译成:
现证明,名称为C=CN, ST=BJ, O=NetSecurity, OU=SSL, CN=Client的用户持有RSA公钥(n=0xB1ED76DA4A4873CE30950CFD294E919F96E6B06C913A493FE78C81A1D6B7537073D54C4C3D8CF2672640D0F95F8E5EB498B58BB17DAF888
A43EFC66ACD7B9C84143AD9E12E7EEED3D07DCC27F4B02A6821D3F01B7B36E66F74C91B7641BCCDF7E73522F323F8B922C3C562885E5A6596468
1A0CC5174DF2D28A85ED6C7D0ED37, e=65537),公钥(证书)有效期为:GMT时间 2011年11月3日16:50到2012年11月2日16:50,证明签名算法sha1WithRSAEncryption。证明人:C=CN, ST=BJ, O=NetSecurity, OU=SSL, CN=CA

下一节我们将用数学计算对证书签名进行验证,结束之前,我们公布答案:对应MD5值a3ab18fd048c2f330a72af1f7c916f71的消息(以16进制表示)是
0xB4D3CAFDD1A7B5BDC3DCC2EBD1A7,该消息代表什么内容,有心的同学可以进一步观察下。

原文地址:https://www.cnblogs.com/efzju/p/2287053.html