继续上节,我们追踪到函数ASN1_item_i2d调用处,并推测buf_in作为函数出参,是证书的tbsCertificate字段,而inl作为函数返回值,是tbsCertificate部分的长度。但是在查看buf_in内容时,却得到inl两次不同的值。这是为什么,难道两次查看的内容确实不同?索性就一探究竟,看下这次返回的buf_in吧,下面是buf_in的部分内存DUMP
30 82 02 2b a0 03 02 01 02 02 09 00 9d a2 42 4a  0?.+?.......??BJ
a2 6a 51 de 30 0d 06 09 2a 86 48 86 f7 0d 01 01  ?jQ?0...*?H??...
05 05 00 30 4b 31 0b 30 09 06 03 55 04 06 13 02  ...0K1.0...U....
43 4e 31 0b 30 09 06 03 55 04 08 13 02 42 4a 31  CN1.0...U....BJ1
14 30 12 06 03 55 04 0a 13 0b 4e 65 74 53 65 63  .0...U....NetSec
75 72 69 74 79 31 0c 30 0a 06 03 55 04 0b 13 03  urity1.0...U....
53 53 4c 31 0b 30 09 06 03 55 04 03 13 02 43 41  SSL1.0...U....CA
有没看出点眉目?如果你足够细心,会发现其中有些字串比较熟悉,如SSL、CA,像证书的部分内容(记得证书的Subject和Issuer字段吗)。用UltraEdit查看被验证证书(必须是DER格式编码)的二进制内容,其tbsCertificate部分显示(用蓝色标出)如下
30 82 02 93 30 82 01 FC A0 03 02 01 02 02 09 00 ; 0???鼱.......
00 A2 42 4A A2 6A 51 DF 30 0D 06 09 2A 86 48 86 ; .JQ?...*咹?
F7 0D 01 01 05 05 00 30 4B 31 0B 30 09 06 03 55 ; ?.....0K1.0...U
04 06 13 02 43 4E 31 0B 30 09 06 03 55 04 08 13 ; ....CN1.0...U...
02 42 4A 31 14 30 12 06 03 55 04 0A 13 0B 4E 65 ; .BJ1.0...U....Ne
74 53 65 63 75 72 69 74 79 31 0C 30 0A 06 03 55 ; tSecurity1.0...U
04 0B 13 03 53 53 4C 31 0B 30 09 06 03 55 04 03 ; ....SSL1.0...U..
13 02 43 41 30 1E 17 0D 31 31 31 31 30 33 31 36 ; ..CA0...11110316
比较上面两部分内容,发现不匹配,又碰到了死胡同。转而一想,我们还有一张证书嘛,CA证书。再打开CA证书并比较其tbsCertificate部分和内存中的buf_in,果然匹配,而且长度也与返回值inl相同,都是559。有兴趣的同学可以用Asn1View验证下。至此,我们明白,前面代码中断在获取CA证书内容之处。在此基础上判定:上一节的511长度就应该与被验证的证书相关。

如何证明呢,再次按F5,发现程序不会执行完毕,而是再次断在同一行,按F10单步执行,得到的inl就是511。但是这次再重新比较用户证书与内存内容,终于发现一个不同的地方,长度----原证书的tbsCertificate部分长是512,但是OpenSSL执行函数ASN1_item_i2d后给出的却是511字节长。可以判定,正是这个长度的差异,导致其摘要变化,最终影响签名验证的正确性。
我们的目光又聚焦在函数ASN1_item_i2d上面。至于如何把长度变化的幕后原因找到,请见下一节。