summaryrefslogtreecommitdiff
path: root/ext/crypto/00_crypto.js
diff options
context:
space:
mode:
authorFilip Skokan <panva.ip@gmail.com>2022-10-04 08:06:25 +0200
committerGitHub <noreply@github.com>2022-10-03 23:06:25 -0700
commit7742ad77fa94c402d59a890c67a11da55886c68b (patch)
tree8d70af9ec2ce2176acc16df89fe5146d59fdd6cf /ext/crypto/00_crypto.js
parentfde938116d8b44a87579d6b65dcba79cbe988809 (diff)
fix(ext/crypto): curve25519 import export (#16140)
Diffstat (limited to 'ext/crypto/00_crypto.js')
-rw-r--r--ext/crypto/00_crypto.js106
1 files changed, 87 insertions, 19 deletions
diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js
index 9134f486b..5e918cc7d 100644
--- a/ext/crypto/00_crypto.js
+++ b/ext/crypto/00_crypto.js
@@ -128,6 +128,7 @@
"AES-CBC": null,
"AES-GCM": null,
"AES-KW": null,
+ "Ed25519": null,
"X25519": null,
},
"deriveBits": {
@@ -1049,6 +1050,10 @@
result = exportKeyEd25519(format, key, innerKey);
break;
}
+ case "X25519": {
+ result = exportKeyX25519(format, key, innerKey);
+ break;
+ }
case "AES-CTR":
case "AES-CBC":
case "AES-GCM":
@@ -2142,7 +2147,7 @@
return constructKey(
"public",
extractable,
- [],
+ usageIntersection(keyUsages, recognisedUsages),
algorithm,
handle,
);
@@ -2173,7 +2178,7 @@
return constructKey(
"public",
extractable,
- [],
+ usageIntersection(keyUsages, recognisedUsages),
algorithm,
handle,
);
@@ -2204,7 +2209,7 @@
return constructKey(
"private",
extractable,
- [],
+ usageIntersection(keyUsages, recognisedUsages),
algorithm,
handle,
);
@@ -2299,7 +2304,7 @@
// 9.
if (jwk.d !== undefined) {
// https://www.rfc-editor.org/rfc/rfc8037#section-2
- const privateKeyData = ops.op_crypto_base64url(jwk.d);
+ const privateKeyData = ops.op_crypto_base64url_decode(jwk.d);
const handle = {};
WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
@@ -2311,13 +2316,13 @@
return constructKey(
"private",
extractable,
- [],
+ usageIntersection(keyUsages, recognisedUsages),
algorithm,
handle,
);
} else {
// https://www.rfc-editor.org/rfc/rfc8037#section-2
- const publicKeyData = ops.op_crypto_base64url(jwk.d);
+ const publicKeyData = ops.op_crypto_base64url_decode(jwk.x);
const handle = {};
WeakMapPrototypeSet(KEY_STORE, handle, publicKeyData);
@@ -2329,7 +2334,7 @@
return constructKey(
"public",
extractable,
- [],
+ usageIntersection(keyUsages, recognisedUsages),
algorithm,
handle,
);
@@ -2422,7 +2427,7 @@
return constructKey(
"private",
extractable,
- [],
+ usageIntersection(keyUsages, recognisedUsages),
algorithm,
handle,
);
@@ -2438,7 +2443,7 @@
keyUsages,
(u) =>
!ArrayPrototypeIncludes(
- SUPPORTED_KEY_USAGES["X25519"].private,
+ ["deriveKey", "deriveBits"],
u,
),
) !== undefined
@@ -2504,7 +2509,7 @@
// 9.
if (jwk.d !== undefined) {
// https://www.rfc-editor.org/rfc/rfc8037#section-2
- const privateKeyData = ops.op_crypto_base64url(jwk.d);
+ const privateKeyData = ops.op_crypto_base64url_decode(jwk.d);
const handle = {};
WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
@@ -2516,13 +2521,13 @@
return constructKey(
"private",
extractable,
- [],
+ usageIntersection(keyUsages, ["deriveKey", "deriveBits"]),
algorithm,
handle,
);
} else {
// https://www.rfc-editor.org/rfc/rfc8037#section-2
- const publicKeyData = ops.op_crypto_base64url(jwk.d);
+ const publicKeyData = ops.op_crypto_base64url_decode(jwk.x);
const handle = {};
WeakMapPrototypeSet(KEY_STORE, handle, publicKeyData);
@@ -3310,9 +3315,6 @@
private: ["deriveKey", "deriveBits"],
jwkUse: "enc",
},
- "X25519": {
- private: ["deriveKey", "deriveBits"],
- },
};
function importKeyRSA(
@@ -4046,13 +4048,16 @@
);
}
- const pkcs8Der = ops.op_export_pkcs8_ed25519(innerKey);
+ const pkcs8Der = ops.op_export_pkcs8_ed25519(
+ new Uint8Array([0x04, 0x22, ...innerKey]),
+ );
+ pkcs8Der[15] = 0x20;
return pkcs8Der.buffer;
}
case "jwk": {
const x = key[_type] === "private"
? ops.op_jwk_x_ed25519(innerKey)
- : ops.op_crypto_base64url(innerKey);
+ : ops.op_crypto_base64url_encode(innerKey);
const jwk = {
kty: "OKP",
alg: "EdDSA",
@@ -4062,7 +4067,7 @@
ext: key[_extractable],
};
if (key[_type] === "private") {
- jwk.d = ops.op_crypto_base64url(innerKey);
+ jwk.d = ops.op_crypto_base64url_encode(innerKey);
}
return jwk;
}
@@ -4071,6 +4076,66 @@
}
}
+ function exportKeyX25519(format, key, innerKey) {
+ switch (format) {
+ case "raw": {
+ // 1.
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key is not a public key",
+ "InvalidAccessError",
+ );
+ }
+
+ // 2-3.
+ return innerKey.buffer;
+ }
+ case "spki": {
+ // 1.
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key is not a public key",
+ "InvalidAccessError",
+ );
+ }
+
+ const spkiDer = ops.op_export_spki_x25519(innerKey);
+ return spkiDer.buffer;
+ }
+ case "pkcs8": {
+ // 1.
+ if (key[_type] !== "private") {
+ throw new DOMException(
+ "Key is not a public key",
+ "InvalidAccessError",
+ );
+ }
+
+ const pkcs8Der = ops.op_export_pkcs8_x25519(
+ new Uint8Array([0x04, 0x22, ...innerKey]),
+ );
+ pkcs8Der[15] = 0x20;
+ return pkcs8Der.buffer;
+ }
+ case "jwk": {
+ if (key[_type] === "private") {
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+ const x = ops.op_crypto_base64url_encode(innerKey);
+ const jwk = {
+ kty: "OKP",
+ crv: "X25519",
+ x,
+ "key_ops": key.usages,
+ ext: key[_extractable],
+ };
+ return jwk;
+ }
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+ }
+
function exportKeyEC(format, key, innerKey) {
switch (format) {
case "raw": {
@@ -4391,7 +4456,10 @@
// 7.
if (length === null) {
return secret.buffer;
- } else if (secret.length * 8 < length) {
+ } else if (
+ length === 0 || secret.buffer.byteLength * 8 < length ||
+ secret.length * 8 < length
+ ) {
throw new DOMException("Invalid length", "OperationError");
} else {
return secret.subarray(0, length / 8).buffer;