在 1999 年颁布的 RFC 2634《Enhanced Security Services for S/MIME》中,使用 SigningCertificate 指示校验数字签名时应当使用的证书。SigningCertificate 应当被包含在 ASN.1 结构“签名属性”(即 SignedAttributes,注:在 RFC 5652 CMS 标准中定义了 SignedAttributes,SignedAttributes 通常是 SignedData 结构中 SignerInfo 的 signedAttrs 子项的值)中,SigningCertificate 的具体定义如下:
SigningCertificate ::= SEQUENCE {
certs SEQUENCE OF ESSCertID,
policies SEQUENCE OF PolicyInformation OPTIONAL
}
SigningCertificate 的 ASN.1 对象识别符被定义为:
id-aa-signingCertificate OBJECT IDENTIFIER ::= { iso(1)
member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
smime(16) id-aa(2) 12 }
SigningCertificate 中的 certs 子项是由 ESSCertID 组成的 SEQUENCE。在组成 certs 的一系列 ESSCertID 中,第一个 ESSCertID 指示的数字证书被用来校验数字签名。ESSCertID 的定义如下:
ESSCertID ::= SEQUENCE {
certHash Hash,
issuerSerial IssuerSerial OPTIONAL
}
Hash ::= OCTET STRING -- SHA1 hash of entire certificate
IssuerSerial ::= SEQUENCE {
issuer GeneralNames,
serialNumber CertificateSerialNumber
}
ESSCertID 中包含子项 certHash,certHash 的值是 DER 编码格式的数字证书的 SHA-1 杂凑值。
当需要校验数字签名时,需要做三项检查:
1. 做验签的数学运算,即使用签名证书中的公钥验证数字签名;
2. 检查用来验签的数字证书是否有问题。这时要分为以下步骤做检查:
2.1 从 SigningCertificate 中提取 certs 子项;
2.2 从 certs 子项中提取出第一个 ESSCertID;
2.3 从 ESSCertID 中提取出 certHash;
2.4 计算用来验签的数字证书的 SHA-1 杂凑值;
2.5 比较计算出的杂凑值与 certHash 中包含的杂凑值是否相同,如果不同,则校验失败,认为曾经发生过证书替换攻击,即攻击者使用非法的证书替换了原先正确的证书。
3. 当在 ESSCertID 项中包含 issuerSerial 时(注:issuerSerial 是一个可选项),issuerSerial 中的 issuer 和 serialNumber 应当与验签时所用证书中的对应项一致。
在 2001 年颁布的 RFC 3161 《时间戳协议》标准中,用到了 ESSCertID,它出现在时间戳响应的编码中。时间戳响应中只能包含一个签名,即 TSA 针对时间戳请求所做的签名。如果在发送时间戳请求 TimeStampReq 时,其中子项 certReq (它是 ASN.1 BOOLEAN 类型)的值设置为 true,与 TSA 签名私钥对应的签名证书必须被包含在时间戳响应中,并使用 ESSCertID 来指示这张签名证书。时间戳响应是一个非常复杂的结构,对于 ESSCertID, 它被嵌套包含的层次示意图如下:
使用 ASN1View 工具软件,查看一个时间戳响应示例文件中 SigningCertificate 子项的 OID,如下图所示:
查看其中 ESSCertID 里的 certHash 值,如下图所示:
计算 certHash 的杂凑算法是 SHA-1,固定使用某一种杂凑算法不是一种好的设计方式。随着对杂凑算法的研究,研究人员已经找到了比较有效攻击 SHA-1 算法的方法,现在SHA-1 已经是一种不安全的算法了。为了能够使用其他杂凑算法,在 2007 年颁布的 RFC 5035 《Enhanced Security Services (ESS) Update: Adding CertID Algorithm Agility》中定义了 SigningCertificateV2 这样一种结构,其定义如下:
SigningCertificateV2 ::= SEQUENCE {
certs SEQUENCE OF ESSCertIDv2,
policies SEQUENCE OF PolicyInformation OPTIONAL
}
SigningCertificateV2 的 ASN.1 对象识别符被定义为:
id-aa-signingCertificateV2 OBJECT IDENTIFIER ::= { iso(1)
member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
smime(16) id-aa(2) 47 }
SigningCertificateV2 中的 certs 子项是由 ESSCertIDv2 组成的 SEQUENCE。ESSCertIDv2 的定义如下:
ESSCertIDv2 ::= SEQUENCE {
hashAlgorithm AlgorithmIdentifier DEFAULT {algorithm id-sha256},
certHash Hash,
issuerSerial IssuerSerial OPTIONAL
}
Hash ::= OCTET STRING
IssuerSerial ::= SEQUENCE {
issuer GeneralNames,
serialNumber CertificateSerialNumber
}
与 ESSCertID 的定义相比,ESSCertIDv2 的定义提供了更高的灵活性。在 ESSCertIDv2 中增加了 hashAlgorithm,该项被用来指示计算证书杂凑值的算法,缺省使用 SHA-256 算法,用户也可以使用其他算法,而 IssuerSerial 的定义没有发生变化。
在 2010 年颁布的 RFC 5816《ESSCertIDv2 Update for RFC 3161》中,规定对于数字时间戳,在 RFC 3161 中用到 SigningCertificate 的地方,如果使用 SHA-1 算法,则继续使用 SigningCertificate,其内部也继续使用 ESSCertID;如果使用其他杂凑算法,则必须使用 SigningCertificateV2,其内部应使用 ESSCertIDv2。
使用 ASN1View 工具软件,查看一个时间戳响应示例文件中 SigningCertificateV2 子项的 OID,如下图所示:
查看其中 ESSCertIDv2 里的 certHash 值,它是一个 SHA-256 杂凑值,如下图所示: