当在KMail邮件客户端中,在Kleopatra和GnuPG应用程序中实施与使用俄语密码算法有关的项目时,为了将俄语oid从点十进制转换为DER编码,我决定使用NSS(网络安全服务)软件包中的oidcalc实用程序,它已预安装在所有Linux发行版中,包括本地克隆。结果代码已在工作中使用。一切顺利,直到找到一个oid,其中有一个十进制数字0(零),即“ 1.2.643.2.2.36.0”(szOID_GostR3410_2001_CryptoPro_XchA_ParamSet)。在这里,一个令人不愉快的惊喜在等待着我-我的代码停止工作了。在某个时候,我决定看看这个oid转换成什么:# oidcalc 1.2.643.2.2.36.0
0x2a, 0x85, 0x3, 0x2, 0x2, 0x24,
#
但是应该有0x2a,0x85、0x3、0x2、0x2、0x24、0x0-没有尾随的十六进制零。我试图翻译另一个oid“ 1.2.643.3.6.0.1”(CryptoPro CA,证书有效期1个月):# oidcalc 1.2.643.3.6.0.1
0x2a, 0x85, 0x3, 0x3 0x3, 0x6, 0x1,
#
同样令人遗憾的结果-没有倒数第二个字节为零。很明显,oidcalc实用程序从oid抛出零。以下示例仅确认此假设:# oidcalc 1.2.643.3.6.1
0x2a, 0x85, 0x3, 0x3 0x3, 0x6, 0x1,
#
对于另一项检查,我不得不使用oid实用程序并获得了我期望的结果:# ./oid 1.2.643.2.2.36.0
06 07 2A 85 03 02 02 24 00
# ./oid 1.2.643.3.6.0.1
06 07 2A 85 03 03 06 00 01
#
oid
实用程序已经以ASN1编码输出结果,其中第一个字节确定序列的类型,第二个字节确定序列的长度(以字节为单位),然后oid本身以十六进制表示。之后,剩下的工作就是分析oidcalc.c实用程序的源代码,并将最小的更改汇总在一起: . . .
memset(buf, 0, sizeof(buf));
val = atoi(curstr);
count = 0;
/* */
if(curstr[0] != '0')
while (val) {
buf[count] = (val & 0x7f);
val = val >> 7;
count++;
}
/* */
else
buf[count++] = 0x00;
. . .
现在,如果您重新构建该实用程序,则一切正常:#oidcalc 1.2.643.2.2.36.0
0x2a, 0x85, 0x3, 0x2, 0x2, 0x24, 0x0,
#oidcalc 1.2.643.3.6.0.1
0x2a, 0x85, 0x3, 0x3, 0x6, 0x0, 0x1,
#
实用程序开发人员的错误是什么?在小事情上。为了将数字从字符串转换为整数,作者使用了atoi函数,该函数在字符'0'的翻译和无法翻译的情况下(未指定数字)返回0(零)。事实证明,添加额外的验证就足够了,并且有效。我写信给NSS开发人员了吗?是的,我写了。此外,带有支持PKCS#11接口的带有加密令牌/智能卡的插件的NSS软件包实际上是应用程序的加密核心来自Mozilla,也可用于Google的Chrome浏览器。没有回应,代码没有固定。因此,出现此注释是为了防止其他人作为您卑微的仆人踏上这耙。好吧,当然,我们希望Linux的国内fork / clone的供应商将在其软件包中修复此错误。