diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2021-08-11 12:27:05 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-11 12:27:05 +0200 |
commit | a0285e2eb88f6254f6494b0ecd1878db3a3b2a58 (patch) | |
tree | 90671b004537e20f9493fd3277ffd21d30b39a0e /extensions/crypto | |
parent | 3a6994115176781b3a93d70794b1b81bc95e42b4 (diff) |
Rename extensions/ directory to ext/ (#11643)
Diffstat (limited to 'extensions/crypto')
-rw-r--r-- | extensions/crypto/00_crypto.js | 1013 | ||||
-rw-r--r-- | extensions/crypto/01_webidl.js | 188 | ||||
-rw-r--r-- | extensions/crypto/Cargo.toml | 28 | ||||
-rw-r--r-- | extensions/crypto/README.md | 5 | ||||
-rw-r--r-- | extensions/crypto/key.rs | 117 | ||||
-rw-r--r-- | extensions/crypto/lib.deno_crypto.d.ts | 155 | ||||
-rw-r--r-- | extensions/crypto/lib.rs | 558 |
7 files changed, 0 insertions, 2064 deletions
diff --git a/extensions/crypto/00_crypto.js b/extensions/crypto/00_crypto.js deleted file mode 100644 index 449946295..000000000 --- a/extensions/crypto/00_crypto.js +++ /dev/null @@ -1,1013 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -// @ts-check -/// <reference path="../../core/internal.d.ts" /> -/// <reference path="../../core/lib.deno_core.d.ts" /> -/// <reference path="../webidl/internal.d.ts" /> -/// <reference path="../web/lib.deno_web.d.ts" /> - -"use strict"; - -((window) => { - const core = window.Deno.core; - const webidl = window.__bootstrap.webidl; - const { DOMException } = window.__bootstrap.domException; - - const { - ArrayPrototypeFind, - ArrayBufferIsView, - ArrayPrototypeIncludes, - BigInt64Array, - StringPrototypeToUpperCase, - Symbol, - SymbolFor, - SymbolToStringTag, - WeakMap, - WeakMapPrototypeGet, - WeakMapPrototypeSet, - Int8Array, - Uint8Array, - TypedArrayPrototypeSlice, - Int16Array, - Uint16Array, - Int32Array, - Uint32Array, - Uint8ClampedArray, - TypeError, - } = window.__bootstrap.primordials; - - // P-521 is not yet supported. - const supportedNamedCurves = ["P-256", "P-384"]; - const recognisedUsages = [ - "encrypt", - "decrypt", - "sign", - "verify", - "deriveKey", - "deriveBits", - "wrapKey", - "unwrapKey", - ]; - - const simpleAlgorithmDictionaries = { - RsaHashedKeyGenParams: { hash: "HashAlgorithmIdentifier" }, - EcKeyGenParams: {}, - HmacKeyGenParams: { hash: "HashAlgorithmIdentifier" }, - RsaPssParams: {}, - EcdsaParams: { hash: "HashAlgorithmIdentifier" }, - HmacImportParams: { hash: "HashAlgorithmIdentifier" }, - }; - - const supportedAlgorithms = { - "digest": { - "SHA-1": null, - "SHA-256": null, - "SHA-384": null, - "SHA-512": null, - }, - "generateKey": { - "RSASSA-PKCS1-v1_5": "RsaHashedKeyGenParams", - "RSA-PSS": "RsaHashedKeyGenParams", - "ECDSA": "EcKeyGenParams", - "HMAC": "HmacKeyGenParams", - }, - "sign": { - "RSASSA-PKCS1-v1_5": null, - "RSA-PSS": "RsaPssParams", - "ECDSA": "EcdsaParams", - "HMAC": null, - }, - "verify": { - "RSASSA-PKCS1-v1_5": null, - "RSA-PSS": "RsaPssParams", - "HMAC": null, - }, - "importKey": { - "HMAC": "HmacImportParams", - }, - }; - - // See https://www.w3.org/TR/WebCryptoAPI/#dfn-normalize-an-algorithm - function normalizeAlgorithm(algorithm, op) { - if (typeof algorithm == "string") { - return normalizeAlgorithm({ name: algorithm }, op); - } - - // 1. - const registeredAlgorithms = supportedAlgorithms[op]; - // 2. 3. - const initialAlg = webidl.converters.Algorithm(algorithm, { - prefix: "Failed to normalize algorithm", - context: "passed algorithm", - }); - // 4. - let algName = initialAlg.name; - - // 5. - let desiredType = undefined; - for (const key in registeredAlgorithms) { - if ( - StringPrototypeToUpperCase(key) === StringPrototypeToUpperCase(algName) - ) { - algName = key; - desiredType = registeredAlgorithms[key]; - } - } - if (desiredType === undefined) { - throw new DOMException( - "Unrecognized algorithm name", - "NotSupportedError", - ); - } - - // Fast path everything below if the registered dictionary is "None". - if (desiredType === null) { - return { name: algName }; - } - - const normalizedAlgorithm = webidl.converters[desiredType](algorithm, { - prefix: "Failed to normalize algorithm", - context: "passed algorithm", - }); - normalizedAlgorithm.name = algName; - - const dict = simpleAlgorithmDictionaries[desiredType]; - for (const member in dict) { - const idlType = dict[member]; - const idlValue = normalizedAlgorithm[member]; - - if (idlType === "BufferSource") { - normalizedAlgorithm[member] = new Uint8Array( - TypedArrayPrototypeSlice( - (ArrayBufferIsView(idlValue) ? idlValue.buffer : idlValue), - idlValue.byteOffset ?? 0, - idlValue.byteLength, - ), - ); - } else if (idlType === "HashAlgorithmIdentifier") { - normalizedAlgorithm[member] = normalizeAlgorithm(idlValue, "digest"); - } else if (idlType === "AlgorithmIdentifier") { - // TODO(lucacasonato): implement - throw new TypeError("unimplemented"); - } - } - - return normalizedAlgorithm; - } - - const _handle = Symbol("[[handle]]"); - const _algorithm = Symbol("[[algorithm]]"); - const _extractable = Symbol("[[extractable]]"); - const _usages = Symbol("[[usages]]"); - const _type = Symbol("[[type]]"); - - class CryptoKey { - /** @type {string} */ - [_type]; - /** @type {boolean} */ - [_extractable]; - /** @type {object} */ - [_algorithm]; - /** @type {string[]} */ - [_usages]; - /** @type {object} */ - [_handle]; - - constructor() { - webidl.illegalConstructor(); - } - - /** @returns {string} */ - get type() { - webidl.assertBranded(this, CryptoKey); - return this[_type]; - } - - /** @returns {boolean} */ - get extractable() { - webidl.assertBranded(this, CryptoKey); - return this[_extractable]; - } - - /** @returns {string[]} */ - get usages() { - webidl.assertBranded(this, CryptoKey); - // TODO(lucacasonato): return a SameObject copy - return this[_usages]; - } - - /** @returns {object} */ - get algorithm() { - webidl.assertBranded(this, CryptoKey); - // TODO(lucacasonato): return a SameObject copy - return this[_algorithm]; - } - - get [SymbolToStringTag]() { - return "CryptoKey"; - } - - [SymbolFor("Deno.customInspect")](inspect) { - return `${this.constructor.name} ${ - inspect({ - type: this.type, - extractable: this.extractable, - algorithm: this.algorithm, - usages: this.usages, - }) - }`; - } - } - - webidl.configurePrototype(CryptoKey); - - /** - * @param {string} type - * @param {boolean} extractable - * @param {string[]} usages - * @param {object} algorithm - * @param {object} handle - * @returns - */ - function constructKey(type, extractable, usages, algorithm, handle) { - const key = webidl.createBranded(CryptoKey); - key[_type] = type; - key[_extractable] = extractable; - key[_usages] = usages; - key[_algorithm] = algorithm; - key[_handle] = handle; - return key; - } - - // https://w3c.github.io/webcrypto/#concept-usage-intersection - /** - * @param {string[]} a - * @param {string[]} b - * @returns - */ - function usageIntersection(a, b) { - return a.filter((i) => b.includes(i)); - } - - // TODO(lucacasonato): this should be moved to rust - /** @type {WeakMap<object, object>} */ - const KEY_STORE = new WeakMap(); - - class SubtleCrypto { - constructor() { - webidl.illegalConstructor(); - } - - /** - * @param {string} algorithm - * @param {BufferSource} data - * @returns {Promise<Uint8Array>} - */ - async digest(algorithm, data) { - webidl.assertBranded(this, SubtleCrypto); - const prefix = "Failed to execute 'digest' on 'SubtleCrypto'"; - webidl.requiredArguments(arguments.length, 2, { prefix }); - algorithm = webidl.converters.AlgorithmIdentifier(algorithm, { - prefix, - context: "Argument 1", - }); - data = webidl.converters.BufferSource(data, { - prefix, - context: "Argument 2", - }); - - if (ArrayBufferIsView(data)) { - data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); - } else { - data = new Uint8Array(data); - } - - data = TypedArrayPrototypeSlice(data); - - algorithm = normalizeAlgorithm(algorithm, "digest"); - - const result = await core.opAsync( - "op_crypto_subtle_digest", - algorithm.name, - data, - ); - - return result.buffer; - } - - /** - * @param {string} algorithm - * @param {CryptoKey} key - * @param {BufferSource} data - * @returns {Promise<any>} - */ - async sign(algorithm, key, data) { - webidl.assertBranded(this, SubtleCrypto); - const prefix = "Failed to execute 'sign' on 'SubtleCrypto'"; - webidl.requiredArguments(arguments.length, 3, { prefix }); - algorithm = webidl.converters.AlgorithmIdentifier(algorithm, { - prefix, - context: "Argument 1", - }); - key = webidl.converters.CryptoKey(key, { - prefix, - context: "Argument 2", - }); - data = webidl.converters.BufferSource(data, { - prefix, - context: "Argument 3", - }); - - // 1. - if (ArrayBufferIsView(data)) { - data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); - } else { - data = new Uint8Array(data); - } - data = TypedArrayPrototypeSlice(data); - - // 2. - const normalizedAlgorithm = normalizeAlgorithm(algorithm, "sign"); - - const handle = key[_handle]; - const keyData = WeakMapPrototypeGet(KEY_STORE, handle); - - // 8. - if (normalizedAlgorithm.name !== key[_algorithm].name) { - throw new DOMException( - "Signing algorithm doesn't match key algorithm.", - "InvalidAccessError", - ); - } - - // 9. - if (!ArrayPrototypeIncludes(key[_usages], "sign")) { - throw new DOMException( - "Key does not support the 'sign' operation.", - "InvalidAccessError", - ); - } - - switch (normalizedAlgorithm.name) { - case "RSASSA-PKCS1-v1_5": { - // 1. - if (key[_type] !== "private") { - throw new DOMException( - "Key type not supported", - "InvalidAccessError", - ); - } - - // 2. - const hashAlgorithm = key[_algorithm].hash.name; - const signature = await core.opAsync("op_crypto_sign_key", { - key: keyData, - algorithm: "RSASSA-PKCS1-v1_5", - hash: hashAlgorithm, - }, data); - - return signature.buffer; - } - case "RSA-PSS": { - // 1. - if (key[_type] !== "private") { - throw new DOMException( - "Key type not supported", - "InvalidAccessError", - ); - } - - // 2. - const hashAlgorithm = key[_algorithm].hash.name; - const signature = await core.opAsync("op_crypto_sign_key", { - key: keyData, - algorithm: "RSA-PSS", - hash: hashAlgorithm, - saltLength: normalizedAlgorithm.saltLength, - }, data); - - return signature.buffer; - } - case "ECDSA": { - // 1. - if (key[_type] !== "private") { - throw new DOMException( - "Key type not supported", - "InvalidAccessError", - ); - } - - // 2. - const hashAlgorithm = normalizedAlgorithm.hash.name; - const namedCurve = key[_algorithm].namedCurve; - if (!ArrayPrototypeIncludes(supportedNamedCurves, namedCurve)) { - throw new DOMException("Curve not supported", "NotSupportedError"); - } - - const signature = await core.opAsync("op_crypto_sign_key", { - key: keyData, - algorithm: "ECDSA", - hash: hashAlgorithm, - namedCurve, - }, data); - - return signature.buffer; - } - case "HMAC": { - const hashAlgorithm = key[_algorithm].hash.name; - - const signature = await core.opAsync("op_crypto_sign_key", { - key: keyData, - algorithm: "HMAC", - hash: hashAlgorithm, - }, data); - - return signature.buffer; - } - } - - throw new TypeError("unreachable"); - } - - /** - * @param {string} format - * @param {BufferSource} keyData - * @param {string} algorithm - * @param {boolean} extractable - * @param {KeyUsages[]} keyUsages - * @returns {Promise<any>} - */ - // deno-lint-ignore require-await - async importKey(format, keyData, algorithm, extractable, keyUsages) { - webidl.assertBranded(this, SubtleCrypto); - const prefix = "Failed to execute 'importKey' on 'SubtleCrypto'"; - webidl.requiredArguments(arguments.length, 4, { prefix }); - format = webidl.converters.KeyFormat(format, { - prefix, - context: "Argument 1", - }); - keyData = webidl.converters.BufferSource(keyData, { - prefix, - context: "Argument 2", - }); - algorithm = webidl.converters.AlgorithmIdentifier(algorithm, { - prefix, - context: "Argument 3", - }); - extractable = webidl.converters.boolean(extractable, { - prefix, - context: "Argument 4", - }); - keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, { - prefix, - context: "Argument 5", - }); - - const normalizedAlgorithm = normalizeAlgorithm(algorithm, "importKey"); - - if ( - ArrayPrototypeFind( - keyUsages, - (u) => !ArrayPrototypeIncludes(["sign", "verify"], u), - ) !== undefined - ) { - throw new DOMException("Invalid key usages", "SyntaxError"); - } - - switch (normalizedAlgorithm.name) { - // https://w3c.github.io/webcrypto/#hmac-operations - case "HMAC": { - switch (format) { - case "raw": { - const hash = normalizedAlgorithm.hash; - // 5. - let length = keyData.byteLength * 8; - // 6. - if (length === 0) { - throw new DOMException("Key length is zero", "DataError"); - } - if (normalizeAlgorithm.length) { - // 7. - if ( - normalizedAlgorithm.length > length || - normalizedAlgorithm.length <= (length - 8) - ) { - throw new DOMException( - "Key length is invalid", - "DataError", - ); - } - length = normalizeAlgorithm.length; - } - - if (keyUsages.length == 0) { - throw new DOMException("Key usage is empty", "SyntaxError"); - } - - const handle = {}; - WeakMapPrototypeSet(KEY_STORE, handle, { - type: "raw", - data: keyData, - }); - - const algorithm = { - name: "HMAC", - length, - hash, - }; - - const key = constructKey( - "secret", - true, - usageIntersection(keyUsages, recognisedUsages), - algorithm, - handle, - ); - - return key; - } - // TODO(@littledivy): jwk - default: - throw new DOMException("Not implemented", "NotSupportedError"); - } - } - // TODO(@littledivy): RSASSA-PKCS1-v1_5 - // TODO(@littledivy): RSA-PSS - // TODO(@littledivy): ECDSA - default: - throw new DOMException("Not implemented", "NotSupportedError"); - } - } - - /** - * @param {string} format - * @param {CryptoKey} key - * @returns {Promise<any>} - */ - // deno-lint-ignore require-await - async exportKey(format, key) { - webidl.assertBranded(this, SubtleCrypto); - const prefix = "Failed to execute 'exportKey' on 'SubtleCrypto'"; - webidl.requiredArguments(arguments.length, 2, { prefix }); - format = webidl.converters.KeyFormat(format, { - prefix, - context: "Argument 1", - }); - key = webidl.converters.CryptoKey(key, { - prefix, - context: "Argument 2", - }); - - const handle = key[_handle]; - // 2. - const bits = WeakMapPrototypeGet(KEY_STORE, handle); - - switch (key[_algorithm].name) { - case "HMAC": { - if (bits == null) { - throw new DOMException("Key is not available", "OperationError"); - } - switch (format) { - // 3. - case "raw": { - for (let _i = 7 & (8 - bits.length % 8); _i > 0; _i--) { - bits.push(0); - } - // 4-5. - return bits.buffer; - } - // TODO(@littledivy): jwk - default: - throw new DOMException("Not implemented", "NotSupportedError"); - } - } - // TODO(@littledivy): RSASSA-PKCS1-v1_5 - // TODO(@littledivy): RSA-PSS - // TODO(@littledivy): ECDSA - default: - throw new DOMException("Not implemented", "NotSupportedError"); - } - } - - /** - * @param {string} algorithm - * @param {CryptoKey} key - * @param {BufferSource} signature - * @param {BufferSource} data - * @returns {Promise<boolean>} - */ - async verify(algorithm, key, signature, data) { - webidl.assertBranded(this, SubtleCrypto); - const prefix = "Failed to execute 'verify' on 'SubtleCrypto'"; - webidl.requiredArguments(arguments.length, 4, { prefix }); - algorithm = webidl.converters.AlgorithmIdentifier(algorithm, { - prefix, - context: "Argument 1", - }); - key = webidl.converters.CryptoKey(key, { - prefix, - context: "Argument 2", - }); - signature = webidl.converters.BufferSource(signature, { - prefix, - context: "Argument 3", - }); - data = webidl.converters.BufferSource(data, { - prefix, - context: "Argument 4", - }); - - // 2. - if (ArrayBufferIsView(signature)) { - signature = new Uint8Array( - signature.buffer, - signature.byteOffset, - signature.byteLength, - ); - } else { - signature = new Uint8Array(signature); - } - signature = TypedArrayPrototypeSlice(signature); - - // 3. - if (ArrayBufferIsView(data)) { - data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); - } else { - data = new Uint8Array(data); - } - data = TypedArrayPrototypeSlice(data); - - const normalizedAlgorithm = normalizeAlgorithm(algorithm, "verify"); - - const handle = key[_handle]; - const keyData = WeakMapPrototypeGet(KEY_STORE, handle); - - if (normalizedAlgorithm.name !== key[_algorithm].name) { - throw new DOMException( - "Verifying algorithm doesn't match key algorithm.", - "InvalidAccessError", - ); - } - - if (!ArrayPrototypeIncludes(key[_usages], "verify")) { - throw new DOMException( - "Key does not support the 'verify' operation.", - "InvalidAccessError", - ); - } - - switch (normalizedAlgorithm.name) { - case "RSASSA-PKCS1-v1_5": { - if (key[_type] !== "public") { - throw new DOMException( - "Key type not supported", - "InvalidAccessError", - ); - } - - const hashAlgorithm = key[_algorithm].hash.name; - return await core.opAsync("op_crypto_verify_key", { - key: keyData, - algorithm: "RSASSA-PKCS1-v1_5", - hash: hashAlgorithm, - signature, - }, data); - } - case "RSA-PSS": { - if (key[_type] !== "public") { - throw new DOMException( - "Key type not supported", - "InvalidAccessError", - ); - } - - const hashAlgorithm = key[_algorithm].hash.name; - const saltLength = normalizedAlgorithm.saltLength; - return await core.opAsync("op_crypto_verify_key", { - key: keyData, - algorithm: "RSA-PSS", - hash: hashAlgorithm, - saltLength, - signature, - }, data); - } - case "HMAC": { - const hash = key[_algorithm].hash.name; - return await core.opAsync("op_crypto_verify_key", { - key: keyData, - algorithm: "HMAC", - hash, - signature, - }, data); - } - } - - throw new TypeError("unreachable"); - } - - /** - * @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'"; - webidl.requiredArguments(arguments.length, 3, { prefix }); - algorithm = webidl.converters.AlgorithmIdentifier(algorithm, { - prefix, - context: "Argument 1", - }); - extractable = webidl.converters["boolean"](extractable, { - prefix, - context: "Argument 2", - }); - keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, { - prefix, - context: "Argument 3", - }); - - const usages = keyUsages; - - const normalizedAlgorithm = normalizeAlgorithm(algorithm, "generateKey"); - - // https://github.com/denoland/deno/pull/9614#issuecomment-866049433 - if (!extractable) { - throw new DOMException( - "Non-extractable keys are not supported", - "SecurityError", - ); - } - - const result = await generateKey( - normalizedAlgorithm, - extractable, - usages, - ); - - if (result instanceof CryptoKey) { - const type = result[_type]; - if ((type === "secret" || type === "private") && usages.length === 0) { - throw new DOMException("Invalid key usages", "SyntaxError"); - } - } else if (result.privateKey instanceof CryptoKey) { - if (result.privateKey[_usages].length === 0) { - throw new DOMException("Invalid key usages", "SyntaxError"); - } - } - - return result; - } - - get [SymbolToStringTag]() { - return "SubtleCrypto"; - } - } - - async function generateKey(normalizedAlgorithm, extractable, usages) { - switch (normalizedAlgorithm.name) { - case "RSASSA-PKCS1-v1_5": - case "RSA-PSS": { - // 1. - if ( - ArrayPrototypeFind( - usages, - (u) => !ArrayPrototypeIncludes(["sign", "verify"], u), - ) !== undefined - ) { - throw new DOMException("Invalid key usages", "SyntaxError"); - } - - // 2. - const keyData = await core.opAsync( - "op_crypto_generate_key", - { - name: normalizedAlgorithm.name, - modulusLength: normalizedAlgorithm.modulusLength, - publicExponent: normalizedAlgorithm.publicExponent, - }, - ); - const handle = {}; - WeakMapPrototypeSet(KEY_STORE, handle, { - type: "pkcs8", - data: keyData, - }); - - // 4-8. - const algorithm = { - name: normalizedAlgorithm.name, - modulusLength: normalizedAlgorithm.modulusLength, - publicExponent: normalizedAlgorithm.publicExponent, - hash: normalizedAlgorithm.hash, - }; - - // 9-13. - const publicKey = constructKey( - "public", - true, - usageIntersection(usages, ["verify"]), - algorithm, - handle, - ); - - // 14-18. - const privateKey = constructKey( - "private", - extractable, - usageIntersection(usages, ["sign"]), - algorithm, - handle, - ); - - // 19-22. - return { publicKey, privateKey }; - } - // TODO(lucacasonato): RSA-OAEP - case "ECDSA": { - // 1. - if ( - ArrayPrototypeFind( - usages, - (u) => !ArrayPrototypeIncludes(["sign", "verify"], u), - ) !== undefined - ) { - throw new DOMException("Invalid key usages", "SyntaxError"); - } - - // 2-3. - const handle = {}; - if ( - ArrayPrototypeIncludes( - supportedNamedCurves, - normalizedAlgorithm.namedCurve, - ) - ) { - const keyData = await core.opAsync("op_crypto_generate_key", { - name: "ECDSA", - namedCurve: normalizedAlgorithm.namedCurve, - }); - WeakMapPrototypeSet(KEY_STORE, handle, { - type: "pkcs8", - data: keyData, - }); - } else { - throw new DOMException("Curve not supported", "NotSupportedError"); - } - - // 4-6. - const algorithm = { - name: "ECDSA", - namedCurve: normalizedAlgorithm.namedCurve, - }; - - // 7-11. - const publicKey = constructKey( - "public", - true, - usageIntersection(usages, ["verify"]), - algorithm, - handle, - ); - - // 12-16. - const privateKey = constructKey( - "private", - extractable, - usageIntersection(usages, ["sign"]), - algorithm, - handle, - ); - - // 17-20. - return { publicKey, privateKey }; - } - // TODO(lucacasonato): ECDH - // TODO(lucacasonato): AES-CTR - // TODO(lucacasonato): AES-CBC - // TODO(lucacasonato): AES-GCM - // TODO(lucacasonato): AES-KW - case "HMAC": { - // 1. - if ( - ArrayPrototypeFind( - usages, - (u) => !ArrayPrototypeIncludes(["sign", "verify"], u), - ) !== undefined - ) { - throw new DOMException("Invalid key usages", "SyntaxError"); - } - - // 2. - let length; - if (normalizedAlgorithm.length === undefined) { - length = null; - } else if (normalizedAlgorithm.length !== 0) { - length = normalizedAlgorithm.length; - } else { - throw new DOMException("Invalid length", "OperationError"); - } - - // 3-4. - const keyData = await core.opAsync("op_crypto_generate_key", { - name: "HMAC", - hash: normalizedAlgorithm.hash.name, - length, - }); - const handle = {}; - WeakMapPrototypeSet(KEY_STORE, handle, { type: "raw", data: keyData }); - - // 6-10. - const algorithm = { - name: "HMAC", - hash: { - name: normalizedAlgorithm.hash.name, - }, - length: keyData.byteLength * 8, - }; - - // 5, 11-13. - const key = constructKey( - "secret", - extractable, - usages, - algorithm, - handle, - ); - - // 14. - return key; - } - } - } - - const subtle = webidl.createBranded(SubtleCrypto); - - class Crypto { - constructor() { - webidl.illegalConstructor(); - } - - getRandomValues(arrayBufferView) { - webidl.assertBranded(this, Crypto); - const prefix = "Failed to execute 'getRandomValues' on 'Crypto'"; - webidl.requiredArguments(arguments.length, 1, { prefix }); - arrayBufferView = webidl.converters.ArrayBufferView(arrayBufferView, { - prefix, - context: "Argument 1", - }); - if ( - !( - arrayBufferView instanceof Int8Array || - arrayBufferView instanceof Uint8Array || - arrayBufferView instanceof Uint8ClampedArray || - arrayBufferView instanceof Int16Array || - arrayBufferView instanceof Uint16Array || - arrayBufferView instanceof Int32Array || - arrayBufferView instanceof Uint32Array || - arrayBufferView instanceof BigInt64Array || - arrayBufferView instanceof BigUint64Array - ) - ) { - throw new DOMException( - "The provided ArrayBufferView is not an integer array type", - "TypeMismatchError", - ); - } - const ui8 = new Uint8Array( - arrayBufferView.buffer, - arrayBufferView.byteOffset, - arrayBufferView.byteLength, - ); - core.opSync("op_crypto_get_random_values", ui8); - return arrayBufferView; - } - - randomUUID() { - webidl.assertBranded(this, Crypto); - return core.opSync("op_crypto_random_uuid"); - } - - get subtle() { - webidl.assertBranded(this, Crypto); - return subtle; - } - - get [SymbolToStringTag]() { - return "Crypto"; - } - - [SymbolFor("Deno.customInspect")](inspect) { - return `${this.constructor.name} ${inspect({})}`; - } - } - - webidl.configurePrototype(Crypto); - - window.__bootstrap.crypto = { - SubtleCrypto, - crypto: webidl.createBranded(Crypto), - Crypto, - CryptoKey, - }; -})(this); diff --git a/extensions/crypto/01_webidl.js b/extensions/crypto/01_webidl.js deleted file mode 100644 index 7e78170b4..000000000 --- a/extensions/crypto/01_webidl.js +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -// @ts-check -/// <reference path="../../core/lib.deno_core.d.ts" /> -/// <reference path="../webidl/internal.d.ts" /> - -"use strict"; - -((window) => { - const webidl = window.__bootstrap.webidl; - const { CryptoKey } = window.__bootstrap.crypto; - - webidl.converters.AlgorithmIdentifier = (V, opts) => { - // Union for (object or DOMString) - if (webidl.type(V) == "Object") { - return webidl.converters.object(V, opts); - } - return webidl.converters.DOMString(V, opts); - }; - - webidl.converters.KeyType = webidl.createEnumConverter("KeyType", [ - "public", - "private", - "secret", - ]); - - webidl.converters.KeyFormat = webidl.createEnumConverter("KeyFormat", [ - "raw", - "pkcs8", - "spki", - "jwk", - ]); - - webidl.converters.KeyUsage = webidl.createEnumConverter("KeyUsage", [ - "encrypt", - "decrypt", - "sign", - "verify", - "deriveKey", - "deriveBits", - "wrapKey", - "unwrapKey", - ]); - - webidl.converters["sequence<KeyUsage>"] = webidl.createSequenceConverter( - webidl.converters.KeyUsage, - ); - - webidl.converters.HashAlgorithmIdentifier = - webidl.converters.AlgorithmIdentifier; - - /** @type {__bootstrap.webidl.Dictionary} */ - const dictAlgorithm = [{ - key: "name", - converter: webidl.converters.DOMString, - required: true, - }]; - - webidl.converters.Algorithm = webidl - .createDictionaryConverter("Algorithm", dictAlgorithm); - - webidl.converters.BigInteger = webidl.converters.Uint8Array; - - /** @type {__bootstrap.webidl.Dictionary} */ - const dictRsaKeyGenParams = [ - ...dictAlgorithm, - { - key: "modulusLength", - converter: (V, opts) => - webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }), - required: true, - }, - { - key: "publicExponent", - converter: webidl.converters.BigInteger, - required: true, - }, - ]; - - webidl.converters.RsaKeyGenParams = webidl - .createDictionaryConverter("RsaKeyGenParams", dictRsaKeyGenParams); - - const dictRsaHashedKeyGenParams = [ - ...dictRsaKeyGenParams, - { - key: "hash", - converter: webidl.converters.HashAlgorithmIdentifier, - required: true, - }, - ]; - - webidl.converters.RsaHashedKeyGenParams = webidl.createDictionaryConverter( - "RsaHashedKeyGenParams", - dictRsaHashedKeyGenParams, - ); - - webidl.converters.NamedCurve = webidl.converters.DOMString; - - const dictEcKeyGenParams = [ - ...dictAlgorithm, - { - key: "namedCurve", - converter: webidl.converters.NamedCurve, - required: true, - }, - ]; - - webidl.converters.EcKeyGenParams = webidl - .createDictionaryConverter("EcKeyGenParams", dictEcKeyGenParams); - - const dictHmacKeyGenParams = [ - ...dictAlgorithm, - { - key: "hash", - converter: webidl.converters.HashAlgorithmIdentifier, - required: true, - }, - { - key: "length", - converter: (V, opts) => - webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }), - }, - ]; - - webidl.converters.HmacKeyGenParams = webidl - .createDictionaryConverter("HmacKeyGenParams", dictHmacKeyGenParams); - - const dictRsaPssParams = [ - ...dictAlgorithm, - { - key: "saltLength", - converter: (V, opts) => - webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }), - required: true, - }, - ]; - - webidl.converters.RsaPssParams = webidl - .createDictionaryConverter("RsaPssParams", dictRsaPssParams); - - const dictEcdsaParams = [ - ...dictAlgorithm, - { - key: "hash", - converter: webidl.converters.HashAlgorithmIdentifier, - required: true, - }, - ]; - - webidl.converters["EcdsaParams"] = webidl - .createDictionaryConverter("EcdsaParams", dictEcdsaParams); - - const dictHmacImportParams = [ - ...dictAlgorithm, - { - key: "hash", - converter: webidl.converters.HashAlgorithmIdentifier, - required: true, - }, - { - key: "length", - converter: (V, opts) => - webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }), - }, - ]; - - webidl.converters.HmacImportParams = webidl - .createDictionaryConverter("HmacImportParams", dictHmacImportParams); - - webidl.converters.CryptoKey = webidl.createInterfaceConverter( - "CryptoKey", - CryptoKey, - ); - - const dictCryptoKeyPair = [ - { - key: "publicKey", - converter: webidl.converters.CryptoKey, - }, - { - key: "privateKey", - converter: webidl.converters.CryptoKey, - }, - ]; - - webidl.converters.CryptoKeyPair = webidl - .createDictionaryConverter("CryptoKeyPair", dictCryptoKeyPair); -})(this); diff --git a/extensions/crypto/Cargo.toml b/extensions/crypto/Cargo.toml deleted file mode 100644 index 8eb939e86..000000000 --- a/extensions/crypto/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -[package] -name = "deno_crypto" -version = "0.28.0" -authors = ["the Deno authors"] -edition = "2018" -license = "MIT" -readme = "README.md" -repository = "https://github.com/denoland/deno" -description = "Web Cryptography API implementation for Deno" - -[lib] -path = "lib.rs" - -[dependencies] -deno_core = { version = "0.96.0", path = "../../core" } -deno_web = { version = "0.45.0", path = "../web" } -lazy_static = "1.4.0" -num-traits = "0.2.14" -rand = "0.8.4" -ring = { version = "0.16.20", features = ["std"] } -rsa = { version = "0.5.0", default-features = false, features = ["std"] } -serde = { version = "1.0.126", features = ["derive"] } -sha-1 = "0.9.7" -sha2 = "0.9.5" -tokio = { version = "1.8.1", features = ["full"] } -uuid = { version = "0.8.2", features = ["v4"] } diff --git a/extensions/crypto/README.md b/extensions/crypto/README.md deleted file mode 100644 index be0724458..000000000 --- a/extensions/crypto/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# deno_crypto - -This crate implements the Web Cryptography API. - -Spec: https://www.w3.org/TR/WebCryptoAPI/ diff --git a/extensions/crypto/key.rs b/extensions/crypto/key.rs deleted file mode 100644 index cb44812fd..000000000 --- a/extensions/crypto/key.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -use ring::agreement::Algorithm as RingAlgorithm; -use ring::digest; -use ring::hmac::Algorithm as HmacAlgorithm; -use ring::signature::EcdsaSigningAlgorithm; -use serde::Deserialize; -use serde::Serialize; - -#[derive(Serialize, Deserialize, Copy, Clone)] -#[serde(rename_all = "camelCase")] -pub enum KeyType { - Public, - Private, - Secret, -} - -#[derive(Serialize, Deserialize, Copy, Clone)] -pub enum CryptoHash { - #[serde(rename = "SHA-1")] - Sha1, - #[serde(rename = "SHA-256")] - Sha256, - #[serde(rename = "SHA-384")] - Sha384, - #[serde(rename = "SHA-512")] - Sha512, -} - -#[derive(Serialize, Deserialize, Copy, Clone)] -pub enum CryptoNamedCurve { - #[serde(rename = "P-256")] - P256, - #[serde(rename = "P-384")] - P384, -} - -impl From<CryptoNamedCurve> for &RingAlgorithm { - fn from(curve: CryptoNamedCurve) -> &'static RingAlgorithm { - match curve { - CryptoNamedCurve::P256 => &ring::agreement::ECDH_P256, - CryptoNamedCurve::P384 => &ring::agreement::ECDH_P384, - } - } -} - -impl From<CryptoNamedCurve> for &EcdsaSigningAlgorithm { - fn from(curve: CryptoNamedCurve) -> &'static EcdsaSigningAlgorithm { - match curve { - CryptoNamedCurve::P256 => { - &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING - } - CryptoNamedCurve::P384 => { - &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING - } - } - } -} - -impl From<CryptoHash> for HmacAlgorithm { - fn from(hash: CryptoHash) -> HmacAlgorithm { - match hash { - CryptoHash::Sha1 => ring::hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, - CryptoHash::Sha256 => ring::hmac::HMAC_SHA256, - CryptoHash::Sha384 => ring::hmac::HMAC_SHA384, - CryptoHash::Sha512 => ring::hmac::HMAC_SHA512, - } - } -} - -impl From<CryptoHash> for &'static digest::Algorithm { - fn from(hash: CryptoHash) -> &'static digest::Algorithm { - match hash { - CryptoHash::Sha1 => &digest::SHA1_FOR_LEGACY_USE_ONLY, - CryptoHash::Sha256 => &digest::SHA256, - CryptoHash::Sha384 => &digest::SHA384, - CryptoHash::Sha512 => &digest::SHA512, - } - } -} - -#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)] -#[serde(rename_all = "camelCase")] -pub enum KeyUsage { - Encrypt, - Decrypt, - Sign, - Verify, - DeriveKey, - DeriveBits, - WrapKey, - UnwrapKey, -} - -#[derive(Serialize, Deserialize, Clone, Copy)] -pub enum Algorithm { - #[serde(rename = "RSASSA-PKCS1-v1_5")] - RsassaPkcs1v15, - #[serde(rename = "RSA-PSS")] - RsaPss, - #[serde(rename = "RSA-OAEP")] - RsaOaep, - #[serde(rename = "ECDSA")] - Ecdsa, - #[serde(rename = "ECDH")] - Ecdh, - #[serde(rename = "AES-CTR")] - AesCtr, - #[serde(rename = "AES-CBC")] - AesCbc, - #[serde(rename = "AES-GCM")] - AesGcm, - #[serde(rename = "AES-KW")] - AesKw, - #[serde(rename = "HMAC")] - Hmac, -} diff --git a/extensions/crypto/lib.deno_crypto.d.ts b/extensions/crypto/lib.deno_crypto.d.ts deleted file mode 100644 index b89b62f2e..000000000 --- a/extensions/crypto/lib.deno_crypto.d.ts +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -/// <reference no-default-lib="true" /> -/// <reference lib="esnext" /> - -declare var crypto: Crypto; - -interface Algorithm { - name: string; -} - -interface KeyAlgorithm { - name: string; -} - -type AlgorithmIdentifier = string | Algorithm; -type HashAlgorithmIdentifier = AlgorithmIdentifier; -type KeyType = "private" | "public" | "secret"; -type KeyUsage = - | "decrypt" - | "deriveBits" - | "deriveKey" - | "encrypt" - | "sign" - | "unwrapKey" - | "verify" - | "wrapKey"; - -type NamedCurve = string; - -interface HmacKeyGenParams extends Algorithm { - hash: HashAlgorithmIdentifier; - length?: number; -} - -interface EcKeyGenParams extends Algorithm { - namedCurve: NamedCurve; -} - -interface EcdsaParams extends Algorithm { - hash: HashAlgorithmIdentifier; -} - -interface RsaHashedKeyGenParams extends RsaKeyGenParams { - hash: HashAlgorithmIdentifier; -} - -interface RsaKeyGenParams extends Algorithm { - modulusLength: number; - publicExponent: Uint8Array; -} - -interface RsaPssParams extends Algorithm { - saltLength: number; -} - -interface HmacImportParams extends Algorithm { - hash: HashAlgorithmIdentifier; - length?: number; -} - -/** The CryptoKey dictionary of the Web Crypto API represents a cryptographic key. */ -interface CryptoKey { - readonly algorithm: KeyAlgorithm; - readonly extractable: boolean; - readonly type: KeyType; - readonly usages: KeyUsage[]; -} - -declare var CryptoKey: { - prototype: CryptoKey; - new (): CryptoKey; -}; - -/** The CryptoKeyPair dictionary of the Web Crypto API represents a key pair for an asymmetric cryptography algorithm, also known as a public-key algorithm. */ -interface CryptoKeyPair { - privateKey: CryptoKey; - publicKey: CryptoKey; -} - -declare var CryptoKeyPair: { - prototype: CryptoKeyPair; - new (): CryptoKeyPair; -}; - -/** This Web Crypto API interface provides a number of low-level cryptographic functions. It is accessed via the Crypto.subtle properties available in a window context (via Window.crypto). */ -interface SubtleCrypto { - generateKey( - algorithm: RsaHashedKeyGenParams | EcKeyGenParams, - extractable: boolean, - keyUsages: KeyUsage[], - ): Promise<CryptoKeyPair>; - generateKey( - algorithm: HmacKeyGenParams, - extractable: boolean, - keyUsages: KeyUsage[], - ): Promise<CryptoKey>; - generateKey( - algorithm: AlgorithmIdentifier, - extractable: boolean, - keyUsages: KeyUsage[], - ): Promise<CryptoKeyPair | CryptoKey>; - importKey( - format: "raw", - keyData: BufferSource, - algorithm: AlgorithmIdentifier | HmacImportParams, - extractable: boolean, - keyUsages: KeyUsage[], - ): Promise<CryptoKey>; - sign( - algorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams, - key: CryptoKey, - data: BufferSource, - ): Promise<ArrayBuffer>; - verify( - algorithm: AlgorithmIdentifier | RsaPssParams, - key: CryptoKey, - signature: BufferSource, - data: BufferSource, - ): Promise<boolean>; - digest( - algorithm: AlgorithmIdentifier, - data: BufferSource, - ): Promise<ArrayBuffer>; -} - -declare interface Crypto { - readonly subtle: SubtleCrypto; - getRandomValues< - T extends - | Int8Array - | Int16Array - | Int32Array - | Uint8Array - | Uint16Array - | Uint32Array - | Uint8ClampedArray - | Float32Array - | Float64Array - | DataView - | null, - >( - array: T, - ): T; - randomUUID(): string; -} - -interface Algorithm { - name: string; -} - -declare var SubtleCrypto: { - prototype: SubtleCrypto; - new (): SubtleCrypto; -}; diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs deleted file mode 100644 index 5989b121a..000000000 --- a/extensions/crypto/lib.rs +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -use deno_core::error::custom_error; -use deno_core::error::not_supported; -use deno_core::error::null_opbuf; -use deno_core::error::type_error; -use deno_core::error::AnyError; -use deno_core::include_js_files; -use deno_core::op_async; -use deno_core::op_sync; -use deno_core::Extension; -use deno_core::OpState; -use deno_core::ZeroCopyBuf; -use serde::Deserialize; - -use std::cell::RefCell; -use std::convert::TryInto; -use std::rc::Rc; - -use lazy_static::lazy_static; -use num_traits::cast::FromPrimitive; -use rand::rngs::OsRng; -use rand::rngs::StdRng; -use rand::thread_rng; -use rand::Rng; -use rand::SeedableRng; -use ring::digest; -use ring::hmac::Algorithm as HmacAlgorithm; -use ring::hmac::Key as HmacKey; -use ring::rand as RingRand; -use ring::rand::SecureRandom; -use ring::signature::EcdsaKeyPair; -use ring::signature::EcdsaSigningAlgorithm; -use rsa::padding::PaddingScheme; -use rsa::pkcs8::FromPrivateKey; -use rsa::pkcs8::ToPrivateKey; -use rsa::BigUint; -use rsa::PublicKey; -use rsa::RsaPrivateKey; -use rsa::RsaPublicKey; -use sha1::Sha1; -use sha2::Digest; -use sha2::Sha256; -use sha2::Sha384; -use sha2::Sha512; -use std::path::PathBuf; - -pub use rand; // Re-export rand - -mod key; - -use crate::key::Algorithm; -use crate::key::CryptoHash; -use crate::key::CryptoNamedCurve; - -// Allowlist for RSA public exponents. -lazy_static! { - static ref PUB_EXPONENT_1: BigUint = BigUint::from_u64(3).unwrap(); - static ref PUB_EXPONENT_2: BigUint = BigUint::from_u64(65537).unwrap(); -} - -pub fn init(maybe_seed: Option<u64>) -> Extension { - Extension::builder() - .js(include_js_files!( - prefix "deno:extensions/crypto", - "00_crypto.js", - "01_webidl.js", - )) - .ops(vec![ - ( - "op_crypto_get_random_values", - op_sync(op_crypto_get_random_values), - ), - ("op_crypto_generate_key", op_async(op_crypto_generate_key)), - ("op_crypto_sign_key", op_async(op_crypto_sign_key)), - ("op_crypto_verify_key", op_async(op_crypto_verify_key)), - ("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)), - ("op_crypto_random_uuid", op_sync(op_crypto_random_uuid)), - ]) - .state(move |state| { - if let Some(seed) = maybe_seed { - state.put(StdRng::seed_from_u64(seed)); - } - Ok(()) - }) - .build() -} - -pub fn op_crypto_get_random_values( - state: &mut OpState, - mut zero_copy: ZeroCopyBuf, - _: (), -) -> Result<(), AnyError> { - if zero_copy.len() > 65536 { - return Err( - deno_web::DomExceptionQuotaExceededError::new(&format!("The ArrayBufferView's byte length ({}) exceeds the number of bytes of entropy available via this API (65536)", zero_copy.len())) - .into(), - ); - } - - let maybe_seeded_rng = state.try_borrow_mut::<StdRng>(); - if let Some(seeded_rng) = maybe_seeded_rng { - seeded_rng.fill(&mut *zero_copy); - } else { - let mut rng = thread_rng(); - rng.fill(&mut *zero_copy); - } - - Ok(()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct AlgorithmArg { - name: Algorithm, - modulus_length: Option<u32>, - public_exponent: Option<ZeroCopyBuf>, - named_curve: Option<CryptoNamedCurve>, - hash: Option<CryptoHash>, - length: Option<usize>, -} - -pub async fn op_crypto_generate_key( - _state: Rc<RefCell<OpState>>, - args: AlgorithmArg, - _: (), -) -> Result<ZeroCopyBuf, AnyError> { - let algorithm = args.name; - - let key = match algorithm { - Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss => { - let public_exponent = args.public_exponent.ok_or_else(not_supported)?; - let modulus_length = args.modulus_length.ok_or_else(not_supported)?; - - let exponent = BigUint::from_bytes_be(&public_exponent); - if exponent != *PUB_EXPONENT_1 && exponent != *PUB_EXPONENT_2 { - return Err(custom_error( - "DOMExceptionOperationError", - "Bad public exponent", - )); - } - - let mut rng = OsRng; - - let private_key: RsaPrivateKey = tokio::task::spawn_blocking( - move || -> Result<RsaPrivateKey, rsa::errors::Error> { - RsaPrivateKey::new_with_exp( - &mut rng, - modulus_length as usize, - &exponent, - ) - }, - ) - .await - .unwrap() - .map_err(|e| custom_error("DOMExceptionOperationError", e.to_string()))?; - - private_key.to_pkcs8_der()?.as_ref().to_vec() - } - Algorithm::Ecdsa => { - let curve: &EcdsaSigningAlgorithm = - args.named_curve.ok_or_else(not_supported)?.into(); - let rng = RingRand::SystemRandom::new(); - let private_key: Vec<u8> = tokio::task::spawn_blocking( - move || -> Result<Vec<u8>, ring::error::Unspecified> { - let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)?; - Ok(pkcs8.as_ref().to_vec()) - }, - ) - .await - .unwrap() - .map_err(|_| { - custom_error("DOMExceptionOperationError", "Key generation failed") - })?; - - private_key - } - Algorithm::Hmac => { - let hash: HmacAlgorithm = args.hash.ok_or_else(not_supported)?.into(); - - let length = if let Some(length) = args.length { - if (length % 8) != 0 { - return Err(custom_error( - "DOMExceptionOperationError", - "hmac block length must be byte aligned", - )); - } - let length = length / 8; - if length > ring::digest::MAX_BLOCK_LEN { - return Err(custom_error( - "DOMExceptionOperationError", - "hmac block length is too large", - )); - } - length - } else { - hash.digest_algorithm().block_len - }; - - let rng = RingRand::SystemRandom::new(); - let mut key_bytes = [0; ring::digest::MAX_BLOCK_LEN]; - let key_bytes = &mut key_bytes[..length]; - rng.fill(key_bytes).map_err(|_| { - custom_error("DOMExceptionOperationError", "Key generation failed") - })?; - - key_bytes.to_vec() - } - _ => return Err(not_supported()), - }; - - Ok(key.into()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "lowercase")] -pub enum KeyFormat { - Raw, - Pkcs8, -} - -#[derive(Deserialize)] -#[serde(rename_all = "lowercase")] -pub struct KeyData { - // TODO(littledivy): Kept here to be used to importKey() in future. - #[allow(dead_code)] - r#type: KeyFormat, - data: ZeroCopyBuf, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SignArg { - key: KeyData, - algorithm: Algorithm, - salt_length: Option<u32>, - hash: Option<CryptoHash>, - named_curve: Option<CryptoNamedCurve>, -} - -pub async fn op_crypto_sign_key( - _state: Rc<RefCell<OpState>>, - args: SignArg, - zero_copy: Option<ZeroCopyBuf>, -) -> Result<ZeroCopyBuf, AnyError> { - let zero_copy = zero_copy.ok_or_else(null_opbuf)?; - let data = &*zero_copy; - let algorithm = args.algorithm; - - let signature = match algorithm { - Algorithm::RsassaPkcs1v15 => { - let private_key = RsaPrivateKey::from_pkcs8_der(&*args.key.data)?; - let (padding, hashed) = match args - .hash - .ok_or_else(|| type_error("Missing argument hash".to_string()))? - { - CryptoHash::Sha1 => { - let mut hasher = Sha1::new(); - hasher.update(&data); - ( - PaddingScheme::PKCS1v15Sign { - hash: Some(rsa::hash::Hash::SHA1), - }, - hasher.finalize()[..].to_vec(), - ) - } - CryptoHash::Sha256 => { - let mut hasher = Sha256::new(); - hasher.update(&data); - ( - PaddingScheme::PKCS1v15Sign { - hash: Some(rsa::hash::Hash::SHA2_256), - }, - hasher.finalize()[..].to_vec(), - ) - } - CryptoHash::Sha384 => { - let mut hasher = Sha384::new(); - hasher.update(&data); - ( - PaddingScheme::PKCS1v15Sign { - hash: Some(rsa::hash::Hash::SHA2_384), - }, - hasher.finalize()[..].to_vec(), - ) - } - CryptoHash::Sha512 => { - let mut hasher = Sha512::new(); - hasher.update(&data); - ( - PaddingScheme::PKCS1v15Sign { - hash: Some(rsa::hash::Hash::SHA2_512), - }, - hasher.finalize()[..].to_vec(), - ) - } - }; - - private_key.sign(padding, &hashed)? - } - Algorithm::RsaPss => { - let private_key = RsaPrivateKey::from_pkcs8_der(&*args.key.data)?; - - let salt_len = args - .salt_length - .ok_or_else(|| type_error("Missing argument saltLength".to_string()))? - as usize; - - let rng = OsRng; - let (padding, digest_in) = match args - .hash - .ok_or_else(|| type_error("Missing argument hash".to_string()))? - { - CryptoHash::Sha1 => { - let mut hasher = Sha1::new(); - hasher.update(&data); - ( - PaddingScheme::new_pss_with_salt::<Sha1, _>(rng, salt_len), - hasher.finalize()[..].to_vec(), - ) - } - CryptoHash::Sha256 => { - let mut hasher = Sha256::new(); - hasher.update(&data); - ( - PaddingScheme::new_pss_with_salt::<Sha256, _>(rng, salt_len), - hasher.finalize()[..].to_vec(), - ) - } - CryptoHash::Sha384 => { - let mut hasher = Sha384::new(); - hasher.update(&data); - ( - PaddingScheme::new_pss_with_salt::<Sha384, _>(rng, salt_len), - hasher.finalize()[..].to_vec(), - ) - } - CryptoHash::Sha512 => { - let mut hasher = Sha512::new(); - hasher.update(&data); - ( - PaddingScheme::new_pss_with_salt::<Sha512, _>(rng, salt_len), - hasher.finalize()[..].to_vec(), - ) - } - }; - - // Sign data based on computed padding and return buffer - private_key.sign(padding, &digest_in)? - } - Algorithm::Ecdsa => { - let curve: &EcdsaSigningAlgorithm = - args.named_curve.ok_or_else(not_supported)?.try_into()?; - - let key_pair = EcdsaKeyPair::from_pkcs8(curve, &*args.key.data)?; - // We only support P256-SHA256 & P384-SHA384. These are recommended signature pairs. - // https://briansmith.org/rustdoc/ring/signature/index.html#statics - if let Some(hash) = args.hash { - match hash { - CryptoHash::Sha256 | CryptoHash::Sha384 => (), - _ => return Err(type_error("Unsupported algorithm")), - } - }; - - let rng = RingRand::SystemRandom::new(); - let signature = key_pair.sign(&rng, data)?; - - // Signature data as buffer. - signature.as_ref().to_vec() - } - Algorithm::Hmac => { - let hash: HmacAlgorithm = args.hash.ok_or_else(not_supported)?.into(); - - let key = HmacKey::new(hash, &*args.key.data); - - let signature = ring::hmac::sign(&key, data); - signature.as_ref().to_vec() - } - _ => return Err(type_error("Unsupported algorithm".to_string())), - }; - - Ok(signature.into()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct VerifyArg { - key: KeyData, - algorithm: Algorithm, - salt_length: Option<u32>, - hash: Option<CryptoHash>, - signature: ZeroCopyBuf, -} - -pub async fn op_crypto_verify_key( - _state: Rc<RefCell<OpState>>, - args: VerifyArg, - zero_copy: Option<ZeroCopyBuf>, -) -> Result<bool, AnyError> { - let zero_copy = zero_copy.ok_or_else(null_opbuf)?; - let data = &*zero_copy; - let algorithm = args.algorithm; - - let verification = match algorithm { - Algorithm::RsassaPkcs1v15 => { - let public_key: RsaPublicKey = - RsaPrivateKey::from_pkcs8_der(&*args.key.data)?.to_public_key(); - let (padding, hashed) = match args - .hash - .ok_or_else(|| type_error("Missing argument hash".to_string()))? - { - CryptoHash::Sha1 => { - let mut hasher = Sha1::new(); - hasher.update(&data); - ( - PaddingScheme::PKCS1v15Sign { - hash: Some(rsa::hash::Hash::SHA1), - }, - hasher.finalize()[..].to_vec(), - ) - } - CryptoHash::Sha256 => { - let mut hasher = Sha256::new(); - hasher.update(&data); - ( - PaddingScheme::PKCS1v15Sign { - hash: Some(rsa::hash::Hash::SHA2_256), - }, - hasher.finalize()[..].to_vec(), - ) - } - CryptoHash::Sha384 => { - let mut hasher = Sha384::new(); - hasher.update(&data); - ( - PaddingScheme::PKCS1v15Sign { - hash: Some(rsa::hash::Hash::SHA2_384), - }, - hasher.finalize()[..].to_vec(), - ) - } - CryptoHash::Sha512 => { - let mut hasher = Sha512::new(); - hasher.update(&data); - ( - PaddingScheme::PKCS1v15Sign { - hash: Some(rsa::hash::Hash::SHA2_512), - }, - hasher.finalize()[..].to_vec(), - ) - } - }; - - public_key - .verify(padding, &hashed, &*args.signature) - .is_ok() - } - Algorithm::RsaPss => { - let salt_len = args - .salt_length - .ok_or_else(|| type_error("Missing argument saltLength".to_string()))? - as usize; - let public_key: RsaPublicKey = - RsaPrivateKey::from_pkcs8_der(&*args.key.data)?.to_public_key(); - - let rng = OsRng; - let (padding, hashed) = match args - .hash - .ok_or_else(|| type_error("Missing argument hash".to_string()))? - { - CryptoHash::Sha1 => { - let mut hasher = Sha1::new(); - hasher.update(&data); - ( - PaddingScheme::new_pss_with_salt::<Sha1, _>(rng, salt_len), - hasher.finalize()[..].to_vec(), - ) - } - CryptoHash::Sha256 => { - let mut hasher = Sha256::new(); - hasher.update(&data); - ( - PaddingScheme::new_pss_with_salt::<Sha256, _>(rng, salt_len), - hasher.finalize()[..].to_vec(), - ) - } - CryptoHash::Sha384 => { - let mut hasher = Sha384::new(); - hasher.update(&data); - ( - PaddingScheme::new_pss_with_salt::<Sha384, _>(rng, salt_len), - hasher.finalize()[..].to_vec(), - ) - } - CryptoHash::Sha512 => { - let mut hasher = Sha512::new(); - hasher.update(&data); - ( - PaddingScheme::new_pss_with_salt::<Sha512, _>(rng, salt_len), - hasher.finalize()[..].to_vec(), - ) - } - }; - - public_key - .verify(padding, &hashed, &*args.signature) - .is_ok() - } - Algorithm::Hmac => { - let hash: HmacAlgorithm = args.hash.ok_or_else(not_supported)?.into(); - let key = HmacKey::new(hash, &*args.key.data); - ring::hmac::verify(&key, data, &*args.signature).is_ok() - } - _ => return Err(type_error("Unsupported algorithm".to_string())), - }; - - Ok(verification) -} - -pub fn op_crypto_random_uuid( - state: &mut OpState, - _: (), - _: (), -) -> Result<String, AnyError> { - let maybe_seeded_rng = state.try_borrow_mut::<StdRng>(); - let uuid = if let Some(seeded_rng) = maybe_seeded_rng { - let mut bytes = [0u8; 16]; - seeded_rng.fill(&mut bytes); - uuid::Builder::from_bytes(bytes) - .set_version(uuid::Version::Random) - .build() - } else { - uuid::Uuid::new_v4() - }; - - Ok(uuid.to_string()) -} - -pub async fn op_crypto_subtle_digest( - _state: Rc<RefCell<OpState>>, - algorithm: CryptoHash, - data: Option<ZeroCopyBuf>, -) -> Result<ZeroCopyBuf, AnyError> { - let input = data.ok_or_else(null_opbuf)?; - let output = tokio::task::spawn_blocking(move || { - digest::digest(algorithm.into(), &input) - .as_ref() - .to_vec() - .into() - }) - .await?; - - Ok(output) -} - -pub fn get_declaration() -> PathBuf { - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_crypto.d.ts") -} |