summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/tests/unit/webcrypto_test.ts37
-rw-r--r--ext/crypto/00_crypto.js102
-rw-r--r--ext/crypto/lib.deno_crypto.d.ts6
-rw-r--r--tools/wpt/expectation.json3
4 files changed, 145 insertions, 3 deletions
diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts
index 56a23bfb5..493cf9517 100644
--- a/cli/tests/unit/webcrypto_test.ts
+++ b/cli/tests/unit/webcrypto_test.ts
@@ -499,3 +499,40 @@ unitTest(async function testHkdfDeriveBits() {
);
assertEquals(result.byteLength, 128 / 8);
});
+
+unitTest(async function testWrapKey() {
+ // Test wrapKey
+ const key = await crypto.subtle.generateKey(
+ {
+ name: "RSA-OAEP",
+ modulusLength: 4096,
+ publicExponent: new Uint8Array([1, 0, 1]),
+ hash: "SHA-256",
+ },
+ true,
+ ["wrapKey", "unwrapKey"],
+ );
+
+ const hmacKey = await crypto.subtle.generateKey(
+ {
+ name: "HMAC",
+ hash: "SHA-256",
+ length: 128,
+ },
+ true,
+ ["sign"],
+ );
+
+ const wrappedKey = await crypto.subtle.wrapKey(
+ "raw",
+ hmacKey,
+ key.publicKey,
+ {
+ name: "RSA-OAEP",
+ label: new Uint8Array(8),
+ },
+ );
+
+ assert(wrappedKey instanceof ArrayBuffer);
+ assertEquals(wrappedKey.byteLength, 512);
+});
diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js
index a503d316a..fdd0f612d 100644
--- a/ext/crypto/00_crypto.js
+++ b/ext/crypto/00_crypto.js
@@ -120,6 +120,10 @@
"decrypt": {
"RSA-OAEP": "RsaOaepParams",
},
+ "wrapKey": {
+ // TODO(@littledivy): Enable this once implemented.
+ // "AES-KW": "AesKeyWrapParams",
+ },
};
// Decodes the unpadded base64 to the octet sequence containing key value `k` defined in RFC7518 Section 6.4
@@ -1525,6 +1529,104 @@
* @param {KeyUsage[]} keyUsages
* @returns {Promise<any>}
*/
+ async wrapKey(format, key, wrappingKey, wrapAlgorithm) {
+ webidl.assertBranded(this, SubtleCrypto);
+ const prefix = "Failed to execute 'wrapKey' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 4, { prefix });
+ format = webidl.converters.KeyFormat(format, {
+ prefix,
+ context: "Argument 1",
+ });
+ key = webidl.converters.CryptoKey(key, {
+ prefix,
+ context: "Argument 2",
+ });
+ wrappingKey = webidl.converters.CryptoKey(wrappingKey, {
+ prefix,
+ context: "Argument 3",
+ });
+ wrapAlgorithm = webidl.converters.AlgorithmIdentifier(wrapAlgorithm, {
+ prefix,
+ context: "Argument 4",
+ });
+
+ let normalizedAlgorithm;
+
+ try {
+ // 2.
+ normalizedAlgorithm = normalizeAlgorithm(wrapAlgorithm, "wrapKey");
+ } catch (_) {
+ // 3.
+ normalizedAlgorithm = normalizeAlgorithm(wrapAlgorithm, "encrypt");
+ }
+
+ // 8.
+ if (normalizedAlgorithm.name !== wrappingKey[_algorithm].name) {
+ throw new DOMException(
+ "Wrapping algorithm doesn't match key algorithm.",
+ "InvalidAccessError",
+ );
+ }
+
+ // 9.
+ if (!ArrayPrototypeIncludes(wrappingKey[_usages], "wrapKey")) {
+ throw new DOMException(
+ "Key does not support the 'wrapKey' operation.",
+ "InvalidAccessError",
+ );
+ }
+
+ // 10. NotSupportedError will be thrown in step 12.
+ // 11.
+ if (key[_extractable] === false) {
+ throw new DOMException(
+ "Key is not extractable",
+ "InvalidAccessError",
+ );
+ }
+
+ // 12.
+ const exportedKey = await this.exportKey(format, key);
+
+ let bytes;
+ // 13.
+ if (format !== "jwk") {
+ bytes = exportedKey;
+ } else {
+ // TODO(@littledivy): Implement JWK.
+ throw new DOMException(
+ "Not implemented",
+ "NotSupportedError",
+ );
+ }
+
+ // 14-15.
+ if (
+ supportedAlgorithms["wrapKey"][normalizedAlgorithm.name] !== undefined
+ ) {
+ // TODO(@littledivy): Implement this for AES-KW.
+ throw new DOMException(
+ "Not implemented",
+ "NotSupportedError",
+ );
+ } else if (
+ supportedAlgorithms["encrypt"][normalizedAlgorithm.name] !== undefined
+ ) {
+ return this.encrypt(normalizedAlgorithm, wrappingKey, bytes);
+ } else {
+ throw new DOMException(
+ "Algorithm not supported",
+ "NotSupportedError",
+ );
+ }
+ }
+
+ /**
+ * @param {string} algorithm
+ * @param {boolean} extractable
+ * @param {KeyUsage[]} keyUsages
+ * @returns {Promise<any>}
+ */
async generateKey(algorithm, extractable, keyUsages) {
webidl.assertBranded(this, SubtleCrypto);
const prefix = "Failed to execute 'generateKey' on 'SubtleCrypto'";
diff --git a/ext/crypto/lib.deno_crypto.d.ts b/ext/crypto/lib.deno_crypto.d.ts
index 55b94c24d..3dd66d59a 100644
--- a/ext/crypto/lib.deno_crypto.d.ts
+++ b/ext/crypto/lib.deno_crypto.d.ts
@@ -215,6 +215,12 @@ interface SubtleCrypto {
baseKey: CryptoKey,
length: number,
): Promise<ArrayBuffer>;
+ wrapKey(
+ format: KeyFormat,
+ key: CryptoKey,
+ wrappingKey: CryptoKey,
+ wrapAlgorithm: AlgorithmIdentifier | RsaOaepParams,
+ ): Promise<ArrayBuffer>;
}
declare interface Crypto {
diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json
index 5235c1828..72c276d7b 100644
--- a/tools/wpt/expectation.json
+++ b/tools/wpt/expectation.json
@@ -12149,12 +12149,9 @@
"historical.any.html": false,
"idlharness.https.any.html": [
"SubtleCrypto interface: operation deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>)",
- "SubtleCrypto interface: operation wrapKey(KeyFormat, CryptoKey, CryptoKey, AlgorithmIdentifier)",
"SubtleCrypto interface: operation unwrapKey(KeyFormat, BufferSource, CryptoKey, AlgorithmIdentifier, AlgorithmIdentifier, boolean, sequence<KeyUsage>)",
"SubtleCrypto interface: crypto.subtle must inherit property \"deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>)\" with the proper type",
"SubtleCrypto interface: calling deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>) on crypto.subtle with too few arguments must throw TypeError",
- "SubtleCrypto interface: crypto.subtle must inherit property \"wrapKey(KeyFormat, CryptoKey, CryptoKey, AlgorithmIdentifier)\" with the proper type",
- "SubtleCrypto interface: calling wrapKey(KeyFormat, CryptoKey, CryptoKey, AlgorithmIdentifier) on crypto.subtle with too few arguments must throw TypeError",
"SubtleCrypto interface: crypto.subtle must inherit property \"unwrapKey(KeyFormat, BufferSource, CryptoKey, AlgorithmIdentifier, AlgorithmIdentifier, boolean, sequence<KeyUsage>)\" with the proper type",
"SubtleCrypto interface: calling unwrapKey(KeyFormat, BufferSource, CryptoKey, AlgorithmIdentifier, AlgorithmIdentifier, boolean, sequence<KeyUsage>) on crypto.subtle with too few arguments must throw TypeError",
"Window interface: attribute crypto"