summaryrefslogtreecommitdiffstats
path: root/dom/crypto/test/test_WebCrypto.html
diff options
context:
space:
mode:
Diffstat (limited to 'dom/crypto/test/test_WebCrypto.html')
-rw-r--r--dom/crypto/test/test_WebCrypto.html1234
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>