summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDivy Srivastava <dj.srivastava23@gmail.com>2021-08-29 17:53:51 +0530
committerGitHub <noreply@github.com>2021-08-29 14:23:51 +0200
commit5ee211017912bc0837cbce3b845e6ab4a7887885 (patch)
tree8f71f0dff5013e422f56e61e5b1623d29a3fd0f8
parent8a097410a8df3195681305818035ab7dde41452b (diff)
feat(ext/crypto): support JWK export for HMAC (#11864)
-rw-r--r--cli/tests/unit/webcrypto_test.ts11
-rw-r--r--ext/crypto/00_crypto.js49
-rw-r--r--ext/crypto/lib.deno_crypto.d.ts8
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,