数字证书、CA及PKI(二)

本节我们正式验证数字证书sslclientcert中签名的合法性,根据RFC2459,证书内容分为三部分:
tbsCertificate、signatureAlgorithm和signatureValue。
证书中signatureAlgorithm内容是sha1WithRSAEncryption,结合RSA算法,得到验证公式如下
signatureValuee=SHA1(tbsCertificate)(mod n)

计算右边,待签名消息tbsCertificate内容如下
00000000h: 30 82 01 FC A0 03 02 01 02 02 09 00 9D A2 42 4A
00000010h: A2 6A 51 DF 30 0D 06 09 2A 86 48 86 F7 0D 01 01
00000020h: 05 05 00 30 4B 31 0B 30 09 06 03 55 04 06 13 02
00000030h: 43 4E 31 0B 30 09 06 03 55 04 08 13 02 42 4A 31
00000040h: 14 30 12 06 03 55 04 0A 13 0B 4E 65 74 53 65 63
00000050h: 75 72 69 74 79 31 0C 30 0A 06 03 55 04 0B 13 03
00000060h: 53 53 4C 31 0B 30 09 06 03 55 04 03 13 02 43 41
00000070h: 30 1E 17 0D 31 31 31 31 30 33 31 36 35 30 35 31
00000080h: 5A 17 0D 31 32 31 31 30 32 31 36 35 30 35 31 5A
00000090h: 30 4F 31 0B 30 09 06 03 55 04 06 13 02 43 4E 31
000000a0h: 0B 30 09 06 03 55 04 08 13 02 42 4A 31 14 30 12
000000b0h: 06 03 55 04 0A 13 0B 4E 65 74 53 65 63 75 72 69
000000c0h: 74 79 31 0C 30 0A 06 03 55 04 0B 13 03 53 53 4C
000000d0h: 31 0F 30 0D 06 03 55 04 03 13 06 43 6C 69 65 6E
000000e0h: 74 30 81 9F 30 0D 06 09 2A 86 48 86 F7 0D 01 01
000000f0h: 01 05 00 03 81 8D 00 30 81 89 02 81 81 00 B1 ED
00000100h: 76 DA 4A 48 73 CE 30 95 0C FD 29 4E 91 9F 96 E6
00000110h: B0 6C 91 3A 49 3F E7 8C 81 A1 D6 B7 53 70 73 D5
00000120h: 4C 4C 3D 8C F2 67 26 40 D0 F9 5F 8E 5E B4 98 B5
00000130h: 8B B1 7D AF 88 8A 43 EF C6 6A CD 7B 9C 84 14 3A
00000140h: D9 E1 2E 7E EE D3 D0 7D CC 27 F4 B0 2A 68 21 D3
00000150h: F0 1B 7B 36 E6 6F 74 C9 1B 76 41 BC CD F7 E7 35
00000160h: 22 F3 23 F8 B9 22 C3 C5 62 88 5E 5A 65 96 46 81
00000170h: A0 CC 51 74 DF 2D 28 A8 5E D6 C7 D0 ED 37 02 03
00000180h: 01 00 01 A3 7B 30 79 30 09 06 03 55 1D 13 04 02
00000190h: 30 00 30 2C 06 09 60 86 48 01 86 F8 42 01 0D 04
000001a0h: 1F 16 1D 4F 70 65 6E 53 53 4C 20 47 65 6E 65 72
000001b0h: 61 74 65 64 20 43 65 72 74 69 66 69 63 61 74 65
000001c0h: 30 1D 06 03 55 1D 0E 04 16 04 14 13 73 C1 F7 67
000001d0h: 0E FC 1B 70 00 E0 A7 AD 32 D3 4B ED 55 16 A3 30
000001e0h: 1F 06 03 55 1D 23 04 18 30 16 80 14 4F C4 EB 32
000001f0h: 17 2C 51 87 0A EA 61 D0 70 37 2B B0 44 99 5F 9A
将tbsCertificate内容保存到文件中,调用命令openssl dgst -sha1计算其SHA1值,得到
SHA1 = 84fb944a36b3200e6af23b0534175b2aed1ab7c5

