上一节,我们展示了一张证书,在Windows中验证正常,但用OpenSSL工具却出现证书验证错误。
究竟是哪一方“犯了错”,暂时也看不出来。怎么办?

聪明的读者首先会想到,能否用第三方程序进行验证?对,这是个好主意。
那请谁呢,我们又请出Perl这个老朋友,在“从数学到密码学”系列中,我们已经初见其锋芒。
在后面几节中,我们还将继续领教其威力,暂且不表。

直奔主题,我们将用验证证书的基本原理,再经历一次从理论到实践的过程。
从出错证书的信息来看,该证书使用sha1WithRSAEncryption签名算法签发,用此算法签发的证书,验证公式如下

(证书的签名部分signatureValue)e=SHA1(证书的待签名部分tbsCertificate)(mod CA的公钥模)

我们仍用Perl的大数计算模块,分别计算等式的左右两边。验证用到的CA证书,其公钥为
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
……省略中间部分……
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

openssl.cert.verify.error.pem的签名部分signatureValue如下(根据X509格式从证书中摘得)
A4 E4 CA D5 59 E1 49 0A AF 68 8B 75 92 86 DB EE
62 7C 94 28 71 30 1D 8E B4 10 EF 4C B0 DC E1 63
……省略中间部分……
90 E3 12 76 06 8F D1 1F B3 9E 38 F5 82 C1 FA 4A
02 24 82 A7 47 08 17 9D 8E 46 2A 37 E7 CF 17 33

证书的待签名部分tbsCertificate如下
30 82 01 FC A0 03 02 01 02 02 09 00 00 A2 42 4A
A2 6A 51 DF 30 0D 06 09 2A 86 48 86 F7 0D 01 01
……省略中间部分……
1F 06 03 55 1D 23 04 18 30 16 80 14 4F C4 EB 32
17 2C 51 87 0A EA 61 D0 70 37 2B B0 44 99 5F 9A
恰好为512字节。

待签名部分tbsCertificate的SHA1值为
1112f6242252f0b8fd59331a1e5f50ca5a7ca111

注意,上面的内容均是转换为DER编码格式。
至于如何由PEM格式得到DER格式的证书,请GOOGLE或参考OpenSSL相关命令。

有了米,就可以下到Perl这个锅里了。我们利用公式
perl -Mbigint -e " $x=Math::BigInt->bmodpow(底数, 指数, 模); print $x->as_hex"
计算公式的左边,过程不再啰嗦了,简言之,结果就是左右两边相等,说明证书验证成功。

好,既然是这样,基本可以肯定错在OpenSSL。我们剩下的任务就是:证明确实是OpenSSL犯的错。
怎么做?代码必不可少,这个倒最简单,直接从openssl.org下载对应版本(0.9.8e)。

剩下的步骤,通常可以归结于两种方法(或者它们的结合):
1、静态方法----使用合适的代码查看工具,通过代码Review,找出出错的代码行。
2、动态方法----让代码运行在调试状态,通过运行过程中的状态信息,定位出错的语句。

基本上任何人更倾向于方法2,尤其是对代码整体不熟悉(笔者行文也采用这一假定)的情况下。
当然要求还是有的,要掌握证书验证的基本原理(如果你仔细看完了以前的文章,应该不是问题)
还要懂得C语言和基本调试方法^_^

但是对于大多数程序员使用的Windows系统,方法2有个不大不小的问题。
Windows中最好用的编程环境Visual Studio,在编译OpenSSL源代码时,是以Makefile的方式进行的(源码包中未提供VC工程)
因而不能使用图形界面的IDE进行代码的断点调试和单步跟踪。
很多网友为了享受图形界面提供的便利调试手段,不得不自己新建一个VC工程,然后手工将源文件一个一个地加到工程中
中间经历的痛苦过程,这里就不一一描述了。

笔者手头也有一个OpenSSL的工程,该工程不是采用将源文件硬加入并不断试错的思路得到
而是模仿编译Makefile的思路,整个过程基本采用脚本自动生成。
事实上,使用IDE对OpenSSL进行调试的方法不止一种,感兴趣的同学请留意后面的Blog。

下一节,就将使用这个VC工程,深入到OpenSSL代码中,去找出真正的BUG。