diff options
Diffstat (limited to 'dom/crypto/test/test_WebCrypto.html')
-rw-r--r-- | dom/crypto/test/test_WebCrypto.html | 1234 |
1 files changed, 1234 insertions, 0 deletions
diff --git a/dom/crypto/test/test_WebCrypto.html b/dom/crypto/test/test_WebCrypto.html new file mode 100644 index 0000000000..90da813880 --- /dev/null +++ b/dom/crypto/test/test_WebCrypto.html @@ -0,0 +1,1234 @@ +<!DOCTYPE html> +<html> + +<head> +<title>WebCrypto Test Suite</title> +<meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> +<link rel="stylesheet" href="./test_WebCrypto.css"/> +<script src="/tests/SimpleTest/SimpleTest.js"></script> + +<!-- Utilities for manipulating ABVs --> +<script src="util.js"></script> + +<!-- A simple wrapper around IndexedDB --> +<script src="simpledb.js"></script> + +<!-- Test vectors drawn from the literature --> +<script src="./test-vectors.js"></script> + +<!-- General testing framework --> +<script src="./test-array.js"></script> + +<script>/* <![CDATA[*/ +"use strict"; + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Test for presence of WebCrypto API methods", + function() { + this.complete( + exists(window.crypto.subtle) && + exists(window.crypto.subtle.encrypt) && + exists(window.crypto.subtle.decrypt) && + exists(window.crypto.subtle.sign) && + exists(window.crypto.subtle.verify) && + exists(window.crypto.subtle.digest) && + exists(window.crypto.subtle.importKey) && + exists(window.crypto.subtle.exportKey) && + exists(window.crypto.subtle.generateKey) && + exists(window.crypto.subtle.deriveKey) && + exists(window.crypto.subtle.deriveBits) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Clean failure on a mal-formed algorithm", + function() { + var that = this; + var alg = { + get name() { + throw new Error("Oh no, no name!"); + }, + }; + + crypto.subtle.importKey("raw", tv.raw, alg, true, ["encrypt"]) + .then( + error(that), + complete(that, function(x) { return true; }) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Import / export round-trip with 'raw'", + function() { + var that = this; + var alg = "AES-GCM"; + + function doExport(x) { + if (!hasKeyFields(x)) { + throw new Error("Invalid key; missing field(s)"); + } else if ((x.algorithm.name != alg) || + (x.algorithm.length != 8 * tv.raw.length) || + (x.type != "secret") || + (!x.extractable) || + (x.usages.length != 1) || + (x.usages[0] != "encrypt")) { + throw new Error("Invalid key: incorrect key data"); + } + return crypto.subtle.exportKey("raw", x); + } + + crypto.subtle.importKey("raw", tv.raw, alg, true, ["encrypt"]) + .then(doExport) + .then( + memcmp_complete(that, tv.raw), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Import failure with format 'raw'", + function() { + var that = this; + var alg = "AES-GCM"; + + crypto.subtle.importKey("raw", tv.negative_raw, alg, true, ["encrypt"]) + .then(error(that), complete(that)); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Proper handling of an ABV representing part of a buffer", + function() { + var that = this; + var alg = "AES-GCM"; + + var u8 = new Uint8Array([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f]); + var u32 = new Uint32Array(u8.buffer, 8, 4); + var out = u8.subarray(8, 24); + + function doExport(x) { + return crypto.subtle.exportKey("raw", x); + } + + crypto.subtle.importKey("raw", u32, alg, true, ["encrypt"]) + .then(doExport, error(that)) + .then(memcmp_complete(that, out), error(that)); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Import / export round-trip with 'pkcs8'", + function() { + var that = this; + var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" }; + + function doExport(x) { + if (!hasKeyFields(x)) { + throw new Error("Invalid key; missing field(s)"); + } else if ((x.algorithm.name != alg.name) || + (x.algorithm.hash.name != alg.hash) || + (x.algorithm.modulusLength != 512) || + (x.algorithm.publicExponent.byteLength != 3) || + (x.type != "private") || + (!x.extractable) || + (x.usages.length != 1) || + (x.usages[0] != "sign")) { + throw new Error("Invalid key: incorrect key data"); + } + return crypto.subtle.exportKey("pkcs8", x); + } + + crypto.subtle.importKey("pkcs8", tv.pkcs8, alg, true, ["sign"]) + .then(doExport) + .then( + memcmp_complete(that, tv.pkcs8), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Import failure with format 'pkcs8'", + function() { + var that = this; + var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" }; + + crypto.subtle.importKey("pkcs8", tv.negative_pkcs8, alg, true, ["encrypt"]) + .then(error(that), complete(that)); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Import / export round-trip with 'spki'", + function() { + var that = this; + var alg = { + name: "RSASSA-PKCS1-v1_5", + hash: "SHA-256", + }; + + function doExport(x) { + if (!hasKeyFields(x)) { + throw new Error("Invalid key; missing field(s)"); + } else if ((x.algorithm.name != alg.name) || + (x.algorithm.modulusLength != 1024) || + (x.algorithm.publicExponent.byteLength != 3) || + (x.type != "public") || + (!x.extractable) || + (x.usages.length != 1) || + (x.usages[0] != "verify")) { + throw new Error("Invalid key: incorrect key data"); + } + return crypto.subtle.exportKey("spki", x); + } + + crypto.subtle.importKey("spki", tv.spki, alg, true, ["verify"]) + .then(doExport, error(that)) + .then( + memcmp_complete(that, tv.spki), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Import failure with format 'spki'", + function() { + var that = this; + var alg = { + name: "RSASSA-PKCS1-v1_5", + hash: "SHA-256", + }; + + crypto.subtle.importKey("spki", tv.negative_spki, alg, true, ["encrypt"]) + .then(error(that), complete(that)); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Importing an ECDSA key as an RSA key should fail", + function() { + var that = this; + var alg = { + name: "RSASSA-PKCS1-v1_5", + hash: "SHA-256", + }; + + crypto.subtle.importKey("spki", tv.ecdh_p256.spki, alg, true, ["verify"]) + .then(error(that), complete(that)); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Refuse to export non-extractable key", + function() { + var that = this; + var alg = "AES-GCM"; + + function doExport(x) { + return crypto.subtle.exportKey("raw", x); + } + + crypto.subtle.importKey("raw", tv.raw, alg, false, ["encrypt"]) + .then(doExport, error(that)) + .then( + error(that), + complete(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "IndexedDB store / retrieve round-trip", + function() { + var that = this; + var alg = "AES-GCM"; + var importedKey; + var dbname = "keyDB"; + var dbstore = "keystore"; + var dbversion = 1; + var dbkey = 0; + var db; + + function doIndexedDB(x) { + importedKey = x; + var req = indexedDB.deleteDatabase(dbname); + req.onerror = error(that); + req.onsuccess = doCreateDB; + } + + function doCreateDB() { + var req = indexedDB.open(dbname, dbversion); + req.onerror = error(that); + req.onupgradeneeded = function(e) { + db = e.target.result; + db.createObjectStore(dbstore, {keyPath: "id"}); + }; + + req.onsuccess = doPut; + } + + function doPut() { + var req = db.transaction([dbstore], "readwrite") + .objectStore(dbstore) + .add({id: dbkey, val: importedKey}); + req.onerror = error(that); + req.onsuccess = doGet; + } + + function doGet() { + var req = db.transaction([dbstore], "readwrite") + .objectStore(dbstore) + .get(dbkey); + req.onerror = error(that); + req.onsuccess = complete(that, function(e) { + db.close(); + return hasKeyFields(e.target.result.val); + }); + } + + crypto.subtle.importKey("raw", tv.raw, alg, false, ["encrypt"]) + .then(doIndexedDB, error(that)); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Generate a 256-bit HMAC-SHA-256 key", + function() { + var that = this; + var alg = { name: "HMAC", length: 256, hash: {name: "SHA-256"} }; + crypto.subtle.generateKey(alg, true, ["sign", "verify"]).then( + complete(that, function(x) { + return hasKeyFields(x) && x.algorithm.length == 256; + }), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Generate a 256-bit HMAC-SHA-256 key without specifying a key length", + function() { + var that = this; + var alg = { name: "HMAC", hash: {name: "SHA-256"} }; + crypto.subtle.generateKey(alg, true, ["sign", "verify"]).then( + complete(that, function(x) { + return hasKeyFields(x) && x.algorithm.length == 512; + }), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Generate a 256-bit HMAC-SHA-512 key without specifying a key length", + function() { + var that = this; + var alg = { name: "HMAC", hash: {name: "SHA-512"} }; + crypto.subtle.generateKey(alg, true, ["sign", "verify"]).then( + complete(that, function(x) { + return hasKeyFields(x) && x.algorithm.length == 1024; + }), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Fail generating an HMAC key when specifying an invalid hash algorithm", + function() { + var that = this; + var alg = { name: "HMAC", hash: {name: "SHA-123"} }; + crypto.subtle.generateKey(alg, true, ["sign", "verify"]).then( + error(that), + complete(that, function() { return true; }) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Fail generating an HMAC key when specifying a zero length", + function() { + var that = this; + var alg = { name: "HMAC", hash: {name: "SHA-256"}, length: 0 }; + crypto.subtle.generateKey(alg, true, ["sign", "verify"]).then( + error(that), + complete(that, function() { return true; }) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Generate a 192-bit AES key", + function() { + var that = this; + var alg = { name: "AES-GCM", length: 192 }; + crypto.subtle.generateKey(alg, true, ["encrypt"]).then( + complete(that, function(x) { + return hasKeyFields(x); + }), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Fail generating an AES key of wrong length", + function() { + var that = this; + var alg = { name: "AES-CBC", length: 64 }; + crypto.subtle.generateKey(alg, false, ["encrypt"]).then( + error(that), + complete(that, function(e) { + return e.name == "OperationError"; + }) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Fail generating a key with bad algorithm argument", + function() { + var that = this; + var alg = { name: "AES", length: 128 }; + crypto.subtle.generateKey(alg, false, ["encrypt"]).then( + error(that), + complete(that, function(e) { + return e.name == "NotSupportedError"; + }) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( "Generate a 1024-bit RSA key", + function() { + var that = this; + var alg = { + name: "RSASSA-PKCS1-v1_5", + hash: "SHA-256", + modulusLength: 1024, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + }; + crypto.subtle.generateKey(alg, false, ["sign", "verify"]).then( + complete(that, function(x) { + return exists(x.publicKey) && + (x.publicKey.algorithm.name == alg.name) && + (x.publicKey.algorithm.modulusLength == alg.modulusLength) && + (x.publicKey.type == "public") && + x.publicKey.extractable && + (x.publicKey.usages.length == 1) && + (x.publicKey.usages[0] == "verify") && + exists(x.privateKey) && + (x.privateKey.algorithm.name == alg.name) && + (x.privateKey.algorithm.modulusLength == alg.modulusLength) && + (x.privateKey.type == "private") && + !x.privateKey.extractable && + (x.privateKey.usages.length == 1) && + (x.privateKey.usages[0] == "sign"); + }), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Fail cleanly when NSS refuses to generate a key pair", + function() { + var that = this; + var alg = { + name: "RSASSA-PKCS1-v1_5", + hash: "SHA-256", + modulusLength: 2299, // NSS does not like this key length + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + }; + + crypto.subtle.generateKey(alg, false, ["sign"]) + .then( error(that), complete(that) ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "SHA-256 digest", + function() { + var that = this; + crypto.subtle.digest("SHA-256", tv.sha256.data).then( + memcmp_complete(that, tv.sha256.result), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Fail cleanly on unknown hash algorithm", + function() { + var that = this; + crypto.subtle.digest("GOST-34_311-95", tv.sha256.data).then( + error(that), + complete(that, function() { return true; }) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-CBC encrypt", + function() { + var that = this; + + function doEncrypt(x) { + return crypto.subtle.encrypt( + { name: "AES-CBC", iv: tv.aes_cbc_enc.iv }, + x, tv.aes_cbc_enc.data); + } + + crypto.subtle.importKey("raw", tv.aes_cbc_enc.key, "AES-CBC", false, ["encrypt"]) + .then(doEncrypt) + .then( + memcmp_complete(that, tv.aes_cbc_enc.result), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-CBC encrypt with wrong IV size", + function() { + var that = this; + + function encrypt(x, iv) { + return crypto.subtle.encrypt( + { name: "AES-CBC", iv }, + x, tv.aes_cbc_enc.data); + } + + function checkPromises(promises) { + for (var promise of promises) { + if (promise.status != "rejected") { + return false; + } + if (promise.reason.name != "OperationError") { + return false; + } + } + + return true; + } + + crypto.subtle.importKey("raw", tv.aes_cbc_enc.key, "AES-CBC", false, ["encrypt"]) + .then(function(key) { + var p1 = encrypt(key, new Uint8Array(15)); + var p2 = encrypt(key, new Uint8Array(17)); + + Promise.allSettled([p1, p2]) + .then(complete(that, checkPromises)); + }); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-CBC decrypt", + function() { + var that = this; + + function doDecrypt(x) { + return crypto.subtle.decrypt( + { name: "AES-CBC", iv: tv.aes_cbc_dec.iv }, + x, tv.aes_cbc_dec.data); + } + + crypto.subtle.importKey("raw", tv.aes_cbc_dec.key, "AES-CBC", false, ["decrypt"]) + .then(doDecrypt) + .then( + memcmp_complete(that, tv.aes_cbc_dec.result), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-CBC decrypt with wrong IV size", + function() { + var that = this; + + function decrypt(x, iv) { + return crypto.subtle.decrypt( + { name: "AES-CBC", iv }, + x, tv.aes_cbc_dec.data); + } + + function checkPromises(promises) { + for (var promise of promises) { + if (promise.status != "rejected") { + return false; + } + if (promise.reason.name != "OperationError") { + return false; + } + } + + return true; + } + + crypto.subtle.importKey("raw", tv.aes_cbc_dec.key, "AES-CBC", false, ["decrypt"]) + .then(function(key) { + var p1 = decrypt(key, new Uint8Array(15)); + var p2 = decrypt(key, new Uint8Array(17)); + + Promise.allSettled([p1, p2]) + .then(complete(that, checkPromises)); + }); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-CTR encryption", + function() { + var that = this; + + function doEncrypt(x) { + return crypto.subtle.encrypt( + { name: "AES-CTR", counter: tv.aes_ctr_enc.iv, length: 32 }, + x, tv.aes_ctr_enc.data); + } + + crypto.subtle.importKey("raw", tv.aes_ctr_enc.key, "AES-CTR", false, ["encrypt"]) + .then(doEncrypt) + .then( + memcmp_complete(that, tv.aes_ctr_enc.result), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-CTR encryption with wrong IV size", + function() { + var that = this; + + function encrypt(x, iv) { + return crypto.subtle.encrypt( + { name: "AES-CTR", counter: iv, length: 32 }, + x, tv.aes_ctr_enc.data); + } + + function checkPromises(promises) { + for (var promise of promises) { + if (promise.status != "rejected") { + return false; + } + if (promise.reason.name != "OperationError") { + return false; + } + } + + return true; + } + + crypto.subtle.importKey("raw", tv.aes_ctr_enc.key, "AES-CTR", false, ["encrypt"]) + .then(function(key) { + var p1 = encrypt(key, new Uint8Array(15)); + var p2 = encrypt(key, new Uint8Array(17)); + + Promise.allSettled([p1, p2]) + .then(complete(that, checkPromises)); + }); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-CTR decryption", + function() { + var that = this; + + function doDecrypt(x) { + return crypto.subtle.decrypt( + { name: "AES-CTR", counter: tv.aes_ctr_dec.iv, length: 32 }, + x, tv.aes_ctr_dec.data); + } + + crypto.subtle.importKey("raw", tv.aes_ctr_dec.key, "AES-CTR", false, ["decrypt"]) + .then(doDecrypt) + .then( + memcmp_complete(that, tv.aes_ctr_dec.result), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-CTR decryption with wrong IV size", + function() { + var that = this; + + function decrypt(x, iv) { + return crypto.subtle.decrypt( + { name: "AES-CTR", counter: iv, length: 32 }, + x, tv.aes_ctr_dec.data); + } + + function checkPromises(promises) { + for (var promise of promises) { + if (promise.status != "rejected") { + return false; + } + if (promise.reason.name != "OperationError") { + return false; + } + } + + return true; + } + + crypto.subtle.importKey("raw", tv.aes_ctr_dec.key, "AES-CTR", false, ["decrypt"]) + .then(function(key) { + var p1 = decrypt(key, new Uint8Array(15)); + var p2 = decrypt(key, new Uint8Array(17)); + + Promise.allSettled([p1, p2]) + .then(complete(that, checkPromises)); + }); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-GCM encryption", + function() { + var that = this; + + function doEncrypt(x) { + return crypto.subtle.encrypt( + { + name: "AES-GCM", + iv: tv.aes_gcm_enc.iv, + additionalData: tv.aes_gcm_enc.adata, + tagLength: 128, + }, + x, tv.aes_gcm_enc.data); + } + + crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, "AES-GCM", false, ["encrypt"]) + .then(doEncrypt) + .then( + memcmp_complete(that, tv.aes_gcm_enc.result), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-GCM decryption", + function() { + var that = this; + + function doDecrypt(x) { + return crypto.subtle.decrypt( + { + name: "AES-GCM", + iv: tv.aes_gcm_dec.iv, + additionalData: tv.aes_gcm_dec.adata, + tagLength: 128, + }, + x, tv.aes_gcm_dec.data); + } + + crypto.subtle.importKey("raw", tv.aes_gcm_dec.key, "AES-GCM", false, ["decrypt"]) + .then(doDecrypt) + .then( + memcmp_complete(that, tv.aes_gcm_dec.result), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-GCM decryption, failing authentication check", + function() { + var that = this; + + function doDecrypt(x) { + return crypto.subtle.decrypt( + { + name: "AES-GCM", + iv: tv.aes_gcm_dec_fail.iv, + additionalData: tv.aes_gcm_dec_fail.adata, + tagLength: 128, + }, + x, tv.aes_gcm_dec_fail.data); + } + + crypto.subtle.importKey("raw", tv.aes_gcm_dec_fail.key, "AES-GCM", false, ["decrypt"]) + .then(doDecrypt) + .then( + error(that), + complete(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-GCM encryption, fail with a zero-length IV", + function() { + var that = this; + var alg = { + name: "AES-GCM", + iv: new Uint8Array(), + additionalData: tv.aes_gcm_enc.adata, + tagLength: 128, + }; + + function doEncrypt(x) { + return crypto.subtle.encrypt(alg, x, tv.aes_gcm_enc.data); + } + + crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, "AES-GCM", false, ["encrypt"]) + .then(doEncrypt) + .then(error(that), complete(that)); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-GCM encryption, accept an all-zero IV (1 byte)", + function() { + var that = this; + var alg = { + name: "AES-GCM", + iv: new Uint8Array(1), + additionalData: tv.aes_gcm_enc.adata, + tagLength: 128, + }; + + function doEncrypt(x) { + return crypto.subtle.encrypt(alg, x, tv.aes_gcm_enc.data); + } + + crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, "AES-GCM", false, ["encrypt"]) + .then(doEncrypt) + .then(complete(that), error(that)); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-GCM encryption, accept an all-zero IV (12 bytes)", + function() { + var that = this; + var alg = { + name: "AES-GCM", + iv: new Uint8Array(12), + additionalData: tv.aes_gcm_enc.adata, + tagLength: 128, + }; + + function doEncrypt(x) { + return crypto.subtle.encrypt(alg, x, tv.aes_gcm_enc.data); + } + + crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, "AES-GCM", false, ["encrypt"]) + .then(doEncrypt) + .then(complete(that), error(that)); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "AES-GCM encryption, accept an all-zero IV (16 bytes)", + function() { + var that = this; + var alg = { + name: "AES-GCM", + iv: new Uint8Array(16), + additionalData: tv.aes_gcm_enc.adata, + tagLength: 128, + }; + + function doEncrypt(x) { + return crypto.subtle.encrypt(alg, x, tv.aes_gcm_enc.data); + } + + crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, "AES-GCM", false, ["encrypt"]) + .then(doEncrypt) + .then(complete(that), error(that)); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "HMAC SHA-256 sign", + function() { + var that = this; + var alg = { + name: "HMAC", + hash: "SHA-256", + }; + + function doSign(x) { + return crypto.subtle.sign("HMAC", x, tv.hmac_sign.data); + } + + crypto.subtle.importKey("raw", tv.hmac_sign.key, alg, false, ["sign"]) + .then(doSign) + .then( + memcmp_complete(that, tv.hmac_sign.result), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "HMAC SHA-256 verify", + function() { + var that = this; + var alg = { + name: "HMAC", + hash: "SHA-256", + }; + + function doVerify(x) { + return crypto.subtle.verify("HMAC", x, tv.hmac_verify.sig, tv.hmac_verify.data); + } + + crypto.subtle.importKey("raw", tv.hmac_verify.key, alg, false, ["verify"]) + .then(doVerify) + .then( + complete(that, function(x) { return !!x; }), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "HMAC SHA-256, failing verification due to bad signature", + function() { + var that = this; + var alg = { + name: "HMAC", + hash: "SHA-256", + }; + + function doVerify(x) { + return crypto.subtle.verify("HMAC", x, tv.hmac_verify.sig_fail, + tv.hmac_verify.data); + } + + crypto.subtle.importKey("raw", tv.hmac_verify.key, alg, false, ["verify"]) + .then(doVerify) + .then( + complete(that, function(x) { return !x; }), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "HMAC SHA-256, failing verification due to key usage restriction", + function() { + var that = this; + var alg = { + name: "HMAC", + hash: "SHA-256", + }; + + function doVerify(x) { + return crypto.subtle.verify("HMAC", x, tv.hmac_verify.sig, + tv.hmac_verify.data); + } + + crypto.subtle.importKey("raw", tv.hmac_verify.key, alg, false, ["encrypt"]) + .then(doVerify) + .then( + error(that), + complete(that, function(x) { return true; }) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "RSASSA/SHA-1 signature", + function() { + var that = this; + var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" }; + + function doSign(x) { + return crypto.subtle.sign(alg.name, x, tv.rsassa.data); + } + + crypto.subtle.importKey("pkcs8", tv.rsassa.pkcs8, alg, false, ["sign"]) + .then( doSign ) + .then( memcmp_complete(that, tv.rsassa.sig1), error(that) ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "RSASSA verification (SHA-1)", + function() { + var that = this; + var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" }; + + function doVerify(x) { + return crypto.subtle.verify(alg.name, x, tv.rsassa.sig1, tv.rsassa.data); + } + + crypto.subtle.importKey("spki", tv.rsassa.spki, alg, false, ["verify"]) + .then( doVerify ) + .then( + complete(that, function(x) { return x; }), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "RSASSA verification (SHA-1), failing verification", + function() { + var that = this; + var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" }; + + function doVerify(x) { + return crypto.subtle.verify(alg.name, x, tv.rsassa.sig_fail, tv.rsassa.data); + } + + crypto.subtle.importKey("spki", tv.rsassa.spki, alg, false, ["verify"]) + .then( doVerify ) + .then( + complete(that, function(x) { return !x; }), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "RSASSA/SHA-256 signature", + function() { + var that = this; + var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }; + + function doSign(x) { + return crypto.subtle.sign(alg.name, x, tv.rsassa.data); + } + + crypto.subtle.importKey("pkcs8", tv.rsassa.pkcs8, alg, false, ["sign"]) + .then( doSign ) + .then( memcmp_complete(that, tv.rsassa.sig256), error(that) ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "RSASSA verification (SHA-256)", + function() { + var that = this; + var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }; + + function doVerify(x) { + return crypto.subtle.verify(alg.name, x, tv.rsassa.sig256, tv.rsassa.data); + } + + crypto.subtle.importKey("spki", tv.rsassa.spki, alg, false, ["verify"]) + .then( doVerify ) + .then( + complete(that, function(x) { return x; }), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "RSASSA verification (SHA-256), failing verification", + function() { + var that = this; + var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }; + + function doVerify(x) { + return crypto.subtle.verify(alg.name, x, tv.rsassa.sig_fail, tv.rsassa.data); + } + + crypto.subtle.importKey("spki", tv.rsassa.spki, alg, false, ["verify"]) + .then( doVerify ) + .then( + complete(that, function(x) { return !x; }), + error(that) + ); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Test that we return ArrayBuffers not ArrayBufferViews", + function() { + var that = this; + + crypto.subtle.digest("SHA-256", tv.sha256.data) + .then(complete(that, function(x) { + return x instanceof ArrayBuffer; + }), error(that)); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Ensure that importing an invalid key doesn't crash", + function() { + var that = this; + var alg = {name: "RSA-OAEP", hash: "SHA-1"}; + + crypto.subtle.importKey("pkcs8", tv.broken_pkcs8.rsa, alg, false, ["decrypt"]) + .then(error(that), complete(that)); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Test that we check keys before using them for encryption/signatures", + function() { + var that = this; + + function doCheckRSASSA() { + var alg = {name: "HMAC", hash: {name: "SHA-1"}}; + + function doSign(x) { + return crypto.subtle.sign("RSASSA-PKCS1-v1_5", x, new Uint8Array()); + } + + return crypto.subtle.generateKey(alg, false, ["sign"]).then(doSign); + } + + doCheckRSASSA().then(error(that), complete(that)); + } +); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Test that we're using the right globals when creating objects", + function() { + // This test isn't supported in workers. + if (window.importScripts) { + return this.complete(true); + } + + var that = this; + var data = crypto.getRandomValues(new Uint8Array(10)); + var hmacAlg = {name: "HMAC", length: 256, hash: "SHA-1"}; + + var rsaAlg = { + name: "RSA-PSS", + hash: "SHA-1", + modulusLength: 1024, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + }; + + function checkPrototypes(obj, type) { + return obj.__proto__ != window[type].prototype && + obj.__proto__ == frames[0][type].prototype; + } + + var p1 = crypto.subtle.importKey.call( + frames[0].crypto.subtle, "raw", data, hmacAlg, false, ["sign", "verify"]); + var p2 = crypto.subtle.generateKey.call( + frames[0].crypto.subtle, hmacAlg, false, ["sign", "verify"]); + var p3 = crypto.subtle.generateKey.call( + frames[0].crypto.subtle, rsaAlg, false, ["sign", "verify"]); + + if (!checkPrototypes(p1, "Promise") || + !checkPrototypes(p2, "Promise") || + !checkPrototypes(p3, "Promise")) { + error(that)(); + } + + return Promise.all([p1, p2, p3]).then(complete(that, keys => { + return keys.every(key => { + if (key instanceof frames[0].CryptoKey) { + return checkPrototypes(key, "CryptoKey"); + } + + return checkPrototypes(key.publicKey, "CryptoKey") && + checkPrototypes(key.privateKey, "CryptoKey"); + }); + }), error(that)); + } +); +/* ]]>*/</script> +</head> + +<body> + +<div id="content"> + <div id="head"> + <b>Web</b>Crypto<br> + </div> + + <iframe style="display: none;"></iframe> + <div id="start" onclick="start();">RUN ALL</div> + + <div id="resultDiv" class="content"> + Summary: + <span class="pass"><span id="passN">0</span> passed, </span> + <span class="fail"><span id="failN">0</span> failed, </span> + <span class="pending"><span id="pendingN">0</span> pending.</span> + <br/> + <br/> + + <table id="results"> + <tr> + <th>Test</th> + <th>Result</th> + <th>Time</th> + </tr> + </table> + + </div> + + <div id="foot"></div> +</div> + +</body> +</html> |