diff options
Diffstat (limited to 'ext/crypto/00_crypto.js')
-rw-r--r-- | ext/crypto/00_crypto.js | 174 |
1 files changed, 172 insertions, 2 deletions
diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js index 55e1ba9ad..5065df293 100644 --- a/ext/crypto/00_crypto.js +++ b/ext/crypto/00_crypto.js @@ -27,6 +27,7 @@ StringFromCharCode, Symbol, SymbolFor, + SyntaxError, WeakMap, WeakMapPrototypeGet, WeakMapPrototypeSet, @@ -123,6 +124,14 @@ "RSA-OAEP": "RsaOaepParams", "AES-CBC": "AesCbcParams", }, + "get key length": { + "AES-CBC": "AesDerivedKeyParams", + "AES-GCM": "AesDerivedKeyParams", + "AES-KW": "AesDerivedKeyParams", + "HMAC": "HmacImportParams", + "HKDF": null, + "PBKDF2": null, + }, "wrapKey": { // TODO(@littledivy): Enable this once implemented. // "AES-KW": "AesKeyWrapParams", @@ -322,6 +331,67 @@ /** @type {WeakMap<object, object>} */ const KEY_STORE = new WeakMap(); + function getKeyLength(algorithm) { + switch (algorithm.name) { + case "AES-CBC": + case "AES-GCM": + case "AES-KW": { + // 1. + if (!ArrayPrototypeIncludes([128, 192, 256], algorithm.length)) { + throw new DOMException( + "length must be 128, 192, or 256", + "OperationError", + ); + } + + // 2. + return algorithm.length; + } + case "HMAC": { + // 1. + let length; + if (algorithm.length === undefined) { + switch (algorithm.hash.name) { + case "SHA-1": + length = 160; + break; + case "SHA-256": + length = 256; + break; + case "SHA-384": + length = 384; + break; + case "SHA-512": + length = 512; + break; + default: + throw new DOMException( + "Unrecognized hash algorithm", + "NotSupportedError", + ); + } + } else if (algorithm.length !== 0) { + length = algorithm.length; + } else { + throw new TypeError("Invalid length."); + } + + // 2. + return length; + } + case "HKDF": { + // 1. + return null; + } + case "PBKDF2": { + // 1. + return null; + } + default: + throw new TypeError("unreachable"); + } + } + class SubtleCrypto { constructor() { webidl.illegalConstructor(); @@ -1574,13 +1644,13 @@ const result = await deriveBits(normalizedAlgorithm, baseKey, length); // 7. if (normalizedAlgorithm.name !== baseKey[_algorithm].name) { - throw new DOMException("InvalidAccessError", "Invalid algorithm name"); + throw new DOMException("Invalid algorithm name", "InvalidAccessError"); } // 8. if (!ArrayPrototypeIncludes(baseKey[_usages], "deriveBits")) { throw new DOMException( - "InvalidAccessError", "baseKey usages does not contain `deriveBits`", + "InvalidAccessError", ); } // 9-10. @@ -1588,6 +1658,106 @@ } /** + * @param {AlgorithmIdentifier} algorithm + * @param {CryptoKey} baseKey + * @param {number} length + * @returns {Promise<ArrayBuffer>} + */ + async deriveKey( + algorithm, + baseKey, + derivedKeyType, + extractable, + keyUsages, + ) { + webidl.assertBranded(this, SubtleCrypto); + const prefix = "Failed to execute 'deriveKey' on 'SubtleCrypto'"; + webidl.requiredArguments(arguments.length, 5, { prefix }); + algorithm = webidl.converters.AlgorithmIdentifier(algorithm, { + prefix, + context: "Argument 1", + }); + baseKey = webidl.converters.CryptoKey(baseKey, { + prefix, + context: "Argument 2", + }); + derivedKeyType = webidl.converters.AlgorithmIdentifier(derivedKeyType, { + prefix, + context: "Argument 3", + }); + extractable = webidl.converters["boolean"](extractable, { + prefix, + context: "Argument 4", + }); + keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, { + prefix, + context: "Argument 5", + }); + + // 2-3. + const normalizedAlgorithm = normalizeAlgorithm(algorithm, "deriveBits"); + + // 4-5. + const normalizedDerivedKeyAlgorithmImport = normalizeAlgorithm( + derivedKeyType, + "importKey", + ); + + // 6-7. + const normalizedDerivedKeyAlgorithmLength = normalizeAlgorithm( + derivedKeyType, + "get key length", + ); + + // 8-10. + + // 11. + if (normalizedAlgorithm.name !== baseKey[_algorithm].name) { + throw new DOMException( + "Invalid algorithm name", + "InvalidAccessError", + ); + } + + // 12. + if (!ArrayPrototypeIncludes(baseKey[_usages], "deriveKey")) { + throw new DOMException( + "baseKey usages does not contain `deriveKey`", + "InvalidAccessError", + ); + } + + // 13. + const length = getKeyLength(normalizedDerivedKeyAlgorithmLength); + + // 14. + const secret = await this.deriveBits( + normalizedAlgorithm, + baseKey, + length, + ); + + // 15. + const result = await this.importKey( + "raw", + secret, + normalizedDerivedKeyAlgorithmImport, + extractable, + keyUsages, + ); + + // 16. + if ( + ArrayPrototypeIncludes(["private", "secret"], result[_type]) && + keyUsages.length == 0 + ) { + throw new SyntaxError("Invalid key usages"); + } + // 17. + return result; + } + + /** * @param {string} algorithm * @param {CryptoKey} key * @param {BufferSource} signature |