从数学到密码学(十九)

摘要:
数字证书、CA和PKI(II)在本节中,我们正式验证数字证书sslclientcert中签名的有效性。根据RFC2459,证书内容分为三部分:tbsCertificate、signatureAlgorithm和signatureValue。在PKI系统中,仍然使用通用用户数字证书sslclientcert。在收到这两个证书后,验证者可以使用CA自签名证书中的CA公钥来验证sslclientcert中公钥的真实性。上述证书B和C称为中间CA证书。PKI的本质之一是信任关系的传递。此外,如果我们想信任下载的根CA证书,我们需要告诉操作系统。在Windows上,这称为证书导入。

数字证书、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
会郑重地提醒你,是否确认导入。下图是就导入过程的截图。
从数学到密码学(十九)第1张

我们注意到,上图中有个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自签名证书的结构等,都可以用上面的思路进行验证分析,就不再重复。

免责声明:文章转载自《从数学到密码学(十九)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇nodejs-5.6 cookie-parserntfs-3g下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

LaTex常用数学符号整理

在论文和博客的写作中,经常会用到Latex的语法来书写数学公式,一份详细的数学符号对照表必不可少,本文重写了部分 Markdown 公式指导手册 。 -1.求和积分的上下标位置 sum olimits_{j=1}^{M} 上下标位于求和符号的水平右端, sumlimits_{j=1}^{M} 上下标位于求和符号的上下处, sum_{j=1}^{...

Java-文件加密传输(摘要+签名)

Java-文件加密传输(摘要+签名) 文件加密传输其实就是将文件以二进制格式进行传输。其中加密文件主要由:源文件二进制文件、源文件数字摘要、数字签名、特征码等等组成。摘要可确认文件的唯一性,数字签名则是对摘要进行了加密。 本文主要记录使用RSA加密方式其中生成RSA密钥主要介绍二种方式: 1、安装openssl情况下使用Linux命令生成 2、Java代...

C#使用BouncyCastle来实现私钥加密公钥解密的方法与java互通的RSA加解密和签名(转)

因为C#的RSA加密解密只有公钥加密,私钥解密,没有私钥加密,公钥解密。在网上查了很久也没有很好的实现。BouncyCastle的文档少之又少。很多人可能会说,C#也是可以的,通过Biginteger开源类来实现,不过那个是有一个文章,不过他加密出来的是16进制结果的。根本不能和JAVA互通。连加密出来的都不和C#原生的加密出来的结果格式一样。所以还是没有...

多密钥ssh-key生成与管理

由于 git 大文件用 http 方式难以传输,必须使用 ssh-key,而 ssh-key 又生成了好多个。最近在各种折腾 ssh,公钥私钥上花费了很多时间,现将一些问题总结如下。系统为 Mac/Linux。 密钥的原理 SSH之所以能够保证安全,原因在于它采用了公钥加密。 整个ssh密码登录过程是这样的: 用户向远程主机发登录请求:ssh user@...

Unity3D中Mathf数学运算函数总结

引入: 看到一个案例注意到函数Mathf.SmoothDamp的使用,游戏中用于做相机的缓冲跟踪和boss直升机跟踪士兵。该函数是Unity3D中Mathf数学运算函数中的一个。一些游戏使用了smoothmove的功能,其实就是类似的效果,只是发现这个函数很容易的已经封装好了,查了官网文档发现使用起来真的非常简单。 smoothdamp,我的理解是平滑缓...

HTTPS通信原理-证书交换

TLS握手过程 握手简述(以RSA为例): client hello:客户端给出TLS协议版本号,支持的加密算法、随机数Client random、扩展字段 server hello:服务端确认双方可支持的加密算法,并把数字证书下发给客户端。同时也会生成一个随机数Server random 客户端验证证书的有效性,并重新生成一个随机数Pre-main s...