summaryrefslogtreecommitdiff
path: root/ext/crypto/00_crypto.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/crypto/00_crypto.js')
-rw-r--r--ext/crypto/00_crypto.js446
1 files changed, 247 insertions, 199 deletions
diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js
index c23fd5a36..311dcfbf1 100644
--- a/ext/crypto/00_crypto.js
+++ b/ext/crypto/00_crypto.js
@@ -142,6 +142,29 @@
},
};
+ const aesJwkAlg = {
+ "AES-CTR": {
+ 128: "A128CTR",
+ 192: "A192CTR",
+ 256: "A256CTR",
+ },
+ "AES-CBC": {
+ 128: "A128CBC",
+ 192: "A192CBC",
+ 256: "A256CBC",
+ },
+ "AES-GCM": {
+ 128: "A128GCM",
+ 192: "A192GCM",
+ 256: "A256GCM",
+ },
+ "AES-KW": {
+ 128: "A128KW",
+ 192: "A192KW",
+ 256: "A256KW",
+ },
+ };
+
// Decodes the unpadded base64 to the octet sequence containing key value `k` defined in RFC7518 Section 6.4
function decodeSymmetricKey(key) {
// Decode from base64url without `=` padding.
@@ -1342,44 +1365,13 @@
throw new DOMException("Invalid key usages", "SyntaxError");
}
- // 2.
- switch (format) {
- case "raw": {
- // 2.
- if (
- !ArrayPrototypeIncludes([128, 192, 256], keyData.byteLength * 8)
- ) {
- throw new DOMException("Invalid key length", "Datarror");
- }
-
- break;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "raw",
- data: keyData,
- });
-
- // 4-7.
- const algorithm = {
- name: "AES-CTR",
- length: keyData.byteLength * 8,
- };
-
- const key = constructKey(
- "secret",
- false,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
+ return importKeyAES(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
);
-
- // 8.
- return key;
}
case "AES-CBC": {
// 1.
@@ -1397,45 +1389,13 @@
) {
throw new DOMException("Invalid key usages", "SyntaxError");
}
-
- // 2.
- switch (format) {
- case "raw": {
- // 2.
- if (
- !ArrayPrototypeIncludes([128, 192, 256], keyData.byteLength * 8)
- ) {
- throw new DOMException("Invalid key length", "Datarror");
- }
-
- break;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "raw",
- data: keyData,
- });
-
- // 4-7.
- const algorithm = {
- name: "AES-CBC",
- length: keyData.byteLength * 8,
- };
-
- const key = constructKey(
- "secret",
- false,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
+ return importKeyAES(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
);
-
- // 8.
- return key;
}
case "AES-GCM": {
// 1.
@@ -1454,44 +1414,13 @@
throw new DOMException("Invalid key usages", "SyntaxError");
}
- // 2.
- switch (format) {
- case "raw": {
- // 2.
- if (
- !ArrayPrototypeIncludes([128, 192, 256], keyData.byteLength * 8)
- ) {
- throw new DOMException("Invalid key length", "Datarror");
- }
-
- break;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "raw",
- data: keyData,
- });
-
- // 4-7.
- const algorithm = {
- name: "AES-GCM",
- length: keyData.byteLength * 8,
- };
-
- const key = constructKey(
- "secret",
- false,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
+ return importKeyAES(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
);
-
- // 8.
- return key;
}
case "AES-KW": {
// 1.
@@ -1508,44 +1437,13 @@
throw new DOMException("Invalid key usages", "SyntaxError");
}
- // 2.
- switch (format) {
- case "raw": {
- // 2.
- if (
- !ArrayPrototypeIncludes([128, 192, 256], keyData.byteLength * 8)
- ) {
- throw new DOMException("Invalid key length", "Datarror");
- }
-
- break;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "raw",
- data: keyData,
- });
-
- // 4-7.
- const algorithm = {
- name: "AES-KW",
- length: keyData.byteLength * 8,
- };
-
- const key = constructKey(
- "secret",
- false,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
+ return importKeyAES(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
);
-
- // 8.
- return key;
}
default:
throw new DOMException("Not implemented", "NotSupportedError");
@@ -1786,57 +1684,11 @@
throw new DOMException("Not implemented", "NotSupportedError");
}
}
- case "AES-CTR": {
- switch (format) {
- // 2.
- case "raw": {
- // 1.
- const data = innerKey.data;
- // 2.
- return data.buffer;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
- case "AES-CBC": {
- switch (format) {
- // 2.
- case "raw": {
- // 1.
- const data = innerKey.data;
- // 2.
- return data.buffer;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
- case "AES-GCM": {
- switch (format) {
- // 2.
- case "raw": {
- // 1.
- const data = innerKey.data;
- // 2.
- return data.buffer;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
+ case "AES-CTR":
+ case "AES-CBC":
+ case "AES-GCM":
case "AES-KW": {
- switch (format) {
- // 2.
- case "raw": {
- // 1.
- const data = innerKey.data;
- // 2.
- return data.buffer;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
+ return exportKeyAES(format, key, innerKey);
}
// TODO(@littledivy): ECDSA
default:
@@ -2591,6 +2443,202 @@
}
}
+ function exportKeyAES(
+ format,
+ key,
+ innerKey,
+ ) {
+ switch (format) {
+ // 2.
+ case "raw": {
+ // 1.
+ const data = innerKey.data;
+ // 2.
+ return data.buffer;
+ }
+ case "jwk": {
+ // 1-3.
+ const jwk = {
+ kty: "oct",
+ k: unpaddedBase64(innerKey.data),
+ };
+
+ // 4.
+ const algorithm = key[_algorithm];
+ switch (algorithm.length) {
+ case 128:
+ jwk.alg = aesJwkAlg[algorithm.name][128];
+ break;
+ case 192:
+ jwk.alg = aesJwkAlg[algorithm.name][192];
+ break;
+ case 256:
+ jwk.alg = aesJwkAlg[algorithm.name][256];
+ break;
+ default:
+ throw new DOMException(
+ "Invalid key length",
+ "NotSupportedError",
+ );
+ }
+
+ // 5.
+ jwk.key_ops = key[_usages];
+ // 6.
+ jwk.ext = key[_extractable];
+ // 7.
+ return jwk;
+ }
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+ }
+
+ function importKeyAES(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
+ ) {
+ // 2.
+ let data = keyData;
+ switch (format) {
+ case "raw": {
+ // 2.
+ if (
+ !ArrayPrototypeIncludes([128, 192, 256], keyData.byteLength * 8)
+ ) {
+ throw new DOMException("Invalid key length", "Datarror");
+ }
+
+ break;
+ }
+ case "jwk": {
+ // 1.
+ const jwk = keyData;
+ // 2.
+ if (jwk.kty !== "oct") {
+ throw new DOMException(
+ "`kty` member of JsonWebKey must be `oct`",
+ "DataError",
+ );
+ }
+
+ // Section 6.4.1 of RFC7518
+ if (jwk.k === undefined) {
+ throw new DOMException(
+ "`k` member of JsonWebKey must be present",
+ "DataError",
+ );
+ }
+
+ // 4.
+ data = decodeSymmetricKey(jwk.k);
+
+ // 5.
+ switch (data.byteLength * 8) {
+ case 128:
+ if (
+ jwk.alg !== undefined &&
+ jwk.alg !== aesJwkAlg[normalizedAlgorithm.name][128]
+ ) {
+ throw new DOMException("Invalid algorithm", "DataError");
+ }
+ break;
+ case 192:
+ if (
+ jwk.alg !== undefined &&
+ jwk.alg !== aesJwkAlg[normalizedAlgorithm.name][192]
+ ) {
+ throw new DOMException("Invalid algorithm", "DataError");
+ }
+ break;
+ case 256:
+ if (
+ jwk.alg !== undefined &&
+ jwk.alg !== aesJwkAlg[normalizedAlgorithm.name][256]
+ ) {
+ throw new DOMException("Invalid algorithm", "DataError");
+ }
+ break;
+ default:
+ throw new DOMException(
+ "Invalid key length",
+ "DataError",
+ );
+ }
+
+ // 6.
+ if (keyUsages.length > 0 && jwk.use && jwk.use !== "enc") {
+ throw new DOMException("Invalid key usages", "DataError");
+ }
+
+ // 7.
+ // Section 4.3 of RFC7517
+ if (jwk.key_ops) {
+ if (
+ ArrayPrototypeFind(
+ jwk.key_ops,
+ (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
+ ) !== undefined
+ ) {
+ throw new DOMException(
+ "`key_ops` member of JsonWebKey is invalid",
+ "DataError",
+ );
+ }
+
+ if (
+ !ArrayPrototypeEvery(
+ jwk.key_ops,
+ (u) => ArrayPrototypeIncludes(keyUsages, u),
+ )
+ ) {
+ throw new DOMException(
+ "`key_ops` member of JsonWebKey is invalid",
+ "DataError",
+ );
+ }
+ }
+
+ // 8.
+ if (jwk.ext === false && extractable == true) {
+ throw new DOMException(
+ "`ext` member of JsonWebKey is invalid",
+ "DataError",
+ );
+ }
+
+ break;
+ }
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "raw",
+ data,
+ });
+
+ // 4-7.
+ const algorithm = {
+ name: normalizedAlgorithm.name,
+ length: data.byteLength * 8,
+ };
+
+ const key = constructKey(
+ "secret",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ // 8.
+ return key;
+ }
async function generateKeyAES(normalizedAlgorithm, extractable, usages) {
// 2.
if (!ArrayPrototypeIncludes([128, 192, 256], normalizedAlgorithm.length)) {