diff options
author | Divy Srivastava <dj.srivastava23@gmail.com> | 2021-08-29 17:53:51 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-29 14:23:51 +0200 |
commit | 5ee211017912bc0837cbce3b845e6ab4a7887885 (patch) | |
tree | 8f71f0dff5013e422f56e61e5b1623d29a3fd0f8 | |
parent | 8a097410a8df3195681305818035ab7dde41452b (diff) |
feat(ext/crypto): support JWK export for HMAC (#11864)
-rw-r--r-- | cli/tests/unit/webcrypto_test.ts | 11 | ||||
-rw-r--r-- | ext/crypto/00_crypto.js | 49 | ||||
-rw-r--r-- | ext/crypto/lib.deno_crypto.d.ts | 8 |
3 files changed, 61 insertions, 7 deletions
diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts index a37e32eba..475efde6c 100644 --- a/cli/tests/unit/webcrypto_test.ts +++ b/cli/tests/unit/webcrypto_test.ts @@ -254,6 +254,8 @@ const jwk: JsonWebKey = { // unpadded base64 for rawKey. k: "AQIDBAUGBwgJCgsMDQ4PEA", alg: "HS256", + ext: true, + "key_ops": ["sign"], }; unitTest(async function subtleCryptoHmacImportExport() { @@ -297,7 +299,10 @@ unitTest(async function subtleCryptoHmacImportExport() { new Uint8Array(actual2), expected, ); - // TODO(@littledivy): Add a test for exporting JWK key when supported. - const exportedKey = await crypto.subtle.exportKey("raw", key1); - assertEquals(new Uint8Array(exportedKey), rawKey); + + const exportedKey1 = await crypto.subtle.exportKey("raw", key1); + assertEquals(new Uint8Array(exportedKey1), rawKey); + + const exportedKey2 = await crypto.subtle.exportKey("jwk", key2); + assertEquals(exportedKey2, jwk); }); diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js index 375170ad9..ab6347d41 100644 --- a/ext/crypto/00_crypto.js +++ b/ext/crypto/00_crypto.js @@ -12,7 +12,7 @@ const core = window.Deno.core; const webidl = window.__bootstrap.webidl; const { DOMException } = window.__bootstrap.domException; - const { atob } = window.__bootstrap.base64; + const { atob, btoa } = window.__bootstrap.base64; const { ArrayPrototypeFind, @@ -122,6 +122,13 @@ return keyBytes; } + function unpaddedBase64(bytes) { + const binaryString = core.decode(bytes); + const base64String = btoa(binaryString); + + return StringPrototypeReplace(base64String, /=/g, ""); + } + // See https://www.w3.org/TR/WebCryptoAPI/#dfn-normalize-an-algorithm // 18.4.4 function normalizeAlgorithm(algorithm, op) { @@ -970,10 +977,48 @@ // 4-5. return bits.buffer; } - // TODO(@littledivy): jwk + case "jwk": { + // 1-3. + const jwk = { + kty: "oct", + k: unpaddedBase64(innerKey.data), + }; + // 4. + const algorithm = key[_algorithm]; + // 5. + const hash = algorithm.hash; + // 6. + switch (hash.name) { + case "SHA-1": + jwk.alg = "HS1"; + break; + case "SHA-256": + jwk.alg = "HS256"; + break; + case "SHA-384": + jwk.alg = "HS384"; + break; + case "SHA-512": + jwk.alg = "HS512"; + break; + default: + throw new DOMException( + "Hash algorithm not supported", + "NotSupportedError", + ); + } + // 7. + jwk.key_ops = key.usages; + // 8. + jwk.ext = key[_extractable]; + // 9. + return jwk; + } default: throw new DOMException("Not implemented", "NotSupportedError"); } + // TODO(@littledivy): Redundant break but deno_lint complains without it + break; } // TODO(@littledivy): RSASSA-PKCS1-v1_5 // TODO(@littledivy): RSA-PSS diff --git a/ext/crypto/lib.deno_crypto.d.ts b/ext/crypto/lib.deno_crypto.d.ts index 2e8d2f8b2..5169e5c3b 100644 --- a/ext/crypto/lib.deno_crypto.d.ts +++ b/ext/crypto/lib.deno_crypto.d.ts @@ -25,7 +25,7 @@ type KeyUsage = | "unwrapKey" | "verify" | "wrapKey"; - +type KeyFormat = "jwk" | "pkcs8" | "raw" | "spki"; type NamedCurve = string; interface RsaOtherPrimesInfo { @@ -164,7 +164,11 @@ interface SubtleCrypto { extractable: boolean, keyUsages: KeyUsage[], ): Promise<CryptoKey>; - exportKey(format: "raw", key: CryptoKey): Promise<ArrayBuffer>; + exportKey(format: "jwk", key: CryptoKey): Promise<JsonWebKey>; + exportKey( + format: Exclude<KeyFormat, "jwk">, + key: CryptoKey, + ): Promise<ArrayBuffer>; sign( algorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams, key: CryptoKey, |