3

我正在尝试使用 JavaScript 验证 PKCS#7 签名。我知道 Web Cryptography API 不支持 PKCS#7,但我只是想验证原始 RSA 签名,而不是完整的 PKCS#7 结构。

我能够解析 PKCS#7、验证证书链、提取签名数据并使用forge验证签名。我不明白为什么无法使用 Web Cryptography API 验证此签名。

考虑这个例子:

var publicKey_pem = "\
    -----BEGIN PUBLIC KEY-----\n\
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyKy7Fm7M5eKVVsOWvpDY\n\
    7OrJ4WJY8kRupJFY2TmsfeOxcZTztx7igt3PRhUtk/P9hNbRge1Hh2lQbnlEozn3\n\
    i335jkGHoHbqGhBim6o4PUikByxEY46NEzxa0p4MdmnmcWh8oqhNH6k0T1ss1eAM\n\
    kCJZNwXqGM64+VuJ58k+H0f1NYFDmmnZVkXNeiRcS7T8MtJEDv0Kni06Brl9KMQa\n\
    xEUx1DLEwmTtW3tV/EA6erIYwpI/yWLdLxT/LxYdtAo9sx55sXXSgFKzTJkLwlhE\n\
    vrgVywIbOsmG0tcRw2NSP4R3XFpETxcwVRjkhbFpcDMjtjilEXZBrB8gaeI4gvX+\n\
    TwIDAQAB\n\
    -----END PUBLIC KEY-----"
    .replace(/^\s+/gm, "");

var signature_b64 = "\
    nuzPQx94kofXoc3TZlcBH+bAFG6b73cq9OXvGeE/mQ4qRDeWPKWZNC0HfkKtSyng\n\
    kTBWRDw7GeIvOQTY9OXtHunnrn3epPO+HzTmDpCwvv0oNVxoTPlnuBuLzP1mpuIT\n\
    RIgiOJ/xTEqzpjwoCG/HxySb5n4KNu3ii4XB+c914x6V/YU3wDCt60+p71QW3tz0\n\
    lvQPlG3CoMouSYi7sGhAdJMPJA1J5B24FAdqCrOB3xXTuX++HqH0fe6eR5cuzDJN\n\
    xkkjV+GDciyVPSrQb42gf9gl7qtOLvhrwor7efin+FhlWvL5plLn53Ao04scghTf\n\
    hZZLxrEkliWG5E3iGarvXA=="
    .replace(/(\n|\x20)/g, "");

var data_b64 = "\
    MYGxMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE1\n\
    MTExNjAwNTMxMFowLwYJKoZIhvcNAQkEMSIEIMcfOGYfrzbx+5cHx8CvoxB6M+25\n\
    Jd+QuGubzoJJjts7MEYGCyqGSIb3DQEJEAITMTcwNTAzMDEwLzALBglghkgBZQME\n\
    AgEEIJ3unWyG0PypTJy/MC9YWBUFjDUAG9AdNs1Byq3tpp23"
    .replace(/(\n|\x20)/g, "");

// using forge 0.7.x
var pki = forge.pki,
    util = forge.util,
    md = forge.md,
    raw = util.binary.raw;
var publicKey = pki.publicKeyFromPem(publicKey_pem);
var signature = new util.ByteBuffer(atob(signature_b64));
var data = new util.ByteBuffer(atob(data_b64));

var hash = md.createMessageDigest("sha256")
    .update(data).digest();
var verified = publicKey.verify(hash, signature,
    "RSASSA-PKCS1-V1_5");
console.info("Verification using forge: " + verified);

var modulus_b64 = "\
    yKy7Fm7M5eKVVsOWvpDY7OrJ4WJY8kRupJFY2TmsfeOxcZTztx7igt3PRhUtk/P9\n\
    hNbRge1Hh2lQbnlEozn3i335jkGHoHbqGhBim6o4PUikByxEY46NEzxa0p4Mdmnm\n\
    cWh8oqhNH6k0T1ss1eAMkCJZNwXqGM64+VuJ58k+H0f1NYFDmmnZVkXNeiRcS7T8\n\
    MtJEDv0Kni06Brl9KMQaxEUx1DLEwmTtW3tV/EA6erIYwpI/yWLdLxT/LxYdtAo9\n\
    sx55sXXSgFKzTJkLwlhEvrgVywIbOsmG0tcRw2NSP4R3XFpETxcwVRjkhbFpcDMj\n\
    tjilEXZBrB8gaeI4gvX+Tw=="
    .replace(/(\n|\x20|=)/g, "")
    .replace(/\//g, "_")
    .replace(/\+/g, "-");

var key = {
    kty: "RSA",
    alg: "RS256",
    e: "AQAB",
    n: modulus_b64
};
var algo = {
    name: "RSASSA-PKCS1-v1_5",
    hash: {name: "SHA-256"}
};
var use = ["verify"];

var crypto = window.crypto.subtle;
crypto.importKey("jwk", key, algo, false, use).then(function(publicKey) {
    var sig = raw.decode(signature.copy().getBytes());
    var dat = raw.decode(data.copy().getBytes());
    return crypto.verify(algo, publicKey, sig, dat);
}).then(function(res) {
    console.info("Verification using Web Crypto: " + res);
}, function(error) {
    console.error(error);
});

使用 forge 验证成功,但使用 Web Cryptography API 验证失败。我不明白这是怎么回事,因为他们使用的是相同的算法规范。

我能够使用 OpenSSL 验证 Web Cryptography API 生成的签名。使用 OpenSSL 检查这两个签名有一点不同:

# verify the external signature using OpenSSL
openssl rsautl -in sig.bin -verify -inkey pub.pem -pubin -asn1parse

    0:d=0  hl=2 l=  47 cons: SEQUENCE          
    2:d=1  hl=2 l=  11 cons:  SEQUENCE          
    4:d=2  hl=2 l=   9 prim:   OBJECT            :sha256
   15:d=1  hl=2 l=  32 prim:  OCTET STRING      
      0000 - 83 8f e4 de ba 8b b7 24-7a db 6d 43 12 c8 57 f5   .......$z.mC..W.
      0010 - 9c 80 1d 53 1b bf 7e 66-a3 d8 d6 fa ee 2a 4e 8a   ...S..~f.....*N.

# verify the web crypto signature using OpenSSL
openssl rsautl -in sig.bin -verify -inkey pub.pem -pubin -asn1parse

    0:d=0  hl=2 l=  49 cons: SEQUENCE          
    2:d=1  hl=2 l=  13 cons:  SEQUENCE          
    4:d=2  hl=2 l=   9 prim:   OBJECT            :sha256
   15:d=2  hl=2 l=   0 prim:   NULL              
   17:d=1  hl=2 l=  32 prim:  OCTET STRING      
      0000 - a5 91 a6 d4 0b f4 20 40-4a 01 17 33 cf b7 b1 90   ...... @J..3....
      0010 - d6 2c 65 bf 0b cd a3 2b-57 b2 77 d9 ad 9f 14 6e   .,e....+W.w....n

这可能是问题的原因吗?如果是这样,是否可以将外部签名转换为 Web Cryptography API 使用的编码?

4

0 回答 0