我想使用JavaScript webcrypto API验证CMS签名邮件。根据RFC 3161,该消息是时间戳响应的一部分。
所以我接受签名,内容(来自encapContentInfo)和公钥,并将其传递给以下导入密钥并验证签名的函数:
function verify(signature, data, publicKey, callback) {
console.log("pubkey: " + publicKey);
console.log("data: " + data);
console.log("signature: " + signature);
crypto.subtle.importKey(
"spki",
new Uint8Array(hexToArray(publicKey)),
{
name: "RSASSA-PKCS1-v1_5",
hash: {name: "SHA-1"}
},
false,
["verify"]
)
.then(function(publicKey){
console.log(publicKey);
crypto.subtle.verify(
{
name: "RSASSA-PKCS1-v1_5",
hash: {name: "SHA-1"}
},
publicKey,
new Uint8Array(hexToArray(signature)),
new Uint8Array(hexToArray(data))
)
.then(function(isvalid){
console.log("valid: " + isvalid);
})
.catch(function(err){
throw(err);
});
})
.catch(function(err){
throw(err);
});
}
输出如下:
pubkey: 30820122300d06092a864886f70d01010105000382010f003082010a0282010100a9ac33b296da7177999d464f47aa4a40d57d58dcfd93beae68913ab75cb77fe36c4b52b3b55a53cce10f70880a81aba4ffdc1d4826fe645cbabcd1e0b4eceff702f6fb378670128eadbe39a4a9e484c1d01f95fcfcbd44ca091dcc344e0356ca8967f54f7f6acc0dd5af8c1a4f77003fe01c3b98d6611d52b3fe432962544e142cc6f99163ccb7798bb8d4aea948d0cd6f72b740915b87ca2824ac9ec958ab0e5eacb36a7a66be091e826f862849026aa911e3b1a84487f6654aad7f3be4d1d9d312b2f9fcd7c69836ae893060393a47b310a6a4b03eeea6c8659df57782fa75855007d5ffb622ff8d229edd57c0771149b7fc827780fcde0c02f82bc2977d250203010001
data: 306b020101060c2b0601040181ad21822c16013031300d0609608648016503040201050004201b14e43e38297d534d827e351c15347f9eebc973258c8b555c044de46c5a0f02021424e3f636950c119fb3ebdb289d60d7bc637f3bd9180f32303136303431393139333931395a
signature: 7a65069868d97fb0ffcd53bca6b80daa671e1b0ac1a1d262ba2fba1525d0ca8e4998d4f49cba990f9a89c52003457ca1bbb037dee8e5e64c617af0c1ea72215b648477b052165810f4f6eb7f869ac19373b2aad1a2b5a809b8b758bdad540a5cd1f33d3c80870c7ae9c6db61dd7c7f8c346ee3c7aadc16f90ed87833a4ba771cbdc930a6dfb3fd16f5ab57de212deddc4d49c11ef825a8d996ba40e0e07c7c5788000d61169fe7512c97d29f7ff4b8ce2842e5b339dae5cef1eb517457b3e8b98bc887dda952b6346bd8345e5eb2cdd976fe5688d375551bc2a20cd7aafd1bbf6a9d102ad2a8dea620ad3ed6763f0841ec020dc1ad485ed1448ae5f5d511ef8f
CryptoKey {}
valid: false
如您所见,验证失败,但我很确定签名是有效的,因为许多人都使用此时间戳服务器。
我的实施有什么问题吗?
我尝试在Firefox扩展程序中执行此操作。
编辑:似乎需要使用signedAttrs字段的DER值,哈希它,然后用证书验证它。
答案 0 :(得分:0)
我自己设法做到了:首先必须使用公钥解密签名,以获取包含消息摘要的ASN.1对象。
e.g。 openssl rsautl -inkey cert.pem -pubin -in signature -out out
然后你获取signedAttrs对象并将开头的显式标记(0xA0)替换为set标记(0x31),因为RFC中有以下句子:
The IMPLICIT [0] tag in the signedAttrs is not used for the DER encoding, rather an EXPLICIT SET OF tag is used
然后计算设置对象的摘要(使用与signerInfo中的digestAlgorithm相同的算法)。
如果签名有效,则两个摘要值相同。