(您可能对 Security.SE 上的这个问题感兴趣。)
这是X.509 证书的结构:
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING }
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
extensions [3] EXPLICIT Extensions OPTIONAL
-- If present, version MUST be v3
}
当出现证书时,浏览器会从证书本身获取签名算法。通常,这类似于RSAwithSHA1
.
在这种情况下,它确实可以重新计算TBSCertificate
(证书的实际内容)的 SHA-1 摘要。
此外,TBSCertificate
它可以从 中找到颁发者名称:这是用于从已知 CA 证书中查找信任锚的名称(颁发者名称必须与 CA 证书的主题匹配)。当它在它已经信任的列表中找到具有正确名称的 CA 证书时,它可以从该 CA 证书中获取公共 RSA 密钥。
同时拥有 SHA-1 摘要和 RSA 公钥,它可以验证signatureValue
匹配。
数字签名是一个加密的哈希值
严格来说,这不是真的,尽管人们常说。数字签名是数字签名,而不是加密。
问题在于 RSA 使用相同的数学来加密和签名:使用公钥加密和使用私钥签名。通常,一个与另一个混淆(即使在 OpenSSL API 中)。用私钥“加密”是没有意义的,因为“加密”意味着隐藏(如果你把公钥泄露出去,你就不会隐藏任何东西,这样它就可以“解密”签名)。
这种关于散列和数字签名加密的微妙之处不适用于其他一些算法,例如仅用于签名的 DSA。
这就是为什么许多数字签名 API 将散列和密钥使用组合成一个“签名”或“验证”操作的原因。这就是 Java Signature API 所做的,例如:您告诉它使用RSAwithSHA1
or DSAwithSHA1
,给它密钥和消息,并告诉它签名或验证,您不必手动进行摘要或“加密”。
用于证书验证的目的:浏览器从证书中获取颁发者并找到对应的公钥(来自受信任的 CA 证书),它还从证书中获取签名算法,然后用该公钥和 TBSCertificate 验证签名内容,根据签名算法的规定。