blob: 0e08d43fdc66087662e78a468bedd0a73fb98d6b [file] [log] [blame]
<script>
function log(msg)
{
// alert(msg);
window.webkit.messageHandlers.testHandler.postMessage(msg);
}
function shouldBeType(_a, _type)
{
let exception;
let _av;
try {
_av = eval(_a);
} catch (e) {
exception = e;
}
const _typev = eval(_type);
if (_av instanceof _typev) {
return true;
} else {
return false;
}
}
function shouldBeCryptoKey(_a, _key)
{
if (!(JSON.stringify(_key.key_ops) == JSON.stringify(_a.key_ops)) || !(_key.ext == _a.ext))
return false;
if (_key.kty == "oct" && _a.kty == "oct")
return (_key.k == _a.k) && (_key.alg == _a.alg);
if (_key.kty == "EC" && _a.kty == "EC")
return (_key.k == _a.k) && (_key.crv == _a.crv) && (_key.x == _a.x) && (_key.y == _a.y) && (_key.d == _a.d);
if (_key.kty == "RSA" && _a.kty == "RSA")
return (_key.alg == _a.alg) && (_key.n == _a.n) && (_key.e == _a.e) && (_key.d == _a.d) && (_key.p == _a.p) && (_key.q == _a.q) && (_key.dp == _a.dp) && (_key.dq == _a.dq) && (_key.qi == _a.qi);
return false;
}
// Values that are used to infer the type of a given primitive type.
const testValues = [
undefined,
null,
5, // Int
0,
1,
false,
true,
5.5, // Double
"Hello,World!",
""
];
// Values that are used to infer the type of a given Boolean/String type.
const testTypeValues = [
{ item: new Boolean(true), type: "Boolean", value: true },
{ item: new Boolean(false), type: "Boolean", value: false },
{ item: new String(), type: "String", value: "" }
];
// Values are in JWK formats.
const testCryptoKeyValues = [
{ kty: "oct", k: "YWJjZGVmZ2gxMjM0NTY3OA", alg: "A128CBC", use: "enc", key_ops: ['decrypt', 'encrypt', 'unwrapKey', 'wrapKey'], ext: true },
{ kty: "EC", use: "sig", ext: true, crv: "P-256", x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA", y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI", key_ops: ['verify'] },
{ kty: "EC", use: "sig", ext: true, key_ops: ["sign"], crv: "P-256", x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA", y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI", d: "ppxBSov3N8_AUcisAuvmLV4yE8e_L_BLE8bZb9Z1Xjg" },
{ kty: "oct", k: "YWJjZGVmZ2gxMjM0NTY3OA", alg: "HS256", use: "sig", key_ops: ["sign", "verify"], ext: true, },
{ kty: "RSA", alg: "PS256", use: "sig", key_ops: ["verify"], ext: true, n: "rcCUCv7Oc1HVam1DIhCzqknThWawOp8QLk8Ziy2p10ByjQFCajoFiyuAWl-R1WXZaf4xitLRracT9agpzIzc-MbLSHIGgWQGO21lGiImy5ftZ-D8bHAqRz2y15pzD4c4CEou7XSSLDoRnR0QG5MsDhD6s2gV9mwHkrtkCxtMWdBi-77as8wGmlNRldcOSgZDLK8UnCSgA1OguZ989bFyc8tOOEIb0xUSfPSz3LPSCnyYz68aDjmKVeNH-ig857OScyWbGyEy3Biw64qun3juUlNWsJ3zngkOdteYWytx5Qr4XKNs6R-Myyq72KUp02mJDZiiyiglxML_i3-_CeecCw", e: "AQAB" },
{ kty: "RSA", alg: "PS1", use: "sig", key_ops: ["sign"], ext: true, n: "rcCUCv7Oc1HVam1DIhCzqknThWawOp8QLk8Ziy2p10ByjQFCajoFiyuAWl-R1WXZaf4xitLRracT9agpzIzc-MbLSHIGgWQGO21lGiImy5ftZ-D8bHAqRz2y15pzD4c4CEou7XSSLDoRnR0QG5MsDhD6s2gV9mwHkrtkCxtMWdBi-77as8wGmlNRldcOSgZDLK8UnCSgA1OguZ989bFyc8tOOEIb0xUSfPSz3LPSCnyYz68aDjmKVeNH-ig857OScyWbGyEy3Biw64qun3juUlNWsJ3zngkOdteYWytx5Qr4XKNs6R-Myyq72KUp02mJDZiiyiglxML_i3-_CeecCw", e: "AQAB", d: "eNLS37aCz7RXSNPD_DtLBJ6j5T8cSxdzRBCjPaI6WcGqJp16lq3UTwuoDLAqlA9oGYm238dsIWpuucP_lQtbWe-7SpxoI6_vmYGf7YVUHv1-DF9qiOmSrMmdxMnVOzYXY8RaT6thPjn_J5cfLV2xI_LwsrMtmpdSyNlgX0zTUhwtuahgAKMEChYjH2EnjHdHw6sY2-wApdcQI7ULE0oo5RzbQZpmuhcN9hiBc0L3hhF0qo50mbl02_65_GQ7DpVkXBxNgRBLzlPabmzzG2oAhfefLgYmSC1opaCkXE6vRWQNWNL45RZNZFYM3uoJghOMqGeocM0BpjdChHrPOlFvSQ", p: "4miTuAjKMeH5uJ5KB397QUwhbkYEgSbcA2mifmSkvE2018gb55qkBHK1eVryf1_m43LNlc6O_ak6gfzdZIZvS5NCGjPl0q09plUpu8qFOSspBwA67qGH76lFlZLn_d4yglS7wfLru4_5Ys8qLLs-DqVLviwposOnyyWqwM5AXp0", q: "xHYrzkivtmnz_sGchnWGc0q-pDOkKicptRpv2pMFIIXxnFX5aMeEXIZjVujXtwUy1UlFIN2GZJSvy5KJ79mu_XyNnFHMzedH-A3ee3u8h1UUrZF-vUu1_e4U_x67NN1dedzUSKynN7pFl3OkuShMBWGV-cwzOPdcVAfVuZlxUMc", dp: "fBzDzYDUBmBQGop7Hn0dvf_T27V6RqpctWo074CQZcFbP2atFVtKSj3viWT3xid2VHzcgiDHdfpM3nEVlEO1wwIonGCSvdjGEOZiiFVOjrZAOVxA8guOjyyFvqbXke06VwPIIVvfKeSU2zuhbP__1tt6F_fxow4Kb2xonGT0GGk", dq: "jmE2DiIPdhwDgLXAQpIaBqQ81bO3XfVT_LRULAwwwwlPuQV148H04zlh9TJ6Y2GZHYokV1U0eOBpJxfkb7dLYtpJpuiBjRf4yIUEoGlkkI_QlJnFSFr-YjGRdfNHqWBkxlSMZL770R9mIATndGkH7z5x-r9KwBZFC4FCG2hg_zE", qi: "YCX_pLwbMBA1ThVH0WcwmnytqNcrMCEwTm7ByA2eU6nWbQrULvf7m9_kzfLUcjsnpAVlBQG5JMXMy0Sq4ptwbywsa5-G8KAOOOR2L3v4hC-Eys9ftgFM_3i0o40eeQH4b3haPbntrIeMg8IzlOuVYKf9-2QuKDoWeRdd7NsdxTk" }
];
indexedDB.deleteDatabase("backward_compatibility");
const openRequest = indexedDB.open("backward_compatibility");
openRequest.onupgradeneeded = function(event) {
// This objectStore stores elements that we only need to check its type to determine its serialization tag.
event.target.result.createObjectStore("type");
// This objectStore stores elements that we need to check its value to determine its serialization tag.
event.target.result.createObjectStore("value", { autoIncrement : true });
// This objectStore stores elements that we need to check both its type and its value to determine its serialization tag.
event.target.result.createObjectStore("typeValue", { autoIncrement : true });
// This objectStore stores crypto keys.
event.target.result.createObjectStore("cryptoKey", { autoIncrement : true });
};
openRequest.onerror = function(event) {
log("Error: " + event.target.error.name);
};
openRequest.onsuccess = function(event) {
db = event.target.result;
storeType();
};
function storeType()
{
const transaction = db.transaction("type", "readwrite");
transaction.onerror = function(event) {
log("Error: " + event.target.error.name);
};
transaction.oncomplete = function(event) { storeValue(); };
const objectStore = transaction.objectStore("type");
// The key of an item is the type of its value, hence we could determine type mismatch, i.e. serialization tag reorder
// simply by using an item's key and value.
objectStore.add([1, 2], "Array");
objectStore.add({ property: null }, "Object");
objectStore.add(new Date(), "Date");
objectStore.add(new File(["foo"], "foo.txt"), "File");
objectStore.add(new ImageData(100, 100), "ImageData");
objectStore.add(new Blob(["foo"]), "Blob");
objectStore.add(new RegExp(''), "RegExp");
objectStore.add(new ArrayBuffer(1), "ArrayBuffer");
objectStore.add(new String(''), "String");
objectStore.add(new Number(12), "Number");
objectStore.add(new Set([1, 2]), "Set");
objectStore.add(new Map(), "Map");
// Typed arrays
objectStore.add(new Int8Array(), "Int8Array");
objectStore.add(new Uint8Array(), "Uint8Array");
objectStore.add(new Uint8ClampedArray(), "Uint8ClampedArray");
objectStore.add(new Int16Array(), "Int16Array");
objectStore.add(new Uint16Array(), "Uint16Array");
objectStore.add(new Int32Array(), "Int32Array");
objectStore.add(new Uint32Array(), "Uint32Array");
objectStore.add(new Float32Array(), "Float32Array");
objectStore.add(new Float64Array(), "Float64Array");
}
function storeValue()
{
const transaction = db.transaction("value", "readwrite");
transaction.onerror = function(event) {
log("Error: " + event.target.error.name);
};
transaction.oncomplete = function(event) { storeTypeValue(); };
const objectStore = transaction.objectStore("value");
// Here we store values in the test matrix in order and read them in order to see if any mismatch happens.
for (let i = 0; i < testValues.length; i++)
objectStore.add(testValues[i]);
}
function storeTypeValue()
{
const transaction = db.transaction("typeValue", "readwrite");
transaction.onerror = function(event) {
log("Error: " + event.target.error.name);
};
transaction.oncomplete = function(event) { storeCryptoKey(); };
const objectStore = transaction.objectStore("typeValue");
// Here we store items in the test matrix in order and read them in order to see if any mismatches its type and value.
for (let i = 0; i < testTypeValues.length; i++)
objectStore.add(testTypeValues[i].item);
}
async function storeCryptoKey()
{
const transaction = db.transaction("cryptoKey", "readwrite");
transaction.onerror = function(event) {
log("Error: " + event.target.error.name);
};
transaction.oncomplete = function(event) { readType(); };
const objectStore = transaction.objectStore("cryptoKey");
// Here we store items in the test matrix in order and read them in order to see if any mismatches its type and value.
let cryptoKey = await crypto.subtle.importKey("jwk", testCryptoKeyValues[0], "aes-cbc", true, ["encrypt", "decrypt", "wrapKey", "unwrapKey"]);
objectStore.add(cryptoKey);
cryptoKey = await crypto.subtle.importKey("jwk", testCryptoKeyValues[1], { name: "ECDSA", namedCurve: "P-256" }, true, ['verify']);
objectStore.add(cryptoKey);
cryptoKey = await crypto.subtle.importKey("jwk", testCryptoKeyValues[2], { name: "ECDSA", namedCurve: "P-256" }, true, ["sign"]);
objectStore.add(cryptoKey);
cryptoKey = await crypto.subtle.importKey("jwk", testCryptoKeyValues[3], {name: "hmac", hash: "sha-256"}, true, ["sign", "verify"]);
objectStore.add(cryptoKey);
cryptoKey = await crypto.subtle.importKey("jwk", testCryptoKeyValues[4], {name: "RSA-PSS", hash: "SHA-256"}, true, ["verify"]);
objectStore.add(cryptoKey);
cryptoKey = await crypto.subtle.importKey("jwk", testCryptoKeyValues[5], {name: "RSA-PSS", hash: "SHA-1"}, true, ["sign"]);
objectStore.add(cryptoKey);
}
let result = true;
function readType()
{
const objectStore = db.transaction("type").objectStore("type");
objectStore.openCursor().onsuccess = function(event) {
cursor = event.target.result;
if (cursor) {
result = result && shouldBeType("cursor.value", cursor.key);
cursor.continue();
} else
readValue();
};
}
function readValue()
{
const objectStore = db.transaction("value").objectStore("value");
objectStore.openCursor().onsuccess = function(event) {
cursor = event.target.result;
if (cursor) {
result = result && (cursor.value === testValues[cursor.key - 1]);
cursor.continue();
} else
readTypeValue();
};
}
function readTypeValue()
{
const objectStore = db.transaction("typeValue").objectStore("typeValue");
objectStore.openCursor().onsuccess = function(event) {
cursor = event.target.result;
if (cursor) {
result = result && shouldBeType("cursor.value", testTypeValues[cursor.key - 1].type) && (cursor.value == testTypeValues[cursor.key - 1].value);
cursor.continue();
} else {
readCryptoKey();
}
};
}
async function readCryptoKey()
{
const objectStore = db.transaction("cryptoKey").objectStore("cryptoKey");
objectStore.openCursor().onsuccess = async function(event) {
cursor = event.target.result;
if (cursor) {
const jwkKey = await crypto.subtle.exportKey("jwk", cursor.value);
result = result && shouldBeCryptoKey(jwkKey, testCryptoKeyValues[cursor.key - 1]);
cursor.continue();
} else {
if (result)
log("Pass");
else
log("Fail");
}
};
}
</script>