1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
|
<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>
|