diff options
author | Filip Skokan <panva.ip@gmail.com> | 2022-10-04 08:06:25 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-03 23:06:25 -0700 |
commit | 7742ad77fa94c402d59a890c67a11da55886c68b (patch) | |
tree | 8d70af9ec2ce2176acc16df89fe5146d59fdd6cf /ext/crypto/00_crypto.js | |
parent | fde938116d8b44a87579d6b65dcba79cbe988809 (diff) |
fix(ext/crypto): curve25519 import export (#16140)
Diffstat (limited to 'ext/crypto/00_crypto.js')
-rw-r--r-- | ext/crypto/00_crypto.js | 106 |
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; |