计算左边,查看证书内容,其签名部分signatureValue的内容为
00000217h: 13 D4 CB 7C 8A 76 3A 3F 7A 5A 22 74 B3 C9 F8 6B
00000227h: 5D 59 59 7C 97 D2 3C 74 A5 3F 85 02 DB F3 78 2F
00000237h: DB 9B 02 DD E3 AB 90 EA 02 3B 2A BC D9 FC 80 22
00000247h: 6A CE 67 24 72 87 BA 7D 4D CD 6E 79 3F 63 C0 B1
00000257h: 9D 29 19 12 96 09 DB BD F7 A8 05 98 6F 2E 42 9E
00000267h: A7 B1 D2 E5 14 E3 8A D9 90 71 4F 34 F0 CA 95 0E
00000277h: 42 12 98 63 9A BB A4 80 79 28 FE 49 2D 26 5E 93
00000287h: 85 0E 33 9C D6 75 D3 A1 C1 28 02 D8 B0 31 B2 2C
接着要进行模指数运算,我们需要知道证明人(即CA)的公钥,它从哪里来?
在PKI体系中,仍延用了普通用户数字证书sslclientcert的使用套路。
其思路是,既然CA可以证明其他人公钥的真实性(通过证书形式)
原则上也可以签发一张证书,证明自己公钥的真实性。
换句话说,CA自己生成一张证书,内容是“CA持有XXX公钥”,并用自己的私钥进行签名。我们称之为自签名证书。
然后将用户证书sslclientcert与CA的自签名证书一起传送给验证方。
验证方收到这2份证书后,就可以利用CA自签名证书中的CA公钥,验证sslclientcert中公钥的真实性。
最后我们还剩下一个问题没有解决:如何鉴别CA自签名证书的真实性(即CA公钥的真实性)?

答案是你别无选择,必须相信:You MUST trust in something.
因为信任关系是有终点的,A相信B,B又相信C,C又相信D,信任链(A->B->C->......)必定会终止在某个人(估且认为是Z)。
验证CA证书的合法性,本质上与此相同:要相信证书A,需要证书B(的公钥进行验证),要相信证书B,需要证书C(的公钥进行验证)。
上面提到的证书B,C,称之为中级CA证书。而链条最后面的那个CA,无法由别人来证明它,只能自己证明自己,我们称之为根CA(证书)。
PKI的本质之一,就是信任关系的传递。
既然根CA证书无法被第3方证明,所以根CA只好通过某种可信途径(比如其官方网站----当然前提是没有被黑)招告天下。
如果你相信根CA,就可以从其网站上下载根CA证书,存放到本地机器,下次需要验证由根CA颁发的证书时,就可以用根CA证书进行签名验证。
当然,根CA证书验证其他证书的功能,在我们的PC上已经由操作系统代劳了。
此外我们要信任下载的根CA证书,需要告诉操作系统,在Windows上,这称为证书的导入。由于证书的导入过程是信任关系的导入,所以Windows
会郑重地提醒你,是否确认导入。下图是就导入过程的截图。

我们注意到,上图中有个SHA1指纹,这是什么意思呢?原来它是被导入证书的SHA1算法值
----还记得吗,作为消息的指纹是HASH算法的一大作用,这里就是用来鉴别CA证书的真假。
如果导入的CA证书是真实的,那么对话框中的指纹内容就和从正规可信渠道得到的证书指纹一样,否则就是假证书。
需要注意的是,被导入证书必须是DER编码格式。想了解详情的同学可以参阅《程序员密码学》或网上资料。

回到前面的话题,假设我们已经拿到根CA证书,并且信任该根CA。在我们这个例子中,根CA的公钥如下
加密指数e=0x10001(十进制65537),模n=
00000000h: C4 0A DB 78 8D 36 56 E0 99 8D 0F F5 C1 63 05 4D
00000010h: EB 3C FE 96 8B 19 AC 2D FC 34 04 C2 D5 DA 9A 58
00000020h: 3A B6 3E 3F B9 86 92 96 21 E6 77 05 3E 7C D1 4C
00000030h: 07 30 FD 35 65 CC 0E 4A E7 A2 CA D0 71 AF E4 EC
00000040h: 90 BD C5 F3 9E 3E DE EB 14 24 55 9C B0 62 BB 1C
00000050h: 9B 88 AA 52 6B 63 B1 4A 56 49 39 E8 6A 0C 91 5E
00000060h: 40 7B EF 07 6A 26 A1 D4 0A 43 F4 49 5C BB FF 51
00000070h: F8 78 22 78 E8 30 7E 19 BD CB 57 56 6D 48 C8 C3
现在可以继续计算左边的值signatureValuee(mod n)
我们再请出Perl来进行大数运算(当然,Perl最擅长的是文本处理,我们只是小试牛刀而已)
perl -Mbigint -e " $x=Math::BigInt->bmodpow(
0x13D4CB7C8A763A3F7A5A2274B3C9F86B5D59597C97D23C74A53F8502DBF3782F
    DB9B02DDE3AB90EA023B2ABCD9FC80226ACE67247287BA7D4DCD6E793F63C0B1
    9D2919129609DBBDF7A805986F2E429EA7B1D2E514E38AD990714F34F0CA950E
    421298639ABBA4807928FE492D265E93850E339CD675D3A1C12802D8B031B22C,
0x10001,
0xC40ADB788D3656E0998D0FF5C163054DEB3CFE968B19AC2DFC3404C2D5DA9A58
    3AB63E3FB986929621E677053E7CD14C0730FD3565CC0E4AE7A2CAD071AFE4EC
    90BDC5F39E3EDEEB1424559CB062BB1C9B88AA526B63B14A564939E86A0C915E
    407BEF076A26A1D40A43F4495CBBFF51F8782278E8307E19BDCB57566D48C8C3
);print $x->as_hex"

结果输出(折行显示)
0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
fffffff003021300906052b0e03021a0500041484fb944a36b3200e6af23b0534175b2aed1ab7c5

左边为什么不等于右边?再仔细看,发现后面红色部分是相同的,而前面一连串的F也有点规律,好象是填充的。
你猜对了,这是RSA公司制定关于公钥密码体制的一系列用于互联互通的操作规范中的一部分,即数字签名的标准PKCS1。
仔细说来,在签名数据前面加上前导1个字节0,后根若干个连续的0xFF,再根1字节0,再后面就是被签名的数据。
最终所有内容长度恰好拼成RSA公钥长度1024位,最后再做生成签名的模运算。

被签名的数据又分为2部分,前一部分是HASH算法(蓝色文字,还记得吗,现在进行签名运算前都要先对消息进行HASH)
后一部分才是签名的内容(红色文字,正好相同)。我们用工具来验证前一部分是代表什么。
先将红色和蓝色连着两部分转换成二进制表示的文件----Perl又可以派上用场----即内容为0x3021......b7c5
对此文件执行命令 openssl asn1parse -inform DER -i,输出如下
 0:d=0  hl=2 l=  33 cons: SEQUENCE
 2:d=1  hl=2 l=   9 cons:  SEQUENCE
 4:d=2  hl=2 l=   5 prim:   OBJECT:sha1 ---- 表示签名算法是SHA1,得到验证
11:d=2  hl=2 l=   0 prim:   NULL
13:d=1  hl=2 l=  20 prim:  OCTET STRING [HEX DUMP]:84FB944A36B3200E6AF23B0534175B2AED1AB7C5

至此,数字证书的验证讲解全部完毕。
剩下如证书吊销列表CRL、根CA自签名证书的结构等,都可以用上面的思路进行验证分析,就不再重复。