JavaScript を使用して PKCS#7 署名を検証しようとしています。PKCS#7 が Web Cryptography API でサポートされていないことは知っていますが、完全な PKCS#7 構造ではなく、未加工の RSA 署名のみを検証しようとしています。
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 を使用して 2 つの署名を調べると、わずかな違いがあります。
# 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 で使用されるエンコーディングに変換できますか?