From 662aa0698605188d57fffbbc0a4b73e3c163f464 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 25 Feb 2021 10:10:28 +0000 Subject: [PATCH 001/130] ok so --- Cargo.lock | 56 +++++++++++++++++++++++++ op_crates/crypto/Cargo.toml | 3 +- op_crates/crypto/key.rs | 53 ++++++++++++++++++++++++ op_crates/crypto/lib.rs | 81 ++++++++++++++++++++++++++++++++++++- 4 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 op_crates/crypto/key.rs diff --git a/Cargo.lock b/Cargo.lock index 64c51af84418c2..eb2d49ac2f46b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -482,7 +482,9 @@ name = "deno_crypto" version = "0.13.0" dependencies = [ "deno_core", + "openssl", "rand 0.8.3", + "serde", ] [[package]] @@ -847,6 +849,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.0.0" @@ -1618,6 +1635,33 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "openssl" +version = "0.10.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" +dependencies = [ + "bitflags", + "cfg-if 1.0.0", + "foreign-types", + "lazy_static", + "libc", + "openssl-sys", +] + +[[package]] +name = "openssl-sys" +version = "0.9.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "os_pipe" version = "0.9.2" @@ -1783,6 +1827,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + [[package]] name = "pmutil" version = "0.5.3" @@ -3332,6 +3382,12 @@ dependencies = [ "getrandom 0.2.2", ] +[[package]] +name = "vcpkg" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" + [[package]] name = "vec_map" version = "0.8.2" diff --git a/op_crates/crypto/Cargo.toml b/op_crates/crypto/Cargo.toml index 641a1cf6615392..28f626b6b22f36 100644 --- a/op_crates/crypto/Cargo.toml +++ b/op_crates/crypto/Cargo.toml @@ -16,4 +16,5 @@ path = "lib.rs" [dependencies] deno_core = { version = "0.79.0", path = "../../core" } rand = "0.8.3" - +openssl = "0.10.32" +serde = { version = "1.0.123", features = ["derive"] } \ No newline at end of file diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs new file mode 100644 index 00000000000000..f8f6283e7b52eb --- /dev/null +++ b/op_crates/crypto/key.rs @@ -0,0 +1,53 @@ +pub enum KeyType { + Public, + Private, + Secret, +} + +pub enum KeyUsage { + Encrypt, + Decrypt, + Sign, + Verify, + DeriveKey, + DeriveBits, + WrapKey, + UnwrapKey, +} + +#[derive(Clone)] +pub enum Algorithm { + RsassaPkcs1v15, + RsaPss, + RsaOaep, + Ecdsa, + Ecdh, + AesCtr, + AesCbc, + AesGcm, + AesKw, + Hmac, +} + +pub struct WebCryptoKey { + pub key_type: KeyType, + pub extractable: bool, + pub algorithm: Algorithm, + pub usages: Vec, +} + +impl WebCryptoKeyPair { + pub fn new(public_key: WebCryptoKey, private_key: WebCryptoKey) -> Self { + Self { + public_key, + private_key, + } + } +} + +pub struct CryptoKeyPair { + pub public_key: A, + pub private_key: B, +} + +pub type WebCryptoKeyPair = CryptoKeyPair; diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 61290080d27a24..71b070cac37f7a 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -1,19 +1,42 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -#![deny(warnings)] +//#![deny(warnings)] use deno_core::error::AnyError; +use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; +use deno_core::BufVec; use deno_core::JsRuntime; use deno_core::OpState; +use deno_core::Resource; use deno_core::ZeroCopyBuf; +use serde::Deserialize; +use serde::Serialize; + +use std::borrow::Cow; +use std::cell::RefCell; +use std::rc::Rc; + +use openssl::bn::BigNum; +use openssl::pkey::Private; +use openssl::pkey::Public; +use openssl::rsa::Rsa; use rand::rngs::StdRng; use rand::thread_rng; use rand::Rng; pub use rand; // Re-export rand +mod key; + +use crate::key::Algorithm; +use crate::key::CryptoKeyPair; +use crate::key::KeyType; +use crate::key::KeyUsage; +use crate::key::WebCryptoKey; +use crate::key::WebCryptoKeyPair; + /// Execute this crates' JS source files. pub fn init(isolate: &mut JsRuntime) { let files = vec![( @@ -41,3 +64,59 @@ pub fn op_crypto_get_random_values( Ok(json!({})) } + +struct CryptoKeyPairResource { + crypto_key: WebCryptoKeyPair, + key: CryptoKeyPair, +} + +impl Resource for CryptoKeyPairResource, Rsa> { + fn name(&self) -> Cow { + "usbDeviceHandle".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct WebCryptoGenerateKeyArgs { + modulus_length: u32, + exponent: u32, +} + +pub async fn op_webcrypto_generate_key( + state: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + let args: WebCryptoGenerateKeyArgs = serde_json::from_value(args)?; + let exponent = BigNum::from_u32(args.exponent)?; + let bits = args.modulus_length; + + let private_key = Rsa::generate_with_e(bits, &exponent)?; + let algorithm = Algorithm::RsaPss; + let public_key: Rsa = Rsa::from_public_components( + private_key.n().to_owned()?, + private_key.e().to_owned()?, + )?; + let webcrypto_key_public = WebCryptoKey { + key_type: KeyType::Public, + algorithm: algorithm.clone(), + extractable: true, + usages: vec![], + }; + let webcrypto_key_private = WebCryptoKey { + key_type: KeyType::Private, + algorithm, + extractable: true, + usages: vec![], + }; + let crypto_key = + WebCryptoKeyPair::new(webcrypto_key_public, webcrypto_key_private); + let key = CryptoKeyPair { + public_key, + private_key, + }; + let resource = CryptoKeyPairResource { crypto_key, key }; + let rid = state.borrow_mut().resource_table.add(resource); + Ok(json!({ "rid": rid })) +} From a337d42dcf22431dbfe2a479e4cc21aadd77dca8 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 25 Feb 2021 10:52:35 +0000 Subject: [PATCH 002/130] interestingg...hmm --- generateKey.js | 1 + op_crates/crypto/01_crypto.js | 4 ++++ op_crates/crypto/key.rs | 8 +++++++- op_crates/crypto/lib.rs | 35 +++++++++++++++++++++++------------ runtime/ops/crypto.rs | 6 ++++++ 5 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 generateKey.js diff --git a/generateKey.js b/generateKey.js new file mode 100644 index 00000000000000..2851ee44e9f98f --- /dev/null +++ b/generateKey.js @@ -0,0 +1 @@ +console.log(Deno.core.jsonOpSync("op_webcrypto_generate_key", { modulusLength: 4096/2, exponent: 101 })) \ No newline at end of file diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index ce13dc74c11e4e..0458a588fb2a0c 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -41,6 +41,10 @@ return arrayBufferView; } + function generateKey(algorithm, extractable, keyUsages) { + core.jsonOpSync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages }) + } + window.crypto = { getRandomValues, }; diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index f8f6283e7b52eb..6834fbdf51601c 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -1,9 +1,14 @@ +use serde::Deserialize; +use serde::Serialize; + +#[derive(Serialize, Deserialize)] pub enum KeyType { Public, Private, Secret, } +#[derive(Serialize, Deserialize)] pub enum KeyUsage { Encrypt, Decrypt, @@ -15,7 +20,7 @@ pub enum KeyUsage { UnwrapKey, } -#[derive(Clone)] +#[derive(Serialize, Deserialize, Clone)] pub enum Algorithm { RsassaPkcs1v15, RsaPss, @@ -29,6 +34,7 @@ pub enum Algorithm { Hmac, } +#[derive(Serialize, Deserialize)] pub struct WebCryptoKey { pub key_type: KeyType, pub extractable: bool, diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 71b070cac37f7a..f425226242e041 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -78,20 +78,31 @@ impl Resource for CryptoKeyPairResource, Rsa> { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] -struct WebCryptoGenerateKeyArgs { +struct WebCryptoAlgorithmArg { + name: Algorithm, + public_modulus: u32, modulus_length: u32, - exponent: u32, + // hash: Option, + // named_curve: Option, } -pub async fn op_webcrypto_generate_key( - state: Rc>, +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct WebCryptoGenerateKeyArg { + algorithm: WebCryptoAlgorithmArg, + extractable: bool, + key_usages: Vec, +} + +pub fn op_webcrypto_generate_key( + state: &mut OpState, args: Value, - _zero_copy: BufVec, + _zero_copy: &mut [ZeroCopyBuf], ) -> Result { - let args: WebCryptoGenerateKeyArgs = serde_json::from_value(args)?; - let exponent = BigNum::from_u32(args.exponent)?; - let bits = args.modulus_length; - + let args: WebCryptoGenerateKeyArg = serde_json::from_value(args)?; + let exponent = BigNum::from_u32(args.algorithm.public_modulus)?; + let bits = args.algorithm.modulus_length; + let extractable = args.extractable; let private_key = Rsa::generate_with_e(bits, &exponent)?; let algorithm = Algorithm::RsaPss; let public_key: Rsa = Rsa::from_public_components( @@ -101,13 +112,13 @@ pub async fn op_webcrypto_generate_key( let webcrypto_key_public = WebCryptoKey { key_type: KeyType::Public, algorithm: algorithm.clone(), - extractable: true, + extractable, usages: vec![], }; let webcrypto_key_private = WebCryptoKey { key_type: KeyType::Private, algorithm, - extractable: true, + extractable, usages: vec![], }; let crypto_key = @@ -117,6 +128,6 @@ pub async fn op_webcrypto_generate_key( private_key, }; let resource = CryptoKeyPairResource { crypto_key, key }; - let rid = state.borrow_mut().resource_table.add(resource); + let rid = state.resource_table.add(resource); Ok(json!({ "rid": rid })) } diff --git a/runtime/ops/crypto.rs b/runtime/ops/crypto.rs index 43a9d11267251e..70f8a8ab377f1f 100644 --- a/runtime/ops/crypto.rs +++ b/runtime/ops/crypto.rs @@ -1,5 +1,6 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. use deno_crypto::op_crypto_get_random_values; +use deno_crypto::op_webcrypto_generate_key; use deno_crypto::rand::rngs::StdRng; use deno_crypto::rand::SeedableRng; @@ -15,4 +16,9 @@ pub fn init(rt: &mut deno_core::JsRuntime, maybe_seed: Option) { "op_crypto_get_random_values", op_crypto_get_random_values, ); + super::reg_json_sync( + rt, + "op_webcrypto_generate_key", + op_webcrypto_generate_key, + ); } From b5b8688927615e79f80ce663c3bc5e07da30d4e6 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 25 Feb 2021 13:35:50 +0000 Subject: [PATCH 003/130] x --- op_crates/crypto/lib.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index f425226242e041..d893511cd97deb 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -103,12 +103,22 @@ pub fn op_webcrypto_generate_key( let exponent = BigNum::from_u32(args.algorithm.public_modulus)?; let bits = args.algorithm.modulus_length; let extractable = args.extractable; - let private_key = Rsa::generate_with_e(bits, &exponent)?; - let algorithm = Algorithm::RsaPss; - let public_key: Rsa = Rsa::from_public_components( - private_key.n().to_owned()?, - private_key.e().to_owned()?, - )?; + let algorithm = args.algorithm.name; + + let (public_key, private_key) = match algorithm { + Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss | Algorithm::RsaOaep => { + let private_key = Rsa::generate_with_e(bits, &exponent)?; + ( + Rsa::from_public_components( + private_key.n().to_owned()?, + private_key.e().to_owned()?, + )?, + private_key, + ) + } + _ => return Ok(json!({})), + }; + let webcrypto_key_public = WebCryptoKey { key_type: KeyType::Public, algorithm: algorithm.clone(), From eb3bc2f6f17215d812aa5242fffec62bb3b30040 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 26 Feb 2021 05:05:58 +0000 Subject: [PATCH 004/130] rsa --- Cargo.lock | 213 +++++++++++++++++++++++++----------- op_crates/crypto/Cargo.toml | 4 +- op_crates/crypto/lib.rs | 21 ++-- 3 files changed, 162 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb2d49ac2f46b0..14720ce291b6dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -156,6 +156,12 @@ dependencies = [ "syn 1.0.60", ] +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + [[package]] name = "autocfg" version = "1.0.1" @@ -338,7 +344,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" dependencies = [ - "autocfg", + "autocfg 1.0.1", "cfg-if 1.0.0", "lazy_static", ] @@ -482,8 +488,8 @@ name = "deno_crypto" version = "0.13.0" dependencies = [ "deno_core", - "openssl", - "rand 0.8.3", + "rand 0.7.3", + "rsa", "serde", ] @@ -849,21 +855,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.0.0" @@ -1245,7 +1236,7 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" dependencies = [ - "autocfg", + "autocfg 1.0.1", "hashbrown", ] @@ -1354,6 +1345,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] [[package]] name = "lexical-core" @@ -1374,6 +1368,12 @@ version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" +[[package]] +name = "libm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" + [[package]] name = "linked-hash-map" version = "0.5.4" @@ -1489,7 +1489,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" dependencies = [ "adler", - "autocfg", + "autocfg 1.0.1", ] [[package]] @@ -1588,19 +1588,49 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" dependencies = [ - "autocfg", + "autocfg 1.0.1", "num-integer", "num-traits", "serde", ] +[[package]] +name = "num-bigint-dig" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d51546d704f52ef14b3c962b5776e53d5b862e5790e40a350d366c209bd7f7a" +dependencies = [ + "autocfg 0.1.7", + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.7.3", + "serde", + "smallvec", + "zeroize", +] + [[package]] name = "num-integer" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg", + "autocfg 1.0.1", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg 1.0.1", + "num-integer", "num-traits", ] @@ -1610,7 +1640,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg", + "autocfg 1.0.1", ] [[package]] @@ -1635,33 +1665,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "openssl" -version = "0.10.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" -dependencies = [ - "bitflags", - "cfg-if 1.0.0", - "foreign-types", - "lazy_static", - "libc", - "openssl-sys", -] - -[[package]] -name = "openssl-sys" -version = "0.9.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "os_pipe" version = "0.9.2" @@ -1706,6 +1709,17 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "pem" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" +dependencies = [ + "base64 0.13.0", + "once_cell", + "regex", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -1827,12 +1841,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkg-config" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" - [[package]] name = "pmutil" version = "0.5.3" @@ -2184,6 +2192,28 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "rsa" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3648b669b10afeab18972c105e284a7b953a669b0be3514c27f9b17acab2f9cd" +dependencies = [ + "byteorder", + "digest", + "lazy_static", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pem", + "rand 0.7.3", + "sha2", + "simple_asn1", + "subtle", + "thiserror", + "zeroize", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -2378,6 +2408,19 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "sha2" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" +dependencies = [ + "block-buffer", + "cfg-if 1.0.0", + "cpuid-bool", + "digest", + "opaque-debug", +] + [[package]] name = "shell-escape" version = "0.1.5" @@ -2393,6 +2436,17 @@ dependencies = [ "libc", ] +[[package]] +name = "simple_asn1" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" +dependencies = [ + "chrono", + "num-bigint", + "num-traits", +] + [[package]] name = "siphasher" version = "0.3.3" @@ -2506,6 +2560,12 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" +[[package]] +name = "subtle" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" + [[package]] name = "swc_atoms" version = "0.2.5" @@ -2870,6 +2930,18 @@ dependencies = [ "unicode-xid 0.2.1", ] +[[package]] +name = "synstructure" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.8", + "syn 1.0.60", + "unicode-xid 0.2.1", +] + [[package]] name = "sys-info" version = "0.8.0" @@ -3013,7 +3085,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8190d04c665ea9e6b6a0dc45523ade572c088d2e6566244c1122671dbf4ae3a" dependencies = [ - "autocfg", + "autocfg 1.0.1", "bytes", "libc", "memchr", @@ -3382,12 +3454,6 @@ dependencies = [ "getrandom 0.2.2", ] -[[package]] -name = "vcpkg" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" - [[package]] name = "vec_map" version = "0.8.2" @@ -3621,3 +3687,24 @@ name = "wyz" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" + +[[package]] +name = "zeroize" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a974bcdd357f0dca4d41677db03436324d45a4c9ed2d0b873a5a360ce41c36" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.8", + "syn 1.0.60", + "synstructure", +] diff --git a/op_crates/crypto/Cargo.toml b/op_crates/crypto/Cargo.toml index 28f626b6b22f36..05e373670b2dea 100644 --- a/op_crates/crypto/Cargo.toml +++ b/op_crates/crypto/Cargo.toml @@ -15,6 +15,6 @@ path = "lib.rs" [dependencies] deno_core = { version = "0.79.0", path = "../../core" } -rand = "0.8.3" -openssl = "0.10.32" +rand = "0.7.0" +rsa = "0.3.0" serde = { version = "1.0.123", features = ["derive"] } \ No newline at end of file diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index d893511cd97deb..283967792a42ce 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -18,13 +18,14 @@ use std::borrow::Cow; use std::cell::RefCell; use std::rc::Rc; -use openssl::bn::BigNum; -use openssl::pkey::Private; -use openssl::pkey::Public; -use openssl::rsa::Rsa; +use rsa::algorithms::generate_multi_prime_key; +use rsa::RSAPrivateKey; +use rsa::RSAPublicKey; + use rand::rngs::StdRng; use rand::thread_rng; use rand::Rng; +use rand::rngs::OsRng; pub use rand; // Re-export rand @@ -70,7 +71,7 @@ struct CryptoKeyPairResource { key: CryptoKeyPair, } -impl Resource for CryptoKeyPairResource, Rsa> { +impl Resource for CryptoKeyPairResource { fn name(&self) -> Cow { "usbDeviceHandle".into() } @@ -100,19 +101,17 @@ pub fn op_webcrypto_generate_key( _zero_copy: &mut [ZeroCopyBuf], ) -> Result { let args: WebCryptoGenerateKeyArg = serde_json::from_value(args)?; - let exponent = BigNum::from_u32(args.algorithm.public_modulus)?; + let exponent = args.algorithm.public_modulus; let bits = args.algorithm.modulus_length; let extractable = args.extractable; let algorithm = args.algorithm.name; let (public_key, private_key) = match algorithm { Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss | Algorithm::RsaOaep => { - let private_key = Rsa::generate_with_e(bits, &exponent)?; + let mut rng = OsRng; + let private_key = generate_multi_prime_key(&mut rng, exponent as usize, bits as usize)?; ( - Rsa::from_public_components( - private_key.n().to_owned()?, - private_key.e().to_owned()?, - )?, + private_key.to_public_key(), private_key, ) } From 38f6075943af41db6649e2627808d811e3876113 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 26 Feb 2021 05:57:28 +0000 Subject: [PATCH 005/130] hmac --- Cargo.lock | 1 + op_crates/crypto/Cargo.toml | 1 + op_crates/crypto/key.rs | 10 +++- op_crates/crypto/lib.rs | 97 +++++++++++++++++++++++++------------ 4 files changed, 76 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 14720ce291b6dc..42a7f4b58978ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -489,6 +489,7 @@ version = "0.13.0" dependencies = [ "deno_core", "rand 0.7.3", + "ring", "rsa", "serde", ] diff --git a/op_crates/crypto/Cargo.toml b/op_crates/crypto/Cargo.toml index 05e373670b2dea..4827b3fa4c122a 100644 --- a/op_crates/crypto/Cargo.toml +++ b/op_crates/crypto/Cargo.toml @@ -16,5 +16,6 @@ path = "lib.rs" [dependencies] deno_core = { version = "0.79.0", path = "../../core" } rand = "0.7.0" +ring = { version = "0.16.20", features = ["std"] } rsa = "0.3.0" serde = { version = "1.0.123", features = ["derive"] } \ No newline at end of file diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index 6834fbdf51601c..5e20cf324fe0be 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -8,6 +8,14 @@ pub enum KeyType { Secret, } +#[derive(Serialize, Deserialize)] +pub enum WebCryptoHash { + Sha1, + Sha256, + Sha384, + Sha512, +} + #[derive(Serialize, Deserialize)] pub enum KeyUsage { Encrypt, @@ -20,7 +28,7 @@ pub enum KeyUsage { UnwrapKey, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, Copy)] pub enum Algorithm { RsassaPkcs1v15, RsaPss, diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 283967792a42ce..e992317f2ed8af 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -18,14 +18,15 @@ use std::borrow::Cow; use std::cell::RefCell; use std::rc::Rc; -use rsa::algorithms::generate_multi_prime_key; -use rsa::RSAPrivateKey; -use rsa::RSAPublicKey; - +use rand::rngs::OsRng; use rand::rngs::StdRng; use rand::thread_rng; use rand::Rng; -use rand::rngs::OsRng; +use ring::hmac::Key as HmacKey; +use ring::rand as RingRand; +use rsa::algorithms::generate_multi_prime_key; +use rsa::RSAPrivateKey; +use rsa::RSAPublicKey; pub use rand; // Re-export rand @@ -35,6 +36,7 @@ use crate::key::Algorithm; use crate::key::CryptoKeyPair; use crate::key::KeyType; use crate::key::KeyUsage; +use crate::key::WebCryptoHash; use crate::key::WebCryptoKey; use crate::key::WebCryptoKeyPair; @@ -73,7 +75,18 @@ struct CryptoKeyPairResource { impl Resource for CryptoKeyPairResource { fn name(&self) -> Cow { - "usbDeviceHandle".into() + "cryptoKeyPair".into() + } +} + +struct CryptoKeyResource { + crypto_key: WebCryptoKey, + key: K, +} + +impl Resource for CryptoKeyResource { + fn name(&self) -> Cow { + "cryptoKey".into() } } @@ -83,7 +96,8 @@ struct WebCryptoAlgorithmArg { name: Algorithm, public_modulus: u32, modulus_length: u32, - // hash: Option, + hash: Option, + // length: Option // named_curve: Option, } @@ -106,37 +120,56 @@ pub fn op_webcrypto_generate_key( let extractable = args.extractable; let algorithm = args.algorithm.name; - let (public_key, private_key) = match algorithm { + let rid = match algorithm { Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss | Algorithm::RsaOaep => { let mut rng = OsRng; - let private_key = generate_multi_prime_key(&mut rng, exponent as usize, bits as usize)?; - ( - private_key.to_public_key(), + let private_key = + generate_multi_prime_key(&mut rng, exponent as usize, bits as usize)?; + let public_key = private_key.to_public_key(); + + let webcrypto_key_public = WebCryptoKey { + key_type: KeyType::Public, + algorithm: algorithm.clone(), + extractable, + usages: vec![], + }; + let webcrypto_key_private = WebCryptoKey { + key_type: KeyType::Private, + algorithm, + extractable, + usages: vec![], + }; + let crypto_key = + WebCryptoKeyPair::new(webcrypto_key_public, webcrypto_key_private); + let key = CryptoKeyPair { + public_key, private_key, - ) + }; + let resource = CryptoKeyPairResource { crypto_key, key }; + state.resource_table.add(resource) + } + Algorithm::Hmac => { + let hash = match args.algorithm.hash.unwrap() { + WebCryptoHash::Sha1 => ring::hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, + WebCryptoHash::Sha256 => ring::hmac::HMAC_SHA256, + WebCryptoHash::Sha384 => ring::hmac::HMAC_SHA384, + WebCryptoHash::Sha512 => ring::hmac::HMAC_SHA512, + }; + let rng = RingRand::SystemRandom::new(); + // TODO: change algorithm length when specified. + let key = HmacKey::generate(hash, &rng)?; + let crypto_key = WebCryptoKey { + key_type: KeyType::Public, + algorithm, + extractable, + usages: vec![], + }; + let resource = CryptoKeyResource { crypto_key, key }; + + state.resource_table.add(resource) } _ => return Ok(json!({})), }; - let webcrypto_key_public = WebCryptoKey { - key_type: KeyType::Public, - algorithm: algorithm.clone(), - extractable, - usages: vec![], - }; - let webcrypto_key_private = WebCryptoKey { - key_type: KeyType::Private, - algorithm, - extractable, - usages: vec![], - }; - let crypto_key = - WebCryptoKeyPair::new(webcrypto_key_public, webcrypto_key_private); - let key = CryptoKeyPair { - public_key, - private_key, - }; - let resource = CryptoKeyPairResource { crypto_key, key }; - let rid = state.resource_table.add(resource); Ok(json!({ "rid": rid })) } From f29745af5fe1b664b317120d2cb1e1d1e4339a09 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 26 Feb 2021 06:53:27 +0000 Subject: [PATCH 006/130] Ecdsa --- op_crates/crypto/key.rs | 7 ++++++ op_crates/crypto/lib.rs | 52 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index 5e20cf324fe0be..50d3077e99ad55 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -16,6 +16,13 @@ pub enum WebCryptoHash { Sha512, } +#[derive(Serialize, Deserialize)] +pub enum WebCryptoNamedCurve { + P256, + P384, + P521, +} + #[derive(Serialize, Deserialize)] pub enum KeyUsage { Encrypt, diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index e992317f2ed8af..21fcbe6976a30a 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -24,6 +24,8 @@ use rand::thread_rng; use rand::Rng; use ring::hmac::Key as HmacKey; use ring::rand as RingRand; +use ring::signature::EcdsaKeyPair; +use ring::signature::KeyPair; use rsa::algorithms::generate_multi_prime_key; use rsa::RSAPrivateKey; use rsa::RSAPublicKey; @@ -39,6 +41,7 @@ use crate::key::KeyUsage; use crate::key::WebCryptoHash; use crate::key::WebCryptoKey; use crate::key::WebCryptoKeyPair; +use crate::key::WebCryptoNamedCurve; /// Execute this crates' JS source files. pub fn init(isolate: &mut JsRuntime) { @@ -75,7 +78,13 @@ struct CryptoKeyPairResource { impl Resource for CryptoKeyPairResource { fn name(&self) -> Cow { - "cryptoKeyPair".into() + "RSACryptoKeyPair".into() + } +} + +impl Resource for CryptoKeyPairResource { + fn name(&self) -> Cow { + "ECDSACryptoKeyPair".into() } } @@ -98,7 +107,7 @@ struct WebCryptoAlgorithmArg { modulus_length: u32, hash: Option, // length: Option - // named_curve: Option, + named_curve: Option, } #[derive(Deserialize)] @@ -148,6 +157,43 @@ pub fn op_webcrypto_generate_key( let resource = CryptoKeyPairResource { crypto_key, key }; state.resource_table.add(resource) } + Algorithm::Ecdsa => { + let curve = match args.algorithm.named_curve.unwrap() { + WebCryptoNamedCurve::P256 => { + &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING + } + WebCryptoNamedCurve::P384 => { + &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING + } + WebCryptoNamedCurve::P521 => panic!(), // TODO: Not implemented but don't panic. + }; + + let rng = RingRand::SystemRandom::new(); + let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)?; + let private_key = EcdsaKeyPair::from_pkcs8(&curve, pkcs8.as_ref())?; + let public_key = private_key.public_key().clone(); + let webcrypto_key_public = WebCryptoKey { + key_type: KeyType::Public, + algorithm: algorithm.clone(), + extractable, + usages: vec![], + }; + let webcrypto_key_private = WebCryptoKey { + key_type: KeyType::Private, + algorithm, + extractable, + usages: vec![], + }; + let crypto_key = + WebCryptoKeyPair::new(webcrypto_key_public, webcrypto_key_private); + let key = CryptoKeyPair { + public_key, + private_key, + }; + let resource = CryptoKeyPairResource { crypto_key, key }; + + state.resource_table.add(resource) + } Algorithm::Hmac => { let hash = match args.algorithm.hash.unwrap() { WebCryptoHash::Sha1 => ring::hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, @@ -159,7 +205,7 @@ pub fn op_webcrypto_generate_key( // TODO: change algorithm length when specified. let key = HmacKey::generate(hash, &rng)?; let crypto_key = WebCryptoKey { - key_type: KeyType::Public, + key_type: KeyType::Secret, algorithm, extractable, usages: vec![], From ca6f1f53f530a9c04a9b995b38d95607d0df79a4 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 26 Feb 2021 07:14:40 +0000 Subject: [PATCH 007/130] ecdh --- op_crates/crypto/lib.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 21fcbe6976a30a..b7216d74c004fc 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -22,6 +22,7 @@ use rand::rngs::OsRng; use rand::rngs::StdRng; use rand::thread_rng; use rand::Rng; +use ring::agreement::EphemeralPrivateKey; use ring::hmac::Key as HmacKey; use ring::rand as RingRand; use ring::signature::EcdsaKeyPair; @@ -88,6 +89,14 @@ impl Resource for CryptoKeyPairResource { } } +impl Resource + for CryptoKeyPairResource +{ + fn name(&self) -> Cow { + "ECDHCryptoKeyPair".into() + } +} + struct CryptoKeyResource { crypto_key: WebCryptoKey, key: K, @@ -157,6 +166,37 @@ pub fn op_webcrypto_generate_key( let resource = CryptoKeyPairResource { crypto_key, key }; state.resource_table.add(resource) } + Algorithm::Ecdh => { + let agreement = match args.algorithm.named_curve.unwrap() { + WebCryptoNamedCurve::P256 => &ring::agreement::ECDH_P256, + WebCryptoNamedCurve::P384 => &ring::agreement::ECDH_P384, + WebCryptoNamedCurve::P521 => panic!(), // TODO: Not implemented but don't panic. + }; + let rng = RingRand::SystemRandom::new(); + let private_key = EphemeralPrivateKey::generate(agreement, &rng)?; + let public_key = private_key.compute_public_key()?; + let webcrypto_key_public = WebCryptoKey { + key_type: KeyType::Public, + algorithm: algorithm.clone(), + extractable, + usages: vec![], + }; + let webcrypto_key_private = WebCryptoKey { + key_type: KeyType::Private, + algorithm, + extractable, + usages: vec![], + }; + let crypto_key = + WebCryptoKeyPair::new(webcrypto_key_public, webcrypto_key_private); + let key = CryptoKeyPair { + public_key, + private_key, + }; + let resource = CryptoKeyPairResource { crypto_key, key }; + + state.resource_table.add(resource) + } Algorithm::Ecdsa => { let curve = match args.algorithm.named_curve.unwrap() { WebCryptoNamedCurve::P256 => { From 36f332a55a133d5901f2e0c355231b575d3cdf19 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 26 Feb 2021 07:20:45 +0000 Subject: [PATCH 008/130] CryptoKey class .. hmm --- op_crates/crypto/01_crypto.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 0458a588fb2a0c..60ec2c50279dbf 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -41,15 +41,29 @@ return arrayBufferView; } + // Just for storing the rid for a crypto key. + class CryptoKey { + #rid + + constructor(key) { + this.usages = key.usages; + this.extractable = key.extractable; + this.algorithm = key.algorithm; + this.keyType = key.keyType; + } + } + function generateKey(algorithm, extractable, keyUsages) { - core.jsonOpSync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages }) + return new CryptoKey(core.jsonOpSync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages })) } window.crypto = { getRandomValues, + generateKey, }; window.__bootstrap = window.__bootstrap || {}; window.__bootstrap.crypto = { getRandomValues, + generateKey, }; })(this); From 78c34e26125f74ec2b175e62efff7924e8bd320f Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 26 Feb 2021 07:36:48 +0000 Subject: [PATCH 009/130] rename algo fields --- generateKey.js | 4 +++- op_crates/crypto/key.rs | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/generateKey.js b/generateKey.js index 2851ee44e9f98f..ac057680e469f6 100644 --- a/generateKey.js +++ b/generateKey.js @@ -1 +1,3 @@ -console.log(Deno.core.jsonOpSync("op_webcrypto_generate_key", { modulusLength: 4096/2, exponent: 101 })) \ No newline at end of file +// console.log(Deno.core.jsonOpSync("op_webcrypto_generate_key", { modulusLength: 4096/2, exponent: 101 })) +// console.log(crypto.generateKey({ name: "RsaPss", modulusLength: 4096, publicModulus: 2 }, true, ["Sign"])) +console.log(crypto.generateKey({ name: "RsaPss", modulusLength: 4096, publicModulus: 2 }, true, ["Sign"])) \ No newline at end of file diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index 50d3077e99ad55..ee0070c2d8c22a 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -37,15 +37,25 @@ pub enum KeyUsage { #[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 = "RSA-PSS")] AesKw, + #[serde(rename = "HMAC")] Hmac, } From b075a6da43392ad5dd426cfda9418ec3420d21d9 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 26 Feb 2021 10:39:28 +0000 Subject: [PATCH 010/130] sign --- op_crates/crypto/key.rs | 10 ++++++ op_crates/crypto/lib.rs | 70 +++++++++++++++++++++++++++++++++++------ 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index ee0070c2d8c22a..74e27e8071b73e 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -2,6 +2,7 @@ use serde::Deserialize; use serde::Serialize; #[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub enum KeyType { Public, Private, @@ -10,20 +11,28 @@ pub enum KeyType { #[derive(Serialize, Deserialize)] pub enum WebCryptoHash { + #[serde(rename = "SHA-1")] Sha1, + #[serde(rename = "SHA-256")] Sha256, + #[serde(rename = "SHA-384")] Sha384, + #[serde(rename = "SHA-512")] Sha512, } #[derive(Serialize, Deserialize)] pub enum WebCryptoNamedCurve { + #[serde(rename = "P-256")] P256, + #[serde(rename = "P-384")] P384, + #[serde(rename = "P-512")] P521, } #[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub enum KeyUsage { Encrypt, Decrypt, @@ -60,6 +69,7 @@ pub enum Algorithm { } #[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct WebCryptoKey { pub key_type: KeyType, pub extractable: bool, diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index b7216d74c004fc..aca1e119ce9afc 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -2,6 +2,7 @@ //#![deny(warnings)] +use deno_core::error::bad_resource_id; use deno_core::error::AnyError; use deno_core::serde_json; use deno_core::serde_json::json; @@ -28,6 +29,7 @@ use ring::rand as RingRand; use ring::signature::EcdsaKeyPair; use ring::signature::KeyPair; use rsa::algorithms::generate_multi_prime_key; +use rsa::padding::PaddingScheme; use rsa::RSAPrivateKey; use rsa::RSAPublicKey; @@ -83,7 +85,7 @@ impl Resource for CryptoKeyPairResource { } } -impl Resource for CryptoKeyPairResource { +impl Resource for CryptoKeyResource { fn name(&self) -> Cow { "ECDSACryptoKeyPair".into() } @@ -211,26 +213,24 @@ pub fn op_webcrypto_generate_key( let rng = RingRand::SystemRandom::new(); let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)?; let private_key = EcdsaKeyPair::from_pkcs8(&curve, pkcs8.as_ref())?; - let public_key = private_key.public_key().clone(); + // let public_key = private_key.public_key().clone(); let webcrypto_key_public = WebCryptoKey { key_type: KeyType::Public, algorithm: algorithm.clone(), extractable, usages: vec![], }; - let webcrypto_key_private = WebCryptoKey { + let crypto_key = WebCryptoKey { key_type: KeyType::Private, algorithm, extractable, usages: vec![], }; - let crypto_key = - WebCryptoKeyPair::new(webcrypto_key_public, webcrypto_key_private); - let key = CryptoKeyPair { - public_key, - private_key, + + let resource = CryptoKeyResource { + crypto_key, + key: private_key, }; - let resource = CryptoKeyPairResource { crypto_key, key }; state.resource_table.add(resource) } @@ -259,3 +259,55 @@ pub fn op_webcrypto_generate_key( Ok(json!({ "rid": rid })) } + +#[derive(Deserialize)] +struct WebCryptoSignArg { + rid: u32, + algorithm: Algorithm, + key: WebCryptoKey, + data: Vec, +} + +pub fn op_webcrypto_sign_key( + state: &mut OpState, + args: Value, + _zero_copy: &mut [ZeroCopyBuf], +) -> Result { + let args: WebCryptoSignArg = serde_json::from_value(args)?; + let data = args.data; + let algorithm = args.algorithm; + + let signature = match algorithm { + Algorithm::RsassaPkcs1v15 => { + let resource = state + .resource_table + .get::>(args.rid) + .ok_or_else(bad_resource_id)?; + + let private_key = &resource.key.private_key; + // TODO(littledivy): Modify resource to store args from generateKey. + // let hash = resource.crypto_key.private_key.hash; + let padding = PaddingScheme::PKCS1v15Sign { hash: None }; + + // Sign data based on computed padding and return buffer + private_key.sign(padding, &data)? + } + Algorithm::Ecdsa => { + let resource = state + .resource_table + .get::>(args.rid) + .ok_or_else(bad_resource_id)?; + let key_pair = &resource.key; + + // Sign data using SecureRng and key. + let rng = RingRand::SystemRandom::new(); + let signature = key_pair.sign(&rng, &data)?; + + // Signature data as buffer. + signature.as_ref().to_vec() + } + _ => panic!(), // TODO: don't panic + }; + + Ok(json!({})) +} From 88369fe55e2b729e199d819a5ed715496b083ca7 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 26 Feb 2021 10:44:36 +0000 Subject: [PATCH 011/130] hmac signing --- op_crates/crypto/lib.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index aca1e119ce9afc..371750bf98ade2 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -306,8 +306,18 @@ pub fn op_webcrypto_sign_key( // Signature data as buffer. signature.as_ref().to_vec() } + Algorithm::Hmac => { + let resource = state + .resource_table + .get::>(args.rid) + .ok_or_else(bad_resource_id)?; + let key = &resource.key; + + let signature = ring::hmac::sign(&key, &data); + signature.as_ref().to_vec() + } _ => panic!(), // TODO: don't panic }; - Ok(json!({})) + Ok(json!({ "data": signature })) } From 581537597a01d3f5ac958d30ab1ed00368174837 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 26 Feb 2021 12:17:24 +0000 Subject: [PATCH 012/130] works --- generateKey.js | 23 ++++++++++++++++++++--- op_crates/crypto/01_crypto.js | 19 +++++++++++++++---- op_crates/crypto/lib.rs | 8 ++++---- runtime/ops/crypto.rs | 2 ++ 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/generateKey.js b/generateKey.js index ac057680e469f6..462be2096720a7 100644 --- a/generateKey.js +++ b/generateKey.js @@ -1,3 +1,20 @@ -// console.log(Deno.core.jsonOpSync("op_webcrypto_generate_key", { modulusLength: 4096/2, exponent: 101 })) -// console.log(crypto.generateKey({ name: "RsaPss", modulusLength: 4096, publicModulus: 2 }, true, ["Sign"])) -console.log(crypto.generateKey({ name: "RsaPss", modulusLength: 4096, publicModulus: 2 }, true, ["Sign"])) \ No newline at end of file +// generateKey + sign +let keyPair = await window.crypto.subtle.generateKey( + { + name: "RSASSA-PKCS1-v1_5", + modulusLength: 2048, + publicModulus: 101, // Oops, ik things are a bit + hash: "SHA-256" + }, + true, + ["encrypt", "decrypt"] +); + +let encoded = new TextEncoder().encode("Hello, World!"); +let signature = await window.crypto.subtle.sign( + "RSASSA-PKCS1-v1_5", + keyPair, + encoded +); + +console.log(signature); \ No newline at end of file diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 60ec2c50279dbf..307aed75855a03 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -42,14 +42,13 @@ } // Just for storing the rid for a crypto key. - class CryptoKey { - #rid - + class CryptoKey { constructor(key) { this.usages = key.usages; this.extractable = key.extractable; this.algorithm = key.algorithm; this.keyType = key.keyType; + this.rid = key.rid; } } @@ -57,13 +56,25 @@ return new CryptoKey(core.jsonOpSync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages })) } + function sign(algorithm, key, data) { + let rid = key.rid; + return core.jsonOpSync("op_webcrypto_sign_key", { rid, algorithm }, data).data; + } + window.crypto = { getRandomValues, - generateKey, + subtle: { + generateKey, + sign, + } }; window.__bootstrap = window.__bootstrap || {}; window.__bootstrap.crypto = { getRandomValues, generateKey, + subtle: { + generateKey, + sign, + } }; })(this); diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 371750bf98ade2..dfcbadb02681dd 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -264,17 +264,17 @@ pub fn op_webcrypto_generate_key( struct WebCryptoSignArg { rid: u32, algorithm: Algorithm, - key: WebCryptoKey, - data: Vec, } pub fn op_webcrypto_sign_key( state: &mut OpState, args: Value, - _zero_copy: &mut [ZeroCopyBuf], + zero_copy: &mut [ZeroCopyBuf], ) -> Result { + assert_eq!(zero_copy.len(), 1); + let args: WebCryptoSignArg = serde_json::from_value(args)?; - let data = args.data; + let data = &*zero_copy[0]; let algorithm = args.algorithm; let signature = match algorithm { diff --git a/runtime/ops/crypto.rs b/runtime/ops/crypto.rs index 70f8a8ab377f1f..3b4a0fa4f19262 100644 --- a/runtime/ops/crypto.rs +++ b/runtime/ops/crypto.rs @@ -1,6 +1,7 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. use deno_crypto::op_crypto_get_random_values; use deno_crypto::op_webcrypto_generate_key; +use deno_crypto::op_webcrypto_sign_key; use deno_crypto::rand::rngs::StdRng; use deno_crypto::rand::SeedableRng; @@ -21,4 +22,5 @@ pub fn init(rt: &mut deno_core::JsRuntime, maybe_seed: Option) { "op_webcrypto_generate_key", op_webcrypto_generate_key, ); + super::reg_json_sync(rt, "op_webcrypto_sign_key", op_webcrypto_sign_key); } From cf7557090658388233f8780f0ffc0b169848649c Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 27 Feb 2021 07:17:32 +0000 Subject: [PATCH 013/130] wip --- op_crates/crypto/key.rs | 69 +++++++++++++++++++++++++++++++++++++++++ op_crates/crypto/lib.rs | 52 +++++++++++++------------------ 2 files changed, 90 insertions(+), 31 deletions(-) diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index 74e27e8071b73e..734b8c75562fd8 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -1,3 +1,5 @@ +use ring::agreement::Algorithm as RingAlgorithm; +use ring::signature::EcdsaSigningAlgorithm; use serde::Deserialize; use serde::Serialize; @@ -31,6 +33,32 @@ pub enum WebCryptoNamedCurve { P521, } +impl Into for WebCryptoNamedCurve { + fn from(curve: RingAlgorithm) -> Self { + match curve { + WebCryptoNamedCurve::P256 => &ring::agreement::ECDH_P256, + WebCryptoNamedCurve::P384 => &ring::agreement::ECDH_P384, + // XXX: Not implemented. + WebCryptoNamedCurve::P521 => panic!(), + } + } +} + +impl From for WebCryptoNamedCurve { + fn from(algo: EcdsaSigningAlgorithm) -> Self { + match algo { + WebCryptoNamedCurve::P256 => { + &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING + } + WebCryptoNamedCurve::P384 => { + &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING + } + // TODO: Not implemented but don't panic. + WebCryptoNamedCurve::P521 => panic!(), + } + } +} + #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum KeyUsage { @@ -77,6 +105,47 @@ pub struct WebCryptoKey { pub usages: Vec, } +impl WebCryptoKey { + pub fn new_private( + extractable: bool, + algorithm: Algorithm, + usages: Vec, + ) -> Self { + Self { + key_type: KeyType::Private, + extractable, + algorithm, + usages, + } + } + + pub fn new_public( + extractable: bool, + algorithm: Algorithm, + usages: Vec, + ) -> Self { + Self { + key_type: KeyType::Public, + extractable, + algorithm, + usages, + } + } + + pub fn new_secret( + extractable: bool, + algorithm: Algorithm, + usages: Vec, + ) -> Self { + Self { + key_type: KeyType::Secret, + extractable, + algorithm, + usages, + } + } +} + impl WebCryptoKeyPair { pub fn new(public_key: WebCryptoKey, private_key: WebCryptoKey) -> Self { Self { diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index dfcbadb02681dd..a7906e6c1b034a 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -114,7 +114,7 @@ impl Resource for CryptoKeyResource { #[serde(rename_all = "camelCase")] struct WebCryptoAlgorithmArg { name: Algorithm, - public_modulus: u32, + public_exponent: u32, modulus_length: u32, hash: Option, // length: Option @@ -135,32 +135,28 @@ pub fn op_webcrypto_generate_key( _zero_copy: &mut [ZeroCopyBuf], ) -> Result { let args: WebCryptoGenerateKeyArg = serde_json::from_value(args)?; - let exponent = args.algorithm.public_modulus; + let exponent = args.algorithm.public_exponent; let bits = args.algorithm.modulus_length; let extractable = args.extractable; let algorithm = args.algorithm.name; let rid = match algorithm { Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss | Algorithm::RsaOaep => { + // Generate RSA private key based of exponent, bits and Rng. let mut rng = OsRng; let private_key = generate_multi_prime_key(&mut rng, exponent as usize, bits as usize)?; + // Extract public key from private key. let public_key = private_key.to_public_key(); - let webcrypto_key_public = WebCryptoKey { - key_type: KeyType::Public, - algorithm: algorithm.clone(), - extractable, - usages: vec![], - }; - let webcrypto_key_private = WebCryptoKey { - key_type: KeyType::Private, - algorithm, - extractable, - usages: vec![], - }; + // Create webcrypto keypair. + let webcrypto_key_public = + WebCryptoKey::new_public(algorithm.clone(), extractable, vec![]); + let webcrypto_key_private = + WebCryptoKey::new_private(algorithm, extractable, vec![]); let crypto_key = WebCryptoKeyPair::new(webcrypto_key_public, webcrypto_key_private); + let key = CryptoKeyPair { public_key, private_key, @@ -169,28 +165,22 @@ pub fn op_webcrypto_generate_key( state.resource_table.add(resource) } Algorithm::Ecdh => { - let agreement = match args.algorithm.named_curve.unwrap() { - WebCryptoNamedCurve::P256 => &ring::agreement::ECDH_P256, - WebCryptoNamedCurve::P384 => &ring::agreement::ECDH_P384, - WebCryptoNamedCurve::P521 => panic!(), // TODO: Not implemented but don't panic. - }; + // Determine agreement from algorithm named_curve. + let agreement = + WebCryptoNamedCurve::from(args.algorithm.named_curve.unwrap()); + // Generate private key from agreement and ring rng. let rng = RingRand::SystemRandom::new(); let private_key = EphemeralPrivateKey::generate(agreement, &rng)?; + // Extract public key. let public_key = private_key.compute_public_key()?; - let webcrypto_key_public = WebCryptoKey { - key_type: KeyType::Public, - algorithm: algorithm.clone(), - extractable, - usages: vec![], - }; - let webcrypto_key_private = WebCryptoKey { - key_type: KeyType::Private, - algorithm, - extractable, - usages: vec![], - }; + // Create webcrypto keypair. + let webcrypto_key_public = + WebCryptoKey::new_public(algorithm.clone(), extractable, vec![]); + let webcrypto_key_private = + WebCryptoKey::new_private(algorithm, extractable, vec![]); let crypto_key = WebCryptoKeyPair::new(webcrypto_key_public, webcrypto_key_private); + let key = CryptoKeyPair { public_key, private_key, From cd22635015114a8f95f267474d545e6bdcf4dfaf Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 28 Feb 2021 16:13:42 +0000 Subject: [PATCH 014/130] into trait --- op_crates/crypto/key.rs | 16 ++++++++-------- op_crates/crypto/lib.rs | 21 +++++++++------------ 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index 734b8c75562fd8..74d77fb8f4d153 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -33,9 +33,9 @@ pub enum WebCryptoNamedCurve { P521, } -impl Into for WebCryptoNamedCurve { - fn from(curve: RingAlgorithm) -> Self { - match curve { +impl Into<&RingAlgorithm> for WebCryptoNamedCurve { + fn into(self) -> &'static RingAlgorithm { + match self { WebCryptoNamedCurve::P256 => &ring::agreement::ECDH_P256, WebCryptoNamedCurve::P384 => &ring::agreement::ECDH_P384, // XXX: Not implemented. @@ -44,9 +44,9 @@ impl Into for WebCryptoNamedCurve { } } -impl From for WebCryptoNamedCurve { - fn from(algo: EcdsaSigningAlgorithm) -> Self { - match algo { +impl Into<&EcdsaSigningAlgorithm> for WebCryptoNamedCurve { + fn into(self) -> &'static EcdsaSigningAlgorithm { + match self { WebCryptoNamedCurve::P256 => { &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING } @@ -107,8 +107,8 @@ pub struct WebCryptoKey { impl WebCryptoKey { pub fn new_private( - extractable: bool, algorithm: Algorithm, + extractable: bool, usages: Vec, ) -> Self { Self { @@ -120,8 +120,8 @@ impl WebCryptoKey { } pub fn new_public( - extractable: bool, algorithm: Algorithm, + extractable: bool, usages: Vec, ) -> Self { Self { diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index ceec963d0b964c..1c560971493453 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -23,10 +23,12 @@ use rand::rngs::OsRng; use rand::rngs::StdRng; use rand::thread_rng; use rand::Rng; +use ring::agreement::Algorithm as RingAlgorithm; use ring::agreement::EphemeralPrivateKey; use ring::hmac::Key as HmacKey; use ring::rand as RingRand; use ring::signature::EcdsaKeyPair; +use ring::signature::EcdsaSigningAlgorithm; use ring::signature::KeyPair; use rsa::algorithms::generate_multi_prime_key; use rsa::padding::PaddingScheme; @@ -167,11 +169,11 @@ pub fn op_webcrypto_generate_key( } Algorithm::Ecdh => { // Determine agreement from algorithm named_curve. - let agreement = - WebCryptoNamedCurve::from(args.algorithm.named_curve.unwrap()); + let agreement: &RingAlgorithm = + args.algorithm.named_curve.unwrap().into(); // Generate private key from agreement and ring rng. let rng = RingRand::SystemRandom::new(); - let private_key = EphemeralPrivateKey::generate(agreement, &rng)?; + let private_key = EphemeralPrivateKey::generate(&agreement, &rng)?; // Extract public key. let public_key = private_key.compute_public_key()?; // Create webcrypto keypair. @@ -191,15 +193,8 @@ pub fn op_webcrypto_generate_key( state.resource_table.add(resource) } Algorithm::Ecdsa => { - let curve = match args.algorithm.named_curve.unwrap() { - WebCryptoNamedCurve::P256 => { - &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING - } - WebCryptoNamedCurve::P384 => { - &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING - } - WebCryptoNamedCurve::P521 => panic!(), // TODO: Not implemented but don't panic. - }; + let curve: &EcdsaSigningAlgorithm = + args.algorithm.named_curve.unwrap().into(); let rng = RingRand::SystemRandom::new(); let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)?; @@ -311,6 +306,8 @@ pub fn op_webcrypto_sign_key( }; Ok(json!({ "data": signature })) +} + pub fn get_declaration() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_crypto.d.ts") } From b125e5eff249d8957e1f80560909b275d208e733 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 28 Feb 2021 17:14:47 +0000 Subject: [PATCH 015/130] async --- op_crates/crypto/01_crypto.js | 8 ++++---- op_crates/crypto/lib.rs | 15 +++++++++------ runtime/ops/crypto.rs | 4 ++-- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 307aed75855a03..1967a9b74aa147 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -52,13 +52,13 @@ } } - function generateKey(algorithm, extractable, keyUsages) { - return new CryptoKey(core.jsonOpSync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages })) + async function generateKey(algorithm, extractable, keyUsages) { + return new CryptoKey(await core.jsonOpAsync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages })) } - function sign(algorithm, key, data) { + async function sign(algorithm, key, data) { let rid = key.rid; - return core.jsonOpSync("op_webcrypto_sign_key", { rid, algorithm }, data).data; + return await core.jsonOpAsync("op_webcrypto_sign_key", { rid, algorithm }, data).data; } window.crypto = { diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 1c560971493453..7b5bc017f76a9d 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -132,10 +132,10 @@ struct WebCryptoGenerateKeyArg { key_usages: Vec, } -pub fn op_webcrypto_generate_key( - state: &mut OpState, +pub async fn op_webcrypto_generate_key( + state: Rc>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], + _zero_copy: BufVec, ) -> Result { let args: WebCryptoGenerateKeyArg = serde_json::from_value(args)?; let exponent = args.algorithm.public_exponent; @@ -143,6 +143,8 @@ pub fn op_webcrypto_generate_key( let extractable = args.extractable; let algorithm = args.algorithm.name; + let mut state = state.borrow_mut(); + let rid = match algorithm { Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss | Algorithm::RsaOaep => { // Generate RSA private key based of exponent, bits and Rng. @@ -252,13 +254,14 @@ struct WebCryptoSignArg { algorithm: Algorithm, } -pub fn op_webcrypto_sign_key( - state: &mut OpState, +pub async fn op_webcrypto_sign_key( + state: Rc>, args: Value, - zero_copy: &mut [ZeroCopyBuf], + zero_copy: BufVec, ) -> Result { assert_eq!(zero_copy.len(), 1); + let state = state.borrow(); let args: WebCryptoSignArg = serde_json::from_value(args)?; let data = &*zero_copy[0]; let algorithm = args.algorithm; diff --git a/runtime/ops/crypto.rs b/runtime/ops/crypto.rs index 3b4a0fa4f19262..b3ed1cfa45a554 100644 --- a/runtime/ops/crypto.rs +++ b/runtime/ops/crypto.rs @@ -17,10 +17,10 @@ pub fn init(rt: &mut deno_core::JsRuntime, maybe_seed: Option) { "op_crypto_get_random_values", op_crypto_get_random_values, ); - super::reg_json_sync( + super::reg_json_async( rt, "op_webcrypto_generate_key", op_webcrypto_generate_key, ); - super::reg_json_sync(rt, "op_webcrypto_sign_key", op_webcrypto_sign_key); + super::reg_json_async(rt, "op_webcrypto_sign_key", op_webcrypto_sign_key); } From 951060e2ba3853fff6d741afe471ff01eaf77403 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 28 Feb 2021 17:36:17 +0000 Subject: [PATCH 016/130] JSKey --- op_crates/crypto/key.rs | 19 +++++++---- op_crates/crypto/lib.rs | 71 +++++++++++++++++++++++++---------------- 2 files changed, 55 insertions(+), 35 deletions(-) diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index 74d77fb8f4d153..b9a90159b9f9c2 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -3,7 +3,7 @@ use ring::signature::EcdsaSigningAlgorithm; use serde::Deserialize; use serde::Serialize; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Copy, Clone)] #[serde(rename_all = "camelCase")] pub enum KeyType { Public, @@ -11,7 +11,7 @@ pub enum KeyType { Secret, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Copy, Clone)] pub enum WebCryptoHash { #[serde(rename = "SHA-1")] Sha1, @@ -23,7 +23,7 @@ pub enum WebCryptoHash { Sha512, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Copy, Clone)] pub enum WebCryptoNamedCurve { #[serde(rename = "P-256")] P256, @@ -59,7 +59,7 @@ impl Into<&EcdsaSigningAlgorithm> for WebCryptoNamedCurve { } } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Copy, Clone)] #[serde(rename_all = "camelCase")] pub enum KeyUsage { Encrypt, @@ -96,7 +96,7 @@ pub enum Algorithm { Hmac, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct WebCryptoKey { pub key_type: KeyType, @@ -133,8 +133,8 @@ impl WebCryptoKey { } pub fn new_secret( - extractable: bool, algorithm: Algorithm, + extractable: bool, usages: Vec, ) -> Self { Self { @@ -160,4 +160,9 @@ pub struct CryptoKeyPair { pub private_key: B, } -pub type WebCryptoKeyPair = CryptoKeyPair; +#[derive(Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WebCryptoKeyPair { + pub public_key: WebCryptoKey, + pub private_key: WebCryptoKey, +} diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 7b5bc017f76a9d..2dc0a44911af51 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -132,6 +132,13 @@ struct WebCryptoGenerateKeyArg { key_usages: Vec, } +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +enum JSCryptoKey { + Single(WebCryptoKey), + Pair(WebCryptoKeyPair), +} + pub async fn op_webcrypto_generate_key( state: Rc>, args: Value, @@ -145,7 +152,7 @@ pub async fn op_webcrypto_generate_key( let mut state = state.borrow_mut(); - let rid = match algorithm { + let (rid, js_key) = match algorithm { Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss | Algorithm::RsaOaep => { // Generate RSA private key based of exponent, bits and Rng. let mut rng = OsRng; @@ -166,8 +173,14 @@ pub async fn op_webcrypto_generate_key( public_key, private_key, }; - let resource = CryptoKeyPairResource { crypto_key, key }; - state.resource_table.add(resource) + let resource = CryptoKeyPairResource { + crypto_key: crypto_key.clone(), + key, + }; + ( + state.resource_table.add(resource), + JSCryptoKey::Pair(crypto_key), + ) } Algorithm::Ecdh => { // Determine agreement from algorithm named_curve. @@ -190,9 +203,15 @@ pub async fn op_webcrypto_generate_key( public_key, private_key, }; - let resource = CryptoKeyPairResource { crypto_key, key }; + let resource = CryptoKeyPairResource { + crypto_key: crypto_key.clone(), + key, + }; - state.resource_table.add(resource) + ( + state.resource_table.add(resource), + JSCryptoKey::Pair(crypto_key), + ) } Algorithm::Ecdsa => { let curve: &EcdsaSigningAlgorithm = @@ -201,26 +220,21 @@ pub async fn op_webcrypto_generate_key( let rng = RingRand::SystemRandom::new(); let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)?; let private_key = EcdsaKeyPair::from_pkcs8(&curve, pkcs8.as_ref())?; - // let public_key = private_key.public_key().clone(); - let webcrypto_key_public = WebCryptoKey { - key_type: KeyType::Public, - algorithm: algorithm.clone(), - extractable, - usages: vec![], - }; - let crypto_key = WebCryptoKey { - key_type: KeyType::Private, - algorithm, - extractable, - usages: vec![], - }; + // Create webcrypto keypair. + let webcrypto_key_public = + WebCryptoKey::new_public(algorithm.clone(), extractable, vec![]); + let crypto_key = + WebCryptoKey::new_private(algorithm, extractable, vec![]); let resource = CryptoKeyResource { - crypto_key, + crypto_key: crypto_key.clone(), key: private_key, }; - state.resource_table.add(resource) + ( + state.resource_table.add(resource), + JSCryptoKey::Single(crypto_key), + ) } Algorithm::Hmac => { let hash = match args.algorithm.hash.unwrap() { @@ -232,20 +246,21 @@ pub async fn op_webcrypto_generate_key( let rng = RingRand::SystemRandom::new(); // TODO: change algorithm length when specified. let key = HmacKey::generate(hash, &rng)?; - let crypto_key = WebCryptoKey { - key_type: KeyType::Secret, - algorithm, - extractable, - usages: vec![], + let crypto_key = WebCryptoKey::new_secret(algorithm, extractable, vec![]); + let resource = CryptoKeyResource { + crypto_key: crypto_key.clone(), + key, }; - let resource = CryptoKeyResource { crypto_key, key }; - state.resource_table.add(resource) + ( + state.resource_table.add(resource), + JSCryptoKey::Single(crypto_key), + ) } _ => return Ok(json!({})), }; - Ok(json!({ "rid": rid })) + Ok(json!({ "rid": rid, "key": js_key })) } #[derive(Deserialize)] From b0335e96775cd6235fa494d712053b5e96e4eb2f Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 2 Mar 2021 04:05:55 +0000 Subject: [PATCH 017/130] Rsa::generate_with_exp --- Cargo.lock | 84 +++++++++++++++++------------------ generateKey.js | 18 +++----- op_crates/crypto/01_crypto.js | 57 +++++++++++++++++------- op_crates/crypto/Cargo.toml | 2 +- op_crates/crypto/lib.rs | 19 ++++---- 5 files changed, 97 insertions(+), 83 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45cdf38985a8ef..401438ee1af921 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -824,7 +824,7 @@ checksum = "7e8709b039f9ad8759e6a895d7f853501f1bb0f0bf2e20b1250270ef89ea8ebc" dependencies = [ "bumpalo", "fnv", - "num-bigint", + "num-bigint 0.2.6", "swc_atoms", "swc_common", "swc_ecmascript", @@ -1722,12 +1722,6 @@ version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" -[[package]] -name = "libm" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" - [[package]] name = "libloading" version = "0.6.7" @@ -1738,6 +1732,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "libm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" + [[package]] name = "linked-hash-map" version = "0.5.4" @@ -1998,6 +1998,17 @@ dependencies = [ "serde", ] +[[package]] +name = "num-bigint" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf" +dependencies = [ + "autocfg 1.0.1", + "num-integer", + "num-traits", +] + [[package]] name = "num-bigint-dig" version = "0.6.1" @@ -2012,7 +2023,6 @@ dependencies = [ "num-iter", "num-traits", "rand 0.7.3", - "serde", "smallvec", "zeroize", ] @@ -2045,6 +2055,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg 1.0.1", + "libm", ] [[package]] @@ -2630,11 +2641,21 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "ron" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064ea8613fb712a19faf920022ec8ddf134984f100090764a4e1d768f3827f1f" +dependencies = [ + "base64 0.13.0", + "bitflags", + "serde", +] + [[package]] name = "rsa" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3648b669b10afeab18972c105e284a7b953a669b0be3514c27f9b17acab2f9cd" +source = "git+https://github.com/RustCrypto/RSA?rev=616b08d#616b08d94bbb03c8fdb1a57188c38701faf6877b" dependencies = [ "byteorder", "digest", @@ -2645,24 +2666,11 @@ dependencies = [ "num-traits", "pem", "rand 0.7.3", - "sha2", "simple_asn1", "subtle", - "thiserror", "zeroize", ] -[[package]] -name = "ron" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "064ea8613fb712a19faf920022ec8ddf134984f100090764a4e1d768f3827f1f" -dependencies = [ - "base64 0.13.0", - "bitflags", - "serde", -] - [[package]] name = "rustc_version" version = "0.2.3" @@ -2857,19 +2865,6 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "sha2" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" -dependencies = [ - "block-buffer", - "cfg-if 1.0.0", - "cpuid-bool", - "digest", - "opaque-debug", -] - [[package]] name = "shell-escape" version = "0.1.5" @@ -2887,13 +2882,14 @@ dependencies = [ [[package]] name = "simple_asn1" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" +checksum = "db8d597fce66eb0f19dd129b9956e4054cba21aeaf97d4116595027b670fac50" dependencies = [ "chrono", - "num-bigint", + "num-bigint 0.3.1", "num-traits", + "thiserror", ] [[package]] @@ -3099,7 +3095,7 @@ dependencies = [ "from_variant", "fxhash", "log", - "num-bigint", + "num-bigint 0.2.6", "once_cell", "owning_ref", "scoped-tls", @@ -3118,7 +3114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efb6a027891bdb66ddddda7bdee43c39be6b7d7861f05fe93177f29183e26738" dependencies = [ "is-macro", - "num-bigint", + "num-bigint 0.2.6", "serde", "string_enum", "swc_atoms", @@ -3132,7 +3128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673a4d3fafd4ccc5c74b31f5896100a7c1c40a86c7e35d0245ce60ee11d49ac9" dependencies = [ "bitflags", - "num-bigint", + "num-bigint 0.2.6", "sourcemap", "swc_atoms", "swc_common", @@ -3176,7 +3172,7 @@ dependencies = [ "enum_kind", "fxhash", "log", - "num-bigint", + "num-bigint 0.2.6", "serde", "smallvec", "swc_atoms", @@ -3323,7 +3319,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "169dbafc108be69387475bab48d94e60a786a5959c76e0bd31f6bfb19e81f1b5" dependencies = [ - "num-bigint", + "num-bigint 0.2.6", "swc_atoms", "swc_common", "swc_ecma_ast", diff --git a/generateKey.js b/generateKey.js index 462be2096720a7..c643d376d5ca1a 100644 --- a/generateKey.js +++ b/generateKey.js @@ -1,20 +1,12 @@ -// generateKey + sign -let keyPair = await window.crypto.subtle.generateKey( +let key = await window.crypto.subtle.generateKey( { - name: "RSASSA-PKCS1-v1_5", - modulusLength: 2048, - publicModulus: 101, // Oops, ik things are a bit + name: "RSA-OAEP", + modulusLength: 4096, + publicExponent: 2, hash: "SHA-256" }, true, ["encrypt", "decrypt"] ); -let encoded = new TextEncoder().encode("Hello, World!"); -let signature = await window.crypto.subtle.sign( - "RSASSA-PKCS1-v1_5", - keyPair, - encoded -); - -console.log(signature); \ No newline at end of file +console.log(key); \ No newline at end of file diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 1967a9b74aa147..c989b9f6243fe4 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -41,14 +41,42 @@ return arrayBufferView; } - // Just for storing the rid for a crypto key. - class CryptoKey { + // Represents a rid in a CryptoKey instance. + const ridSymbol = Symbol(); + + // The CryptoKey class. A JavaScript representation of a WebCrypto key. + // Stores rid of the actual key along with read-only properties. + class CryptoKey { + #usages + #extractable + #algorithm + #keyType + constructor(key) { - this.usages = key.usages; - this.extractable = key.extractable; - this.algorithm = key.algorithm; - this.keyType = key.keyType; - this.rid = key.rid; + // The key is serailized from an Enum in the Rust-side. + // Therefore, we flatten it here. + let key = key.pair || key.single; + this.#usages = key.usages; + this.#extractable = key.extractable; + this.#algorithm = key.algorithm; + this.#keyType = key.keyType; + this[ridSymbol] = key.rid; + } + + get usages() { + return this.#usages; + } + + get extractable() { + return this.#extractable; + } + + get algorithm() { + return this.#algorithm; + } + + get keyType() { + return this.#keyType; } } @@ -61,20 +89,19 @@ return await core.jsonOpAsync("op_webcrypto_sign_key", { rid, algorithm }, data).data; } + const subtle = { + generateKey, + sign, + }; + window.crypto = { getRandomValues, - subtle: { - generateKey, - sign, - } + subtle, }; window.__bootstrap = window.__bootstrap || {}; window.__bootstrap.crypto = { getRandomValues, generateKey, - subtle: { - generateKey, - sign, - } + subtle, }; })(this); diff --git a/op_crates/crypto/Cargo.toml b/op_crates/crypto/Cargo.toml index 4827b3fa4c122a..11ad75e5715571 100644 --- a/op_crates/crypto/Cargo.toml +++ b/op_crates/crypto/Cargo.toml @@ -17,5 +17,5 @@ path = "lib.rs" deno_core = { version = "0.79.0", path = "../../core" } rand = "0.7.0" ring = { version = "0.16.20", features = ["std"] } -rsa = "0.3.0" +rsa = { git = "https://github.com/RustCrypto/RSA", rev = "616b08d" } serde = { version = "1.0.123", features = ["derive"] } \ No newline at end of file diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 2dc0a44911af51..31b13ee4a3746f 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -29,11 +29,10 @@ use ring::hmac::Key as HmacKey; use ring::rand as RingRand; use ring::signature::EcdsaKeyPair; use ring::signature::EcdsaSigningAlgorithm; -use ring::signature::KeyPair; -use rsa::algorithms::generate_multi_prime_key; use rsa::padding::PaddingScheme; use rsa::RSAPrivateKey; use rsa::RSAPublicKey; +use rsa::BigUint; use std::path::PathBuf; pub use rand; // Re-export rand @@ -42,7 +41,6 @@ mod key; use crate::key::Algorithm; use crate::key::CryptoKeyPair; -use crate::key::KeyType; use crate::key::KeyUsage; use crate::key::WebCryptoHash; use crate::key::WebCryptoKey; @@ -117,10 +115,10 @@ impl Resource for CryptoKeyResource { #[serde(rename_all = "camelCase")] struct WebCryptoAlgorithmArg { name: Algorithm, - public_exponent: u32, - modulus_length: u32, + public_exponent: Option, + modulus_length: Option, hash: Option, - // length: Option + length: Option, named_curve: Option, } @@ -145,8 +143,6 @@ pub async fn op_webcrypto_generate_key( _zero_copy: BufVec, ) -> Result { let args: WebCryptoGenerateKeyArg = serde_json::from_value(args)?; - let exponent = args.algorithm.public_exponent; - let bits = args.algorithm.modulus_length; let extractable = args.extractable; let algorithm = args.algorithm.name; @@ -154,10 +150,13 @@ pub async fn op_webcrypto_generate_key( let (rid, js_key) = match algorithm { Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss | Algorithm::RsaOaep => { + let exp = args.algorithm.public_exponent.unwrap(); + let modulus_length = args.algorithm.modulus_length.unwrap(); + let exponent = BigUint::from(exp); + // Generate RSA private key based of exponent, bits and Rng. let mut rng = OsRng; - let private_key = - generate_multi_prime_key(&mut rng, exponent as usize, bits as usize)?; + let private_key = RSAPrivateKey::new_with_exp(&mut rng, modulus_length as usize, &exponent)?; // Extract public key from private key. let public_key = private_key.to_public_key(); From 473f957f798b96232bea92f4c33d2f17ef62ecf5 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 2 Mar 2021 04:50:00 +0000 Subject: [PATCH 018/130] fix key pair logic --- generateKey.js | 4 ++-- op_crates/crypto/01_crypto.js | 25 ++++++++++++++++++------- op_crates/crypto/lib.rs | 8 ++++++-- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/generateKey.js b/generateKey.js index c643d376d5ca1a..5a3ac0f0a8355a 100644 --- a/generateKey.js +++ b/generateKey.js @@ -1,8 +1,8 @@ let key = await window.crypto.subtle.generateKey( { name: "RSA-OAEP", - modulusLength: 4096, - publicExponent: 2, + modulusLength: 1024, + publicExponent: 65537, hash: "SHA-256" }, true, diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index c989b9f6243fe4..04ea190448c506 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -52,15 +52,12 @@ #algorithm #keyType - constructor(key) { - // The key is serailized from an Enum in the Rust-side. - // Therefore, we flatten it here. - let key = key.pair || key.single; + constructor(key, rid) { this.#usages = key.usages; this.#extractable = key.extractable; this.#algorithm = key.algorithm; this.#keyType = key.keyType; - this[ridSymbol] = key.rid; + this[ridSymbol] = rid; } get usages() { @@ -80,12 +77,26 @@ } } + class CryptoKeyPair { + constructor(privateKey, publicKey, rid) { + this.privateKey = new CryptoKey(privateKey); + this.publicKey = new CryptoKey(publicKey); + this[ridSymbol] = rid; + } + } + + // Determine when key is a crypto key pair. + function isKeyPair(key) { + return Boolean(key.privateKey); + } + async function generateKey(algorithm, extractable, keyUsages) { - return new CryptoKey(await core.jsonOpAsync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages })) + let { rid, key }= await core.jsonOpAsync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages }); + return key.single ? new CryptoKey(key.single, rid) : new CryptoKeyPair(key.pair.privateKey, key.pair.publicKey, rid); } async function sign(algorithm, key, data) { - let rid = key.rid; + let rid = isKeyPair(key) ? key.privateKey[ridSymbol] : key[ridSymbol]; return await core.jsonOpAsync("op_webcrypto_sign_key", { rid, algorithm }, data).data; } diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 31b13ee4a3746f..16228665e3464a 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -30,9 +30,9 @@ use ring::rand as RingRand; use ring::signature::EcdsaKeyPair; use ring::signature::EcdsaSigningAlgorithm; use rsa::padding::PaddingScheme; +use rsa::BigUint; use rsa::RSAPrivateKey; use rsa::RSAPublicKey; -use rsa::BigUint; use std::path::PathBuf; pub use rand; // Re-export rand @@ -156,7 +156,11 @@ pub async fn op_webcrypto_generate_key( // Generate RSA private key based of exponent, bits and Rng. let mut rng = OsRng; - let private_key = RSAPrivateKey::new_with_exp(&mut rng, modulus_length as usize, &exponent)?; + let private_key = RSAPrivateKey::new_with_exp( + &mut rng, + modulus_length as usize, + &exponent, + )?; // Extract public key from private key. let public_key = private_key.to_public_key(); From c29f7361ef60ebf4c23517bb283934aabe4c5016 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 2 Mar 2021 08:22:31 +0000 Subject: [PATCH 019/130] progress --- cli/dts/lib.dom.d.ts | 2 +- generateKey.js | 10 +++++++++- op_crates/crypto/01_crypto.js | 19 +++++++++++-------- op_crates/crypto/key.rs | 12 ++++++++++++ op_crates/crypto/lib.deno_crypto.d.ts | 10 +++++++++- op_crates/crypto/lib.rs | 12 +++++------- 6 files changed, 47 insertions(+), 18 deletions(-) diff --git a/cli/dts/lib.dom.d.ts b/cli/dts/lib.dom.d.ts index 960a6800eaeb4c..78eb93e2e93ce6 100644 --- a/cli/dts/lib.dom.d.ts +++ b/cli/dts/lib.dom.d.ts @@ -15503,7 +15503,7 @@ declare var StyleSheetList: { prototype: StyleSheetList; new(): StyleSheetList; }; - + /** 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 { decrypt(algorithm: AlgorithmIdentifier | RsaOaepParams | AesCtrParams | AesCbcParams | AesCmacParams | AesGcmParams | AesCfbParams, key: CryptoKey, data: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer): Promise; diff --git a/generateKey.js b/generateKey.js index 5a3ac0f0a8355a..09002d5fd30b5a 100644 --- a/generateKey.js +++ b/generateKey.js @@ -8,5 +8,13 @@ let key = await window.crypto.subtle.generateKey( true, ["encrypt", "decrypt"] ); +console.log(key) +let enc = new TextEncoder(); +let encoded = enc.encode("Hey") +let signature = await window.crypto.subtle.sign( + "RSA-OAEP", + key, + encoded +); -console.log(key); \ No newline at end of file +console.log(signature); \ No newline at end of file diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 04ea190448c506..6f6d9617158242 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -85,19 +85,22 @@ } } - // Determine when key is a crypto key pair. - function isKeyPair(key) { - return Boolean(key.privateKey); - } - async function generateKey(algorithm, extractable, keyUsages) { - let { rid, key }= await core.jsonOpAsync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages }); + let { rid, key } = await core.jsonOpAsync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages }); return key.single ? new CryptoKey(key.single, rid) : new CryptoKeyPair(key.pair.privateKey, key.pair.publicKey, rid); } async function sign(algorithm, key, data) { - let rid = isKeyPair(key) ? key.privateKey[ridSymbol] : key[ridSymbol]; - return await core.jsonOpAsync("op_webcrypto_sign_key", { rid, algorithm }, data).data; + let rid = key[ridSymbol]; + let simpleParam = typeof algorithm == "string"; + + // Normalize params. We've got serde doing the null to Option serialization. + let saltLength = simpleParam ? null: algorithm.saltLength || null; + let hash = simpleParam ? null : algorithm.hash || null; + algorithm = simpleParam ? algorithm : algorithm.name; + + console.log(rid) + return await core.jsonOpAsync("op_webcrypto_sign_key", { rid, algorithm, saltLength, hash }, data).data; } const subtle = { diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index b9a90159b9f9c2..108cd9054a5a18 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -1,4 +1,5 @@ use ring::agreement::Algorithm as RingAlgorithm; +use ring::hmac::Algorithm as HmacAlgorithm; use ring::signature::EcdsaSigningAlgorithm; use serde::Deserialize; use serde::Serialize; @@ -59,6 +60,17 @@ impl Into<&EcdsaSigningAlgorithm> for WebCryptoNamedCurve { } } +impl Into for WebCryptoHash { + fn into(self) -> HmacAlgorithm { + match self { + WebCryptoHash::Sha1 => ring::hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, + WebCryptoHash::Sha256 => ring::hmac::HMAC_SHA256, + WebCryptoHash::Sha384 => ring::hmac::HMAC_SHA384, + WebCryptoHash::Sha512 => ring::hmac::HMAC_SHA512, + } + } +} + #[derive(Serialize, Deserialize, Copy, Clone)] #[serde(rename_all = "camelCase")] pub enum KeyUsage { diff --git a/op_crates/crypto/lib.deno_crypto.d.ts b/op_crates/crypto/lib.deno_crypto.d.ts index a00757e7193ba1..aebe0395359e38 100644 --- a/op_crates/crypto/lib.deno_crypto.d.ts +++ b/op_crates/crypto/lib.deno_crypto.d.ts @@ -5,8 +5,16 @@ declare var crypto: Crypto; +/** 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 | DhKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise; + generateKey(algorithm: HmacKeyGenParams | Pbkdf2Params, extractable: boolean, keyUsages: KeyUsage[]): Promise; + generateKey(algorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: KeyUsage[]): Promise; + sign(algorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams, key: CryptoKey, data: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer): Promise; +} + declare interface Crypto { - readonly subtle: null; + readonly subtle: SubtleCrypto; getRandomValues< T extends | Int8Array diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 16228665e3464a..283a40eed28274 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -26,6 +26,7 @@ use rand::Rng; use ring::agreement::Algorithm as RingAlgorithm; use ring::agreement::EphemeralPrivateKey; use ring::hmac::Key as HmacKey; +use ring::hmac::Algorithm as HmacAlgorithm; use ring::rand as RingRand; use ring::signature::EcdsaKeyPair; use ring::signature::EcdsaSigningAlgorithm; @@ -240,12 +241,7 @@ pub async fn op_webcrypto_generate_key( ) } Algorithm::Hmac => { - let hash = match args.algorithm.hash.unwrap() { - WebCryptoHash::Sha1 => ring::hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, - WebCryptoHash::Sha256 => ring::hmac::HMAC_SHA256, - WebCryptoHash::Sha384 => ring::hmac::HMAC_SHA384, - WebCryptoHash::Sha512 => ring::hmac::HMAC_SHA512, - }; + let hash: HmacAlgorithm = args.algorithm.hash.unwrap().into(); let rng = RingRand::SystemRandom::new(); // TODO: change algorithm length when specified. let key = HmacKey::generate(hash, &rng)?; @@ -254,7 +250,6 @@ pub async fn op_webcrypto_generate_key( crypto_key: crypto_key.clone(), key, }; - ( state.resource_table.add(resource), JSCryptoKey::Single(crypto_key), @@ -267,9 +262,12 @@ pub async fn op_webcrypto_generate_key( } #[derive(Deserialize)] +#[serde(rename_all = "camelCase")] struct WebCryptoSignArg { rid: u32, algorithm: Algorithm, + salt_length: Option, + hash: Option, } pub async fn op_webcrypto_sign_key( From a33fbc709a2b9ed353051d12d19f215b8d97bb63 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 2 Mar 2021 09:31:36 +0000 Subject: [PATCH 020/130] impl sign --- Cargo.lock | 17 +++++++++++++++- op_crates/crypto/Cargo.toml | 2 ++ op_crates/crypto/lib.rs | 39 ++++++++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 401438ee1af921..ee0f8c622df208 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -594,6 +594,8 @@ dependencies = [ "ring", "rsa", "serde", + "sha-1", + "sha2", ] [[package]] @@ -2854,9 +2856,22 @@ dependencies = [ [[package]] name = "sha-1" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f" +dependencies = [ + "block-buffer", + "cfg-if 1.0.0", + "cpuid-bool", + "digest", + "opaque-debug", +] + +[[package]] +name = "sha2" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4b312c3731e3fe78a185e6b9b911a7aa715b8e31cce117975219aab2acf285d" +checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" dependencies = [ "block-buffer", "cfg-if 1.0.0", diff --git a/op_crates/crypto/Cargo.toml b/op_crates/crypto/Cargo.toml index 11ad75e5715571..938ce36ee61cdb 100644 --- a/op_crates/crypto/Cargo.toml +++ b/op_crates/crypto/Cargo.toml @@ -18,4 +18,6 @@ deno_core = { version = "0.79.0", path = "../../core" } rand = "0.7.0" ring = { version = "0.16.20", features = ["std"] } rsa = { git = "https://github.com/RustCrypto/RSA", rev = "616b08d" } +sha-1 = "0.9.4" +sha2 = "0.9.3" serde = { version = "1.0.123", features = ["derive"] } \ No newline at end of file diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 283a40eed28274..19890b233c4cd8 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -25,8 +25,8 @@ use rand::thread_rng; use rand::Rng; use ring::agreement::Algorithm as RingAlgorithm; use ring::agreement::EphemeralPrivateKey; -use ring::hmac::Key as HmacKey; use ring::hmac::Algorithm as HmacAlgorithm; +use ring::hmac::Key as HmacKey; use ring::rand as RingRand; use ring::signature::EcdsaKeyPair; use ring::signature::EcdsaSigningAlgorithm; @@ -34,6 +34,8 @@ use rsa::padding::PaddingScheme; use rsa::BigUint; use rsa::RSAPrivateKey; use rsa::RSAPublicKey; +use sha1::Sha1; +use sha2::{Digest, Sha256, Sha384, Sha512}; use std::path::PathBuf; pub use rand; // Re-export rand @@ -79,6 +81,7 @@ pub fn op_crypto_get_random_values( struct CryptoKeyPairResource { crypto_key: WebCryptoKeyPair, key: CryptoKeyPair, + hash: Option, } impl Resource for CryptoKeyPairResource { @@ -104,6 +107,7 @@ impl Resource struct CryptoKeyResource { crypto_key: WebCryptoKey, key: K, + hash: Option, } impl Resource for CryptoKeyResource { @@ -180,6 +184,7 @@ pub async fn op_webcrypto_generate_key( let resource = CryptoKeyPairResource { crypto_key: crypto_key.clone(), key, + hash: args.algorithm.hash, }; ( state.resource_table.add(resource), @@ -210,6 +215,7 @@ pub async fn op_webcrypto_generate_key( let resource = CryptoKeyPairResource { crypto_key: crypto_key.clone(), key, + hash: args.algorithm.hash, }; ( @@ -233,6 +239,7 @@ pub async fn op_webcrypto_generate_key( let resource = CryptoKeyResource { crypto_key: crypto_key.clone(), key: private_key, + hash: args.algorithm.hash, }; ( @@ -249,6 +256,7 @@ pub async fn op_webcrypto_generate_key( let resource = CryptoKeyResource { crypto_key: crypto_key.clone(), key, + hash: args.algorithm.hash, }; ( state.resource_table.add(resource), @@ -297,6 +305,35 @@ pub async fn op_webcrypto_sign_key( // Sign data based on computed padding and return buffer private_key.sign(padding, &data)? } + Algorithm::RsaOaep => { + let resource = state + .resource_table + .get::>(args.rid) + .ok_or_else(bad_resource_id)?; + + let private_key = &resource.key.private_key; + + let rng = OsRng; + let salt_len = args.salt_length.unwrap() as usize; + + let padding = match resource.hash.unwrap() { + WebCryptoHash::Sha1 => { + PaddingScheme::new_pss_with_salt::(rng, salt_len) + } + WebCryptoHash::Sha256 => { + PaddingScheme::new_pss_with_salt::(rng, salt_len) + } + WebCryptoHash::Sha384 => { + PaddingScheme::new_pss_with_salt::(rng, salt_len) + } + WebCryptoHash::Sha512 => { + PaddingScheme::new_pss_with_salt::(rng, salt_len) + } + }; + + // Sign data based on computed padding and return buffer + private_key.sign(padding, &data)? + } Algorithm::Ecdsa => { let resource = state .resource_table From 869171a936be04ea4dc764501453224ad56fcd43 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 3 Mar 2021 10:50:24 +0000 Subject: [PATCH 021/130] cleanup and error handling --- generateKey.js | 4 +- op_crates/crypto/01_crypto.js | 42 ++++---- op_crates/crypto/error.rs | 20 ++++ op_crates/crypto/key.rs | 33 +++---- op_crates/crypto/lib.rs | 181 ++++++++++++++++++++-------------- 5 files changed, 168 insertions(+), 112 deletions(-) create mode 100644 op_crates/crypto/error.rs diff --git a/generateKey.js b/generateKey.js index 09002d5fd30b5a..7299b5a37bcd9e 100644 --- a/generateKey.js +++ b/generateKey.js @@ -1,6 +1,6 @@ let key = await window.crypto.subtle.generateKey( { - name: "RSA-OAEP", + name: "RSA-PSS", modulusLength: 1024, publicExponent: 65537, hash: "SHA-256" @@ -12,7 +12,7 @@ console.log(key) let enc = new TextEncoder(); let encoded = enc.encode("Hey") let signature = await window.crypto.subtle.sign( - "RSA-OAEP", + "RSA-PSS", key, encoded ); diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 6f6d9617158242..01912f21549ebf 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -47,10 +47,10 @@ // The CryptoKey class. A JavaScript representation of a WebCrypto key. // Stores rid of the actual key along with read-only properties. class CryptoKey { - #usages - #extractable - #algorithm - #keyType + #usages; + #extractable; + #algorithm; + #keyType; constructor(key, rid) { this.#usages = key.usages; @@ -77,17 +77,18 @@ } } - class CryptoKeyPair { - constructor(privateKey, publicKey, rid) { - this.privateKey = new CryptoKey(privateKey); - this.publicKey = new CryptoKey(publicKey); - this[ridSymbol] = rid; - } - } - async function generateKey(algorithm, extractable, keyUsages) { - let { rid, key } = await core.jsonOpAsync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages }); - return key.single ? new CryptoKey(key.single, rid) : new CryptoKeyPair(key.pair.privateKey, key.pair.publicKey, rid); + let { key } = await core.jsonOpAsync("op_webcrypto_generate_key", { + algorithm, + extractable, + keyUsages, + }); + return key.single + ? new CryptoKey(key.single.key, key.single.rid) + : { + privateKey: new CryptoKey(key.pair.key.privateKey, key.pair.rid), + publicKey: new CryptoKey(key.pair.key.publicKey, key.pair.rid), + }; } async function sign(algorithm, key, data) { @@ -95,12 +96,17 @@ let simpleParam = typeof algorithm == "string"; // Normalize params. We've got serde doing the null to Option serialization. - let saltLength = simpleParam ? null: algorithm.saltLength || null; + let saltLength = simpleParam ? null : algorithm.saltLength || null; let hash = simpleParam ? null : algorithm.hash || null; algorithm = simpleParam ? algorithm : algorithm.name; - - console.log(rid) - return await core.jsonOpAsync("op_webcrypto_sign_key", { rid, algorithm, saltLength, hash }, data).data; + + console.log(rid); + return await core.jsonOpAsync("op_webcrypto_sign_key", { + rid, + algorithm, + saltLength, + hash, + }, data).data; } const subtle = { diff --git a/op_crates/crypto/error.rs b/op_crates/crypto/error.rs new file mode 100644 index 00000000000000..fbedb544de5d01 --- /dev/null +++ b/op_crates/crypto/error.rs @@ -0,0 +1,20 @@ +use std::fmt; + +#[derive(Debug)] +pub enum WebCryptoError { + MissingArgument(String), + Unsupported, +} + +impl fmt::Display for WebCryptoError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + WebCryptoError::MissingArgument(s) => { + write!(f, "Missing argument {}", &s) + } + WebCryptoError::Unsupported => write!(f, "Unsupported algorithm"), + } + } +} + +impl std::error::Error for WebCryptoError {} diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index 108cd9054a5a18..79be0365170e1d 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -1,8 +1,10 @@ +use crate::error::WebCryptoError; use ring::agreement::Algorithm as RingAlgorithm; use ring::hmac::Algorithm as HmacAlgorithm; use ring::signature::EcdsaSigningAlgorithm; use serde::Deserialize; use serde::Serialize; +use std::convert::TryInto; #[derive(Serialize, Deserialize, Copy, Clone)] #[serde(rename_all = "camelCase")] @@ -34,28 +36,30 @@ pub enum WebCryptoNamedCurve { P521, } -impl Into<&RingAlgorithm> for WebCryptoNamedCurve { - fn into(self) -> &'static RingAlgorithm { +impl TryInto<&RingAlgorithm> for WebCryptoNamedCurve { + type Error = WebCryptoError; + + fn try_into(self) -> Result<&'static RingAlgorithm, Self::Error> { match self { - WebCryptoNamedCurve::P256 => &ring::agreement::ECDH_P256, - WebCryptoNamedCurve::P384 => &ring::agreement::ECDH_P384, - // XXX: Not implemented. - WebCryptoNamedCurve::P521 => panic!(), + WebCryptoNamedCurve::P256 => Ok(&ring::agreement::ECDH_P256), + WebCryptoNamedCurve::P384 => Ok(&ring::agreement::ECDH_P384), + WebCryptoNamedCurve::P521 => Err(WebCryptoError::Unsupported), } } } -impl Into<&EcdsaSigningAlgorithm> for WebCryptoNamedCurve { - fn into(self) -> &'static EcdsaSigningAlgorithm { +impl TryInto<&EcdsaSigningAlgorithm> for WebCryptoNamedCurve { + type Error = WebCryptoError; + + fn try_into(self) -> Result<&'static EcdsaSigningAlgorithm, Self::Error> { match self { WebCryptoNamedCurve::P256 => { - &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING + Ok(&ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING) } WebCryptoNamedCurve::P384 => { - &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING + Ok(&ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING) } - // TODO: Not implemented but don't panic. - WebCryptoNamedCurve::P521 => panic!(), + WebCryptoNamedCurve::P521 => Err(WebCryptoError::Unsupported), } } } @@ -167,11 +171,6 @@ impl WebCryptoKeyPair { } } -pub struct CryptoKeyPair { - pub public_key: A, - pub private_key: B, -} - #[derive(Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct WebCryptoKeyPair { diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 19890b233c4cd8..4a1e656eb6080c 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -17,6 +17,7 @@ use serde::Serialize; use std::borrow::Cow; use std::cell::RefCell; +use std::convert::TryInto; use std::rc::Rc; use rand::rngs::OsRng; @@ -40,10 +41,11 @@ use std::path::PathBuf; pub use rand; // Re-export rand +mod error; mod key; +use crate::error::WebCryptoError; use crate::key::Algorithm; -use crate::key::CryptoKeyPair; use crate::key::KeyUsage; use crate::key::WebCryptoHash; use crate::key::WebCryptoKey; @@ -78,41 +80,45 @@ pub fn op_crypto_get_random_values( Ok(json!({})) } -struct CryptoKeyPairResource { - crypto_key: WebCryptoKeyPair, - key: CryptoKeyPair, +struct CryptoKeyResource { + crypto_key: WebCryptoKey, + key: A, hash: Option, } -impl Resource for CryptoKeyPairResource { +impl Resource for CryptoKeyResource { fn name(&self) -> Cow { - "RSACryptoKeyPair".into() + "RSAPublicCryptoKey".into() + } +} + +impl Resource for CryptoKeyResource { + fn name(&self) -> Cow { + "RSAPrivateCryptoKey".into() } } impl Resource for CryptoKeyResource { fn name(&self) -> Cow { - "ECDSACryptoKeyPair".into() + "ECDSACryptoKey".into() } } -impl Resource - for CryptoKeyPairResource -{ +impl Resource for CryptoKeyResource { fn name(&self) -> Cow { - "ECDHCryptoKeyPair".into() + "ECDHPublicKey".into() } } -struct CryptoKeyResource { - crypto_key: WebCryptoKey, - key: K, - hash: Option, +impl Resource for CryptoKeyResource { + fn name(&self) -> Cow { + "ECDHPrivateKey".into() + } } impl Resource for CryptoKeyResource { fn name(&self) -> Cow { - "cryptoKey".into() + "HMACKey".into() } } @@ -138,8 +144,15 @@ struct WebCryptoGenerateKeyArg { #[derive(Serialize)] #[serde(rename_all = "camelCase")] enum JSCryptoKey { - Single(WebCryptoKey), - Pair(WebCryptoKeyPair), + Single { + key: WebCryptoKey, + rid: u32, + }, + Pair { + key: WebCryptoKeyPair, + private_rid: u32, + public_rid: u32, + }, } pub async fn op_webcrypto_generate_key( @@ -153,10 +166,16 @@ pub async fn op_webcrypto_generate_key( let mut state = state.borrow_mut(); - let (rid, js_key) = match algorithm { + let key = match algorithm { Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss | Algorithm::RsaOaep => { - let exp = args.algorithm.public_exponent.unwrap(); - let modulus_length = args.algorithm.modulus_length.unwrap(); + let exp = args.algorithm.public_exponent.ok_or( + WebCryptoError::MissingArgument("publicExponent".to_string()), + )?; + let modulus_length = args + .algorithm + .modulus_length + .ok_or(WebCryptoError::MissingArgument("modulusLength".to_string()))?; + let exponent = BigUint::from(exp); // Generate RSA private key based of exponent, bits and Rng. @@ -174,27 +193,32 @@ pub async fn op_webcrypto_generate_key( WebCryptoKey::new_public(algorithm.clone(), extractable, vec![]); let webcrypto_key_private = WebCryptoKey::new_private(algorithm, extractable, vec![]); - let crypto_key = - WebCryptoKeyPair::new(webcrypto_key_public, webcrypto_key_private); - - let key = CryptoKeyPair { - public_key, - private_key, - }; - let resource = CryptoKeyPairResource { - crypto_key: crypto_key.clone(), - key, - hash: args.algorithm.hash, - }; - ( - state.resource_table.add(resource), - JSCryptoKey::Pair(crypto_key), - ) + let crypto_key = WebCryptoKeyPair::new( + webcrypto_key_public.clone(), + webcrypto_key_private.clone(), + ); + + JSCryptoKey::Pair { + key: crypto_key, + private_rid: state.resource_table.add(CryptoKeyResource { + crypto_key: webcrypto_key_private, + key: private_key, + hash: args.algorithm.hash, + }), + public_rid: state.resource_table.add(CryptoKeyResource { + crypto_key: webcrypto_key_public, + key: public_key, + hash: args.algorithm.hash, + }), + } } Algorithm::Ecdh => { // Determine agreement from algorithm named_curve. - let agreement: &RingAlgorithm = - args.algorithm.named_curve.unwrap().into(); + let agreement: &RingAlgorithm = args + .algorithm + .named_curve + .ok_or(WebCryptoError::MissingArgument("namedCurve".to_string()))? + .try_into()?; // Generate private key from agreement and ring rng. let rng = RingRand::SystemRandom::new(); let private_key = EphemeralPrivateKey::generate(&agreement, &rng)?; @@ -205,27 +229,31 @@ pub async fn op_webcrypto_generate_key( WebCryptoKey::new_public(algorithm.clone(), extractable, vec![]); let webcrypto_key_private = WebCryptoKey::new_private(algorithm, extractable, vec![]); - let crypto_key = - WebCryptoKeyPair::new(webcrypto_key_public, webcrypto_key_private); - - let key = CryptoKeyPair { - public_key, - private_key, - }; - let resource = CryptoKeyPairResource { - crypto_key: crypto_key.clone(), - key, - hash: args.algorithm.hash, - }; - - ( - state.resource_table.add(resource), - JSCryptoKey::Pair(crypto_key), - ) + let crypto_key = WebCryptoKeyPair::new( + webcrypto_key_public.clone(), + webcrypto_key_private.clone(), + ); + + JSCryptoKey::Pair { + key: crypto_key, + private_rid: state.resource_table.add(CryptoKeyResource { + crypto_key: webcrypto_key_private, + key: private_key, + hash: args.algorithm.hash, + }), + public_rid: state.resource_table.add(CryptoKeyResource { + crypto_key: webcrypto_key_public, + key: public_key, + hash: args.algorithm.hash, + }), + } } Algorithm::Ecdsa => { - let curve: &EcdsaSigningAlgorithm = - args.algorithm.named_curve.unwrap().into(); + let curve: &EcdsaSigningAlgorithm = args + .algorithm + .named_curve + .ok_or(WebCryptoError::MissingArgument("namedCurve".to_string()))? + .try_into()?; let rng = RingRand::SystemRandom::new(); let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)?; @@ -242,13 +270,17 @@ pub async fn op_webcrypto_generate_key( hash: args.algorithm.hash, }; - ( - state.resource_table.add(resource), - JSCryptoKey::Single(crypto_key), - ) + JSCryptoKey::Single { + key: crypto_key, + rid: state.resource_table.add(resource), + } } Algorithm::Hmac => { - let hash: HmacAlgorithm = args.algorithm.hash.unwrap().into(); + let hash: HmacAlgorithm = args + .algorithm + .hash + .ok_or(WebCryptoError::MissingArgument("hash".to_string()))? + .into(); let rng = RingRand::SystemRandom::new(); // TODO: change algorithm length when specified. let key = HmacKey::generate(hash, &rng)?; @@ -258,15 +290,15 @@ pub async fn op_webcrypto_generate_key( key, hash: args.algorithm.hash, }; - ( - state.resource_table.add(resource), - JSCryptoKey::Single(crypto_key), - ) + JSCryptoKey::Single { + key: crypto_key, + rid: state.resource_table.add(resource), + } } - _ => return Ok(json!({})), + _ => return Err(WebCryptoError::Unsupported.into()), }; - Ok(json!({ "rid": rid, "key": js_key })) + Ok(json!({ "key": key })) } #[derive(Deserialize)] @@ -294,10 +326,10 @@ pub async fn op_webcrypto_sign_key( Algorithm::RsassaPkcs1v15 => { let resource = state .resource_table - .get::>(args.rid) + .get::>(args.rid) .ok_or_else(bad_resource_id)?; - let private_key = &resource.key.private_key; + let private_key = &resource.key; // TODO(littledivy): Modify resource to store args from generateKey. // let hash = resource.crypto_key.private_key.hash; let padding = PaddingScheme::PKCS1v15Sign { hash: None }; @@ -308,14 +340,13 @@ pub async fn op_webcrypto_sign_key( Algorithm::RsaOaep => { let resource = state .resource_table - .get::>(args.rid) + .get::>(args.rid) .ok_or_else(bad_resource_id)?; - let private_key = &resource.key.private_key; + let private_key = &resource.key; let rng = OsRng; let salt_len = args.salt_length.unwrap() as usize; - let padding = match resource.hash.unwrap() { WebCryptoHash::Sha1 => { PaddingScheme::new_pss_with_salt::(rng, salt_len) @@ -358,7 +389,7 @@ pub async fn op_webcrypto_sign_key( let signature = ring::hmac::sign(&key, &data); signature.as_ref().to_vec() } - _ => panic!(), // TODO: don't panic + _ => return Err(WebCryptoError::Unsupported.into()), }; Ok(json!({ "data": signature })) From 139dc92c4bae1933a81be95883752466585b14b4 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 3 Mar 2021 14:01:19 +0000 Subject: [PATCH 022/130] ok --- generateKey.js | 2 +- op_crates/crypto/01_crypto.js | 10 +++++++--- op_crates/crypto/error.rs | 13 +++++++++++++ op_crates/crypto/key.rs | 2 +- op_crates/crypto/lib.rs | 3 +++ 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/generateKey.js b/generateKey.js index 7299b5a37bcd9e..48e4303849828f 100644 --- a/generateKey.js +++ b/generateKey.js @@ -13,7 +13,7 @@ let enc = new TextEncoder(); let encoded = enc.encode("Hey") let signature = await window.crypto.subtle.sign( "RSA-PSS", - key, + key.privateKey, encoded ); diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 01912f21549ebf..3fc89a1f7b2588 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -78,16 +78,20 @@ } async function generateKey(algorithm, extractable, keyUsages) { - let { key } = await core.jsonOpAsync("op_webcrypto_generate_key", { + let { key, err } = await core.jsonOpAsync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages, }); + + // A DOMError. + if(err) throw new Error(err); + return key.single ? new CryptoKey(key.single.key, key.single.rid) : { - privateKey: new CryptoKey(key.pair.key.privateKey, key.pair.rid), - publicKey: new CryptoKey(key.pair.key.publicKey, key.pair.rid), + privateKey: new CryptoKey(key.pair.key.privateKey, key.pair.privateRid), + publicKey: new CryptoKey(key.pair.key.publicKey, key.pair.publicRid), }; } diff --git a/op_crates/crypto/error.rs b/op_crates/crypto/error.rs index fbedb544de5d01..2b192d77b387f3 100644 --- a/op_crates/crypto/error.rs +++ b/op_crates/crypto/error.rs @@ -1,4 +1,5 @@ use std::fmt; +use crate::key::KeyUsage; #[derive(Debug)] pub enum WebCryptoError { @@ -18,3 +19,15 @@ impl fmt::Display for WebCryptoError { } impl std::error::Error for WebCryptoError {} + +#[derive(Debug)] +pub struct DOMError(String) + +impl fmt::Display for DOMError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", &self.0) + } +} + +impl std::error::Error for DOMError {} + diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index 79be0365170e1d..d243869f6a8664 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -75,7 +75,7 @@ impl Into for WebCryptoHash { } } -#[derive(Serialize, Deserialize, Copy, Clone)] +#[derive(Serialize, Deserialize, Copy, Clone, Debug)] #[serde(rename_all = "camelCase")] pub enum KeyUsage { Encrypt, diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 4a1e656eb6080c..cd6772c5008304 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -45,6 +45,7 @@ mod error; mod key; use crate::error::WebCryptoError; +use crate::error::DOMError; use crate::key::Algorithm; use crate::key::KeyUsage; use crate::key::WebCryptoHash; @@ -155,6 +156,7 @@ enum JSCryptoKey { }, } + pub async fn op_webcrypto_generate_key( state: Rc>, args: Value, @@ -249,6 +251,7 @@ pub async fn op_webcrypto_generate_key( } } Algorithm::Ecdsa => { + let curve: &EcdsaSigningAlgorithm = args .algorithm .named_curve From 6c78ed9b6d1ee886408fe1995c065adeb9e95794 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 3 Mar 2021 14:54:32 +0000 Subject: [PATCH 023/130] validate usage --- Cargo.lock | 6 ------ op_crates/crypto/error.rs | 5 +++-- op_crates/crypto/key.rs | 2 +- op_crates/crypto/lib.rs | 20 ++++++++++++++++++-- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 088d4b6714df35..27d25a407a0fac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4206,12 +4206,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "zeroize" version = "1.2.0" diff --git a/op_crates/crypto/error.rs b/op_crates/crypto/error.rs index 2b192d77b387f3..b6e65ecc6b6602 100644 --- a/op_crates/crypto/error.rs +++ b/op_crates/crypto/error.rs @@ -1,5 +1,6 @@ use std::fmt; use crate::key::KeyUsage; +use serde::Serialize; #[derive(Debug)] pub enum WebCryptoError { @@ -20,8 +21,8 @@ impl fmt::Display for WebCryptoError { impl std::error::Error for WebCryptoError {} -#[derive(Debug)] -pub struct DOMError(String) +#[derive(Debug, Serialize)] +pub struct DOMError(pub String); impl fmt::Display for DOMError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index d243869f6a8664..16baeca417afd7 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -75,7 +75,7 @@ impl Into for WebCryptoHash { } } -#[derive(Serialize, Deserialize, Copy, Clone, Debug)] +#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub enum KeyUsage { Encrypt, diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index cd6772c5008304..c16a30c2b8ddc7 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -156,6 +156,15 @@ enum JSCryptoKey { }, } +macro_rules! validate_usage { + ($e: expr, $u: expr) => { + for usage in $e { + if !$u.contains(&usage) { + return Ok(json!({ "err": DOMError("Invalid key usage".to_string()) })) + } + } + } +} pub async fn op_webcrypto_generate_key( state: Rc>, @@ -169,7 +178,9 @@ pub async fn op_webcrypto_generate_key( let mut state = state.borrow_mut(); let key = match algorithm { - Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss | Algorithm::RsaOaep => { + Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss => { + validate_usage!(args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); + let exp = args.algorithm.public_exponent.ok_or( WebCryptoError::MissingArgument("publicExponent".to_string()), )?; @@ -215,6 +226,8 @@ pub async fn op_webcrypto_generate_key( } } Algorithm::Ecdh => { + validate_usage!(args.key_usages, vec![KeyUsage::DeriveKey, KeyUsage::DeriveBits]); + // Determine agreement from algorithm named_curve. let agreement: &RingAlgorithm = args .algorithm @@ -251,7 +264,8 @@ pub async fn op_webcrypto_generate_key( } } Algorithm::Ecdsa => { - + validate_usage!(args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); + let curve: &EcdsaSigningAlgorithm = args .algorithm .named_curve @@ -279,6 +293,8 @@ pub async fn op_webcrypto_generate_key( } } Algorithm::Hmac => { + validate_usage!(args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); + let hash: HmacAlgorithm = args .algorithm .hash From 2c8e18e14802208f5e1609add09a41d015fbe2fc Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 3 Mar 2021 15:55:57 +0000 Subject: [PATCH 024/130] fix: pss instead of oaep for signing --- generateKey.js | 2 +- op_crates/crypto/01_crypto.js | 2 +- op_crates/crypto/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/generateKey.js b/generateKey.js index 48e4303849828f..1eff9a60d461f1 100644 --- a/generateKey.js +++ b/generateKey.js @@ -6,7 +6,7 @@ let key = await window.crypto.subtle.generateKey( hash: "SHA-256" }, true, - ["encrypt", "decrypt"] + ["sign", "verify"] ); console.log(key) let enc = new TextEncoder(); diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 3fc89a1f7b2588..a0418bdd0c49b8 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -87,6 +87,7 @@ // A DOMError. if(err) throw new Error(err); + console.log(key); return key.single ? new CryptoKey(key.single.key, key.single.rid) : { @@ -104,7 +105,6 @@ let hash = simpleParam ? null : algorithm.hash || null; algorithm = simpleParam ? algorithm : algorithm.name; - console.log(rid); return await core.jsonOpAsync("op_webcrypto_sign_key", { rid, algorithm, diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index c16a30c2b8ddc7..70c60b33020146 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -356,7 +356,7 @@ pub async fn op_webcrypto_sign_key( // Sign data based on computed padding and return buffer private_key.sign(padding, &data)? } - Algorithm::RsaOaep => { + Algorithm::RsaPss => { let resource = state .resource_table .get::>(args.rid) From 6801c5b8bd63d19d050132eba5791b22021ee130 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 3 Mar 2021 17:12:40 +0000 Subject: [PATCH 025/130] types --- cli/dts/lib.dom.d.ts | 4 -- op_crates/crypto/01_crypto.js | 5 +- op_crates/crypto/lib.deno_crypto.d.ts | 68 ++++++++++++++++++++++++++- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/cli/dts/lib.dom.d.ts b/cli/dts/lib.dom.d.ts index 78eb93e2e93ce6..030d2af21b348d 100644 --- a/cli/dts/lib.dom.d.ts +++ b/cli/dts/lib.dom.d.ts @@ -1672,10 +1672,6 @@ interface RsaHashedKeyAlgorithm extends RsaKeyAlgorithm { hash: KeyAlgorithm; } -interface RsaHashedKeyGenParams extends RsaKeyGenParams { - hash: HashAlgorithmIdentifier; -} - interface RsaKeyAlgorithm extends KeyAlgorithm { modulusLength: number; publicExponent: BigInteger; diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index a0418bdd0c49b8..de378a663bb270 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -87,12 +87,11 @@ // A DOMError. if(err) throw new Error(err); - console.log(key); return key.single ? new CryptoKey(key.single.key, key.single.rid) : { - privateKey: new CryptoKey(key.pair.key.privateKey, key.pair.privateRid), - publicKey: new CryptoKey(key.pair.key.publicKey, key.pair.publicRid), + privateKey: new CryptoKey(key.pair.key.privateKey, key.pair.private_rid), + publicKey: new CryptoKey(key.pair.key.publicKey, key.pair.public_rid), }; } diff --git a/op_crates/crypto/lib.deno_crypto.d.ts b/op_crates/crypto/lib.deno_crypto.d.ts index aebe0395359e38..7516f3ba709d0b 100644 --- a/op_crates/crypto/lib.deno_crypto.d.ts +++ b/op_crates/crypto/lib.deno_crypto.d.ts @@ -5,10 +5,74 @@ 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: number; +} + +interface RsaPssParams extends Algorithm { + saltLength: 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 | DhKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise; - generateKey(algorithm: HmacKeyGenParams | Pbkdf2Params, extractable: boolean, keyUsages: KeyUsage[]): Promise; + generateKey(algorithm: RsaHashedKeyGenParams | EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise; + generateKey(algorithm: HmacKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise; generateKey(algorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: KeyUsage[]): Promise; sign(algorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams, key: CryptoKey, data: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer): Promise; } From 00a97d8fb6bb6036bf2ab79d6fc3d85b70f24f8d Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 4 Mar 2021 04:43:42 +0000 Subject: [PATCH 026/130] fix lint --- op_crates/crypto/01_crypto.js | 24 +++++++++++------------- op_crates/crypto/error.rs | 9 ++++----- op_crates/crypto/lib.rs | 20 +++++++++++++++----- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index de378a663bb270..8759581cf1a4eb 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -78,30 +78,28 @@ } async function generateKey(algorithm, extractable, keyUsages) { - let { key, err } = await core.jsonOpAsync("op_webcrypto_generate_key", { + const { key, err } = await core.jsonOpAsync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages, }); // A DOMError. - if(err) throw new Error(err); - - return key.single - ? new CryptoKey(key.single.key, key.single.rid) - : { - privateKey: new CryptoKey(key.pair.key.privateKey, key.pair.private_rid), - publicKey: new CryptoKey(key.pair.key.publicKey, key.pair.public_rid), - }; + if (err) throw new Error(err); + + return key.single ? new CryptoKey(key.single.key, key.single.rid) : { + privateKey: new CryptoKey(key.pair.key.privateKey, key.pair.private_rid), + publicKey: new CryptoKey(key.pair.key.publicKey, key.pair.public_rid), + }; } async function sign(algorithm, key, data) { - let rid = key[ridSymbol]; - let simpleParam = typeof algorithm == "string"; + const rid = key[ridSymbol]; + const simpleParam = typeof algorithm == "string"; // Normalize params. We've got serde doing the null to Option serialization. - let saltLength = simpleParam ? null : algorithm.saltLength || null; - let hash = simpleParam ? null : algorithm.hash || null; + const saltLength = simpleParam ? null : algorithm.saltLength || null; + const hash = simpleParam ? null : algorithm.hash || null; algorithm = simpleParam ? algorithm : algorithm.name; return await core.jsonOpAsync("op_webcrypto_sign_key", { diff --git a/op_crates/crypto/error.rs b/op_crates/crypto/error.rs index b6e65ecc6b6602..f99c7ec92552bc 100644 --- a/op_crates/crypto/error.rs +++ b/op_crates/crypto/error.rs @@ -1,6 +1,6 @@ -use std::fmt; use crate::key::KeyUsage; use serde::Serialize; +use std::fmt; #[derive(Debug)] pub enum WebCryptoError { @@ -25,10 +25,9 @@ impl std::error::Error for WebCryptoError {} pub struct DOMError(pub String); impl fmt::Display for DOMError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", &self.0) - } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", &self.0) + } } impl std::error::Error for DOMError {} - diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 70c60b33020146..7386be1869e5f7 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -44,8 +44,8 @@ pub use rand; // Re-export rand mod error; mod key; -use crate::error::WebCryptoError; use crate::error::DOMError; +use crate::error::WebCryptoError; use crate::key::Algorithm; use crate::key::KeyUsage; use crate::key::WebCryptoHash; @@ -226,7 +226,10 @@ pub async fn op_webcrypto_generate_key( } } Algorithm::Ecdh => { - validate_usage!(args.key_usages, vec![KeyUsage::DeriveKey, KeyUsage::DeriveBits]); + validate_usage!( + args.key_usages, + vec![KeyUsage::DeriveKey, KeyUsage::DeriveBits] + ); // Determine agreement from algorithm named_curve. let agreement: &RingAlgorithm = args @@ -294,7 +297,7 @@ pub async fn op_webcrypto_generate_key( } Algorithm::Hmac => { validate_usage!(args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); - + let hash: HmacAlgorithm = args .algorithm .hash @@ -365,8 +368,15 @@ pub async fn op_webcrypto_sign_key( let private_key = &resource.key; let rng = OsRng; - let salt_len = args.salt_length.unwrap() as usize; - let padding = match resource.hash.unwrap() { + let salt_len = args + .salt_length + .ok_or(WebCryptoError::MissingArgument("saltLength".to_string()))? + as usize; + + let padding = match resource + .hash + .ok_or(WebCryptoError::MissingArgument("hash".to_string()))? + { WebCryptoHash::Sha1 => { PaddingScheme::new_pss_with_salt::(rng, salt_len) } From 73c8ad51376f540c2f2c3182abdca3472cbcfb0b Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 4 Mar 2021 04:45:18 +0000 Subject: [PATCH 027/130] undo changes to lib.dom --- cli/dts/lib.dom.d.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cli/dts/lib.dom.d.ts b/cli/dts/lib.dom.d.ts index 030d2af21b348d..960a6800eaeb4c 100644 --- a/cli/dts/lib.dom.d.ts +++ b/cli/dts/lib.dom.d.ts @@ -1672,6 +1672,10 @@ interface RsaHashedKeyAlgorithm extends RsaKeyAlgorithm { hash: KeyAlgorithm; } +interface RsaHashedKeyGenParams extends RsaKeyGenParams { + hash: HashAlgorithmIdentifier; +} + interface RsaKeyAlgorithm extends KeyAlgorithm { modulusLength: number; publicExponent: BigInteger; @@ -15499,7 +15503,7 @@ declare var StyleSheetList: { prototype: StyleSheetList; new(): StyleSheetList; }; - + /** 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 { decrypt(algorithm: AlgorithmIdentifier | RsaOaepParams | AesCtrParams | AesCbcParams | AesCmacParams | AesGcmParams | AesCfbParams, key: CryptoKey, data: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer): Promise; From 8c8ef05c2fcb7d6ab48190e65a33925d109e57b0 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 4 Mar 2021 04:48:30 +0000 Subject: [PATCH 028/130] fix example --- generateKey.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/generateKey.js b/generateKey.js index 1eff9a60d461f1..ac47f9be7b8ec0 100644 --- a/generateKey.js +++ b/generateKey.js @@ -1,4 +1,4 @@ -let key = await window.crypto.subtle.generateKey( +const key = await window.crypto.subtle.generateKey( { name: "RSA-PSS", modulusLength: 1024, @@ -9,9 +9,9 @@ let key = await window.crypto.subtle.generateKey( ["sign", "verify"] ); console.log(key) -let enc = new TextEncoder(); -let encoded = enc.encode("Hey") -let signature = await window.crypto.subtle.sign( +const enc = new TextEncoder(); +const encoded = enc.encode("Hey") +const signature = await window.crypto.subtle.sign( "RSA-PSS", key.privateKey, encoded From a458bc199aef9ad6ca9ded1149cfdd2beeb80951 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 4 Mar 2021 05:01:26 +0000 Subject: [PATCH 029/130] fix lint --- op_crates/crypto/lib.rs | 55 +++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 7386be1869e5f7..b9179f634e01bf 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -181,13 +181,12 @@ pub async fn op_webcrypto_generate_key( Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss => { validate_usage!(args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); - let exp = args.algorithm.public_exponent.ok_or( - WebCryptoError::MissingArgument("publicExponent".to_string()), - )?; - let modulus_length = args - .algorithm - .modulus_length - .ok_or(WebCryptoError::MissingArgument("modulusLength".to_string()))?; + let exp = args.algorithm.public_exponent.ok_or_else(|| { + WebCryptoError::MissingArgument("publicExponent".to_string()) + })?; + let modulus_length = args.algorithm.modulus_length.ok_or_else(|| { + WebCryptoError::MissingArgument("modulusLength".to_string()) + })?; let exponent = BigUint::from(exp); @@ -235,7 +234,9 @@ pub async fn op_webcrypto_generate_key( let agreement: &RingAlgorithm = args .algorithm .named_curve - .ok_or(WebCryptoError::MissingArgument("namedCurve".to_string()))? + .ok_or_else(|| { + WebCryptoError::MissingArgument("namedCurve".to_string()) + })? .try_into()?; // Generate private key from agreement and ring rng. let rng = RingRand::SystemRandom::new(); @@ -244,7 +245,7 @@ pub async fn op_webcrypto_generate_key( let public_key = private_key.compute_public_key()?; // Create webcrypto keypair. let webcrypto_key_public = - WebCryptoKey::new_public(algorithm.clone(), extractable, vec![]); + WebCryptoKey::new_public(algorithm, extractable, vec![]); let webcrypto_key_private = WebCryptoKey::new_private(algorithm, extractable, vec![]); let crypto_key = WebCryptoKeyPair::new( @@ -272,7 +273,9 @@ pub async fn op_webcrypto_generate_key( let curve: &EcdsaSigningAlgorithm = args .algorithm .named_curve - .ok_or(WebCryptoError::MissingArgument("namedCurve".to_string()))? + .ok_or_else(|| { + WebCryptoError::MissingArgument("namedCurve".to_string()) + })? .try_into()?; let rng = RingRand::SystemRandom::new(); @@ -301,7 +304,7 @@ pub async fn op_webcrypto_generate_key( let hash: HmacAlgorithm = args .algorithm .hash - .ok_or(WebCryptoError::MissingArgument("hash".to_string()))? + .ok_or_else(|| WebCryptoError::MissingArgument("hash".to_string()))? .into(); let rng = RingRand::SystemRandom::new(); // TODO: change algorithm length when specified. @@ -352,9 +355,24 @@ pub async fn op_webcrypto_sign_key( .ok_or_else(bad_resource_id)?; let private_key = &resource.key; - // TODO(littledivy): Modify resource to store args from generateKey. - // let hash = resource.crypto_key.private_key.hash; - let padding = PaddingScheme::PKCS1v15Sign { hash: None }; + + let padding = match resource + .hash + .ok_or_else(|| WebCryptoError::MissingArgument("hash".to_string()))? + { + WebCryptoHash::Sha1 => PaddingScheme::PKCS1v15Sign { + hash: Some(rsa::hash::Hash::SHA1), + }, + WebCryptoHash::Sha256 => PaddingScheme::PKCS1v15Sign { + hash: Some(rsa::hash::Hash::SHA2_256), + }, + WebCryptoHash::Sha384 => PaddingScheme::PKCS1v15Sign { + hash: Some(rsa::hash::Hash::SHA2_384), + }, + WebCryptoHash::Sha512 => PaddingScheme::PKCS1v15Sign { + hash: Some(rsa::hash::Hash::SHA2_512), + }, + }; // Sign data based on computed padding and return buffer private_key.sign(padding, &data)? @@ -368,14 +386,13 @@ pub async fn op_webcrypto_sign_key( let private_key = &resource.key; let rng = OsRng; - let salt_len = args - .salt_length - .ok_or(WebCryptoError::MissingArgument("saltLength".to_string()))? - as usize; + let salt_len = args.salt_length.ok_or_else(|| { + WebCryptoError::MissingArgument("saltLength".to_string()) + })? as usize; let padding = match resource .hash - .ok_or(WebCryptoError::MissingArgument("hash".to_string()))? + .ok_or_else(|| WebCryptoError::MissingArgument("hash".to_string()))? { WebCryptoHash::Sha1 => { PaddingScheme::new_pss_with_salt::(rng, salt_len) From 30f3af349e197aa9f6e10c17f51b8827effc2df7 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 4 Mar 2021 08:37:04 +0000 Subject: [PATCH 030/130] validate hash --- op_crates/crypto/error.rs | 3 ++- op_crates/crypto/lib.rs | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/op_crates/crypto/error.rs b/op_crates/crypto/error.rs index f99c7ec92552bc..717158d03ace32 100644 --- a/op_crates/crypto/error.rs +++ b/op_crates/crypto/error.rs @@ -1,4 +1,3 @@ -use crate::key::KeyUsage; use serde::Serialize; use std::fmt; @@ -6,6 +5,7 @@ use std::fmt; pub enum WebCryptoError { MissingArgument(String), Unsupported, + UnsupportedHash, } impl fmt::Display for WebCryptoError { @@ -15,6 +15,7 @@ impl fmt::Display for WebCryptoError { write!(f, "Missing argument {}", &s) } WebCryptoError::Unsupported => write!(f, "Unsupported algorithm"), + WebCryptoError::UnsupportedHash => write!(f, "Unsupported hash"), } } } diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index b9179f634e01bf..fc774163f9fec4 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -36,7 +36,7 @@ use rsa::BigUint; use rsa::RSAPrivateKey; use rsa::RSAPublicKey; use sha1::Sha1; -use sha2::{Digest, Sha256, Sha384, Sha512}; +use sha2::{Sha256, Sha384, Sha512}; use std::path::PathBuf; pub use rand; // Re-export rand @@ -202,7 +202,7 @@ pub async fn op_webcrypto_generate_key( // Create webcrypto keypair. let webcrypto_key_public = - WebCryptoKey::new_public(algorithm.clone(), extractable, vec![]); + WebCryptoKey::new_public(algorithm, extractable, vec![]); let webcrypto_key_private = WebCryptoKey::new_private(algorithm, extractable, vec![]); let crypto_key = WebCryptoKeyPair::new( @@ -283,7 +283,7 @@ pub async fn op_webcrypto_generate_key( let private_key = EcdsaKeyPair::from_pkcs8(&curve, pkcs8.as_ref())?; // Create webcrypto keypair. let webcrypto_key_public = - WebCryptoKey::new_public(algorithm.clone(), extractable, vec![]); + WebCryptoKey::new_public(algorithm, extractable, vec![]); let crypto_key = WebCryptoKey::new_private(algorithm, extractable, vec![]); @@ -418,6 +418,15 @@ pub async fn op_webcrypto_sign_key( .ok_or_else(bad_resource_id)?; let key_pair = &resource.key; + // 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 { + WebCryptoHash::Sha256 | WebCryptoHash::Sha384 => (), + _ => return Err(WebCryptoError::UnsupportedHash.into()), + } + }; + // Sign data using SecureRng and key. let rng = RingRand::SystemRandom::new(); let signature = key_pair.sign(&rng, &data)?; From cd821f39b06bb5c3805496a147aa32060a9a7900 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 4 Mar 2021 15:48:45 +0000 Subject: [PATCH 031/130] x --- op_crates/crypto/lib.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index fc774163f9fec4..07cc4a6af9bc6a 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -301,13 +301,19 @@ pub async fn op_webcrypto_generate_key( Algorithm::Hmac => { validate_usage!(args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); - let hash: HmacAlgorithm = args + let mut hash: HmacAlgorithm = args .algorithm .hash .ok_or_else(|| WebCryptoError::MissingArgument("hash".to_string()))? .into(); let rng = RingRand::SystemRandom::new(); - // TODO: change algorithm length when specified. + + // if let Some(length) = args.algorithm.length { + // let mut alg = hash.digest_algorithm(); + // alg.output_len = length as usize; + // alg.chaining_len = length as usize; + // }; + let key = HmacKey::generate(hash, &rng)?; let crypto_key = WebCryptoKey::new_secret(algorithm, extractable, vec![]); let resource = CryptoKeyResource { From 2a345b4adb95c0b6cdb90db85444121184615fe7 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 4 Mar 2021 16:29:51 +0000 Subject: [PATCH 032/130] fix fmt --- generateKey.js | 12 +++---- op_crates/crypto/lib.deno_crypto.d.ts | 51 ++++++++++++++++++++++----- op_crates/crypto/lib.rs | 2 +- 3 files changed, 50 insertions(+), 15 deletions(-) diff --git a/generateKey.js b/generateKey.js index ac47f9be7b8ec0..f768a19de48e79 100644 --- a/generateKey.js +++ b/generateKey.js @@ -3,18 +3,18 @@ const key = await window.crypto.subtle.generateKey( name: "RSA-PSS", modulusLength: 1024, publicExponent: 65537, - hash: "SHA-256" + hash: "SHA-256", }, true, - ["sign", "verify"] + ["sign", "verify"], ); -console.log(key) +console.log(key); const enc = new TextEncoder(); -const encoded = enc.encode("Hey") +const encoded = enc.encode("Hey"); const signature = await window.crypto.subtle.sign( "RSA-PSS", key.privateKey, - encoded + encoded, ); -console.log(signature); \ No newline at end of file +console.log(signature); diff --git a/op_crates/crypto/lib.deno_crypto.d.ts b/op_crates/crypto/lib.deno_crypto.d.ts index 7516f3ba709d0b..ce2bc87924ca0b 100644 --- a/op_crates/crypto/lib.deno_crypto.d.ts +++ b/op_crates/crypto/lib.deno_crypto.d.ts @@ -16,7 +16,15 @@ interface KeyAlgorithm { type AlgorithmIdentifier = string | Algorithm; type HashAlgorithmIdentifier = AlgorithmIdentifier; type KeyType = "private" | "public" | "secret"; -type KeyUsage = "decrypt" | "deriveBits" | "deriveKey" | "encrypt" | "sign" | "unwrapKey" | "verify" | "wrapKey"; +type KeyUsage = + | "decrypt" + | "deriveBits" + | "deriveKey" + | "encrypt" + | "sign" + | "unwrapKey" + | "verify" + | "wrapKey"; type NamedCurve = string; interface HmacKeyGenParams extends Algorithm { @@ -42,7 +50,7 @@ interface RsaKeyGenParams extends Algorithm { } interface RsaPssParams extends Algorithm { - saltLength: number; + saltLength: number; } /** The CryptoKey dictionary of the Web Crypto API represents a cryptographic key. */ @@ -55,7 +63,7 @@ interface CryptoKey { declare var CryptoKey: { prototype: CryptoKey; - new(): 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. */ @@ -66,15 +74,42 @@ interface CryptoKeyPair { declare var CryptoKeyPair: { prototype: CryptoKeyPair; - new(): 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; - generateKey(algorithm: HmacKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise; - generateKey(algorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: KeyUsage[]): Promise; - sign(algorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams, key: CryptoKey, data: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer): Promise; + generateKey( + algorithm: RsaHashedKeyGenParams | EcKeyGenParams, + extractable: boolean, + keyUsages: KeyUsage[], + ): Promise; + generateKey( + algorithm: HmacKeyGenParams, + extractable: boolean, + keyUsages: KeyUsage[], + ): Promise; + generateKey( + algorithm: AlgorithmIdentifier, + extractable: boolean, + keyUsages: KeyUsage[], + ): Promise; + sign( + algorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams, + key: CryptoKey, + data: + | Int8Array + | Int16Array + | Int32Array + | Uint8Array + | Uint16Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | DataView + | ArrayBuffer, + ): Promise; } declare interface Crypto { diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 07cc4a6af9bc6a..5109f74919100e 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -307,7 +307,7 @@ pub async fn op_webcrypto_generate_key( .ok_or_else(|| WebCryptoError::MissingArgument("hash".to_string()))? .into(); let rng = RingRand::SystemRandom::new(); - + // if let Some(length) = args.algorithm.length { // let mut alg = hash.digest_algorithm(); // alg.output_len = length as usize; From 58bd0e6ff5e2e6003a4cd96c89d3b01b6d0359c2 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 4 Mar 2021 16:50:53 +0000 Subject: [PATCH 033/130] fix lint --- op_crates/crypto/lib.rs | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 5109f74919100e..76a5402a413f33 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -1,6 +1,6 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -//#![deny(warnings)] +#![deny(warnings)] use deno_core::error::bad_resource_id; use deno_core::error::AnyError; @@ -130,6 +130,7 @@ struct WebCryptoAlgorithmArg { public_exponent: Option, modulus_length: Option, hash: Option, + #[allow(dead_code)] length: Option, named_curve: Option, } @@ -281,27 +282,35 @@ pub async fn op_webcrypto_generate_key( let rng = RingRand::SystemRandom::new(); let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)?; let private_key = EcdsaKeyPair::from_pkcs8(&curve, pkcs8.as_ref())?; + // Create webcrypto keypair. let webcrypto_key_public = WebCryptoKey::new_public(algorithm, extractable, vec![]); - let crypto_key = + let webcrypto_key_private = WebCryptoKey::new_private(algorithm, extractable, vec![]); + let crypto_key = WebCryptoKeyPair::new( + webcrypto_key_public.clone(), + webcrypto_key_private.clone(), + ); - let resource = CryptoKeyResource { - crypto_key: crypto_key.clone(), + let rid = state.resource_table.add(CryptoKeyResource { + crypto_key: webcrypto_key_private, key: private_key, hash: args.algorithm.hash, - }; + }); - JSCryptoKey::Single { + JSCryptoKey::Pair { key: crypto_key, - rid: state.resource_table.add(resource), + private_rid: rid, + // NOTE: We're using the same Resource for public and private key since they are part + // of the same interface in `ring`. + public_rid: rid, } } Algorithm::Hmac => { validate_usage!(args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); - let mut hash: HmacAlgorithm = args + let hash: HmacAlgorithm = args .algorithm .hash .ok_or_else(|| WebCryptoError::MissingArgument("hash".to_string()))? @@ -361,6 +370,7 @@ pub async fn op_webcrypto_sign_key( .ok_or_else(bad_resource_id)?; let private_key = &resource.key; + validate_usage!(vec![KeyUsage::Sign], resource.crypto_key.usages); let padding = match resource .hash @@ -390,6 +400,7 @@ pub async fn op_webcrypto_sign_key( .ok_or_else(bad_resource_id)?; let private_key = &resource.key; + validate_usage!(vec![KeyUsage::Sign], resource.crypto_key.usages); let rng = OsRng; let salt_len = args.salt_length.ok_or_else(|| { @@ -423,6 +434,7 @@ pub async fn op_webcrypto_sign_key( .get::>(args.rid) .ok_or_else(bad_resource_id)?; let key_pair = &resource.key; + validate_usage!(vec![KeyUsage::Sign], resource.crypto_key.usages); // We only support P256-SHA256 & P384-SHA384. These are recommended signature pairs. // https://briansmith.org/rustdoc/ring/signature/index.html#statics @@ -446,6 +458,7 @@ pub async fn op_webcrypto_sign_key( .get::>(args.rid) .ok_or_else(bad_resource_id)?; let key = &resource.key; + validate_usage!(vec![KeyUsage::Sign], resource.crypto_key.usages); let signature = ring::hmac::sign(&key, &data); signature.as_ref().to_vec() From fca966b3eca9c736537dc8d2dd29d3359a253887 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 5 Mar 2021 06:47:03 +0000 Subject: [PATCH 034/130] start unit tests wip --- cli/tests/unit/unit_tests.ts | 1 + cli/tests/unit/webcrypto_test.ts | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 cli/tests/unit/webcrypto_test.ts diff --git a/cli/tests/unit/unit_tests.ts b/cli/tests/unit/unit_tests.ts index 2664a9ab0e3d03..ea2b78f24d7660 100644 --- a/cli/tests/unit/unit_tests.ts +++ b/cli/tests/unit/unit_tests.ts @@ -77,3 +77,4 @@ import "./performance_test.ts"; import "./version_test.ts"; import "./websocket_test.ts"; import "./webgpu_test.ts"; +import "./webcrypto_test.ts"; \ No newline at end of file diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts new file mode 100644 index 00000000000000..e41d2537acdee0 --- /dev/null +++ b/cli/tests/unit/webcrypto_test.ts @@ -0,0 +1,22 @@ +import { assert, assertEquals, unitTest } from "./test_util.ts"; + +unitTest(async function testGenerateRSAKey(): void { + const subtle = window.crypto.subtle; + assert(subtle); + + const keyPair = await subtle.generateKey( + { + name: "RSA-PSS", + modulusLength: 2048, + publicExponent: 65537, + hash: "SHA-256" + }, + true, + ["sign", "verify"] + ); + + assert(keyPair.privateKey); + assert(keyPair.publicKey); + assertEquals(keyPair.privateKey.extractable, true); + assert(keyPair.privateKey.usages.includes("sign")); +}); \ No newline at end of file From ff5b72fa5a5bfd7601d59402504a862c0c2c5549 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 5 Mar 2021 10:36:49 +0000 Subject: [PATCH 035/130] public exponent --- cli/tests/unit/unit_tests.ts | 2 +- cli/tests/unit/webcrypto_test.ts | 38 ++++++++++++++++---------------- generateKey.js | 2 +- op_crates/crypto/01_crypto.js | 12 +++++++++- op_crates/crypto/lib.rs | 23 +++++++++++-------- 5 files changed, 46 insertions(+), 31 deletions(-) diff --git a/cli/tests/unit/unit_tests.ts b/cli/tests/unit/unit_tests.ts index ea2b78f24d7660..97af65978c7a43 100644 --- a/cli/tests/unit/unit_tests.ts +++ b/cli/tests/unit/unit_tests.ts @@ -77,4 +77,4 @@ import "./performance_test.ts"; import "./version_test.ts"; import "./websocket_test.ts"; import "./webgpu_test.ts"; -import "./webcrypto_test.ts"; \ No newline at end of file +import "./webcrypto_test.ts"; diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts index e41d2537acdee0..d4b03093fb01a6 100644 --- a/cli/tests/unit/webcrypto_test.ts +++ b/cli/tests/unit/webcrypto_test.ts @@ -1,22 +1,22 @@ import { assert, assertEquals, unitTest } from "./test_util.ts"; unitTest(async function testGenerateRSAKey(): void { - const subtle = window.crypto.subtle; - assert(subtle); - - const keyPair = await subtle.generateKey( - { - name: "RSA-PSS", - modulusLength: 2048, - publicExponent: 65537, - hash: "SHA-256" - }, - true, - ["sign", "verify"] - ); - - assert(keyPair.privateKey); - assert(keyPair.publicKey); - assertEquals(keyPair.privateKey.extractable, true); - assert(keyPair.privateKey.usages.includes("sign")); -}); \ No newline at end of file + const subtle = window.crypto.subtle; + assert(subtle); + + const keyPair = await subtle.generateKey( + { + name: "RSA-PSS", + modulusLength: 2048, + publicExponent: new Uint8Array([1, 0, 1]), + hash: "SHA-256", + }, + true, + ["sign", "verify"], + ); + + assert(keyPair.privateKey); + assert(keyPair.publicKey); + assertEquals(keyPair.privateKey.extractable, true); + assert(keyPair.privateKey.usages.includes("sign")); +}); diff --git a/generateKey.js b/generateKey.js index f768a19de48e79..56e69d483b2831 100644 --- a/generateKey.js +++ b/generateKey.js @@ -2,7 +2,7 @@ const key = await window.crypto.subtle.generateKey( { name: "RSA-PSS", modulusLength: 1024, - publicExponent: 65537, + publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256", }, true, diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 8759581cf1a4eb..151c6695182d59 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -78,11 +78,21 @@ } async function generateKey(algorithm, extractable, keyUsages) { + + if(algorithm.publicExponent) { + if (!algorithm.publicExponent instanceof Uint8Array) { + throw new DOMException( + "The provided publicExponent is not an Uint8Array", + "TypeMismatchError", + ); + } + } + const { key, err } = await core.jsonOpAsync("op_webcrypto_generate_key", { algorithm, extractable, keyUsages, - }); + }, algorithm.publicExponent || null); // A DOMError. if (err) throw new Error(err); diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 76a5402a413f33..9c9e322d9b08e4 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -127,7 +127,6 @@ impl Resource for CryptoKeyResource { #[serde(rename_all = "camelCase")] struct WebCryptoAlgorithmArg { name: Algorithm, - public_exponent: Option, modulus_length: Option, hash: Option, #[allow(dead_code)] @@ -170,7 +169,7 @@ macro_rules! validate_usage { pub async fn op_webcrypto_generate_key( state: Rc>, args: Value, - _zero_copy: BufVec, + zero_copy: BufVec, ) -> Result { let args: WebCryptoGenerateKeyArg = serde_json::from_value(args)?; let extractable = args.extractable; @@ -182,14 +181,20 @@ pub async fn op_webcrypto_generate_key( Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss => { validate_usage!(args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); - let exp = args.algorithm.public_exponent.ok_or_else(|| { + let public_exponent = if zero_copy.len() > 0 { + Some(&*zero_copy[0]) + } else { + None + }; + + let exp = public_exponent.ok_or_else(|| { WebCryptoError::MissingArgument("publicExponent".to_string()) })?; let modulus_length = args.algorithm.modulus_length.ok_or_else(|| { WebCryptoError::MissingArgument("modulusLength".to_string()) })?; - let exponent = BigUint::from(exp); + let exponent = BigUint::from_bytes_be(exp); // Generate RSA private key based of exponent, bits and Rng. let mut rng = OsRng; @@ -289,7 +294,7 @@ pub async fn op_webcrypto_generate_key( let webcrypto_key_private = WebCryptoKey::new_private(algorithm, extractable, vec![]); let crypto_key = WebCryptoKeyPair::new( - webcrypto_key_public.clone(), + webcrypto_key_public, webcrypto_key_private.clone(), ); @@ -370,7 +375,7 @@ pub async fn op_webcrypto_sign_key( .ok_or_else(bad_resource_id)?; let private_key = &resource.key; - validate_usage!(vec![KeyUsage::Sign], resource.crypto_key.usages); + validate_usage!(&[KeyUsage::Sign], resource.crypto_key.usages); let padding = match resource .hash @@ -400,7 +405,7 @@ pub async fn op_webcrypto_sign_key( .ok_or_else(bad_resource_id)?; let private_key = &resource.key; - validate_usage!(vec![KeyUsage::Sign], resource.crypto_key.usages); + validate_usage!(&[KeyUsage::Sign], resource.crypto_key.usages); let rng = OsRng; let salt_len = args.salt_length.ok_or_else(|| { @@ -434,7 +439,7 @@ pub async fn op_webcrypto_sign_key( .get::>(args.rid) .ok_or_else(bad_resource_id)?; let key_pair = &resource.key; - validate_usage!(vec![KeyUsage::Sign], resource.crypto_key.usages); + validate_usage!(&[KeyUsage::Sign], resource.crypto_key.usages); // We only support P256-SHA256 & P384-SHA384. These are recommended signature pairs. // https://briansmith.org/rustdoc/ring/signature/index.html#statics @@ -458,7 +463,7 @@ pub async fn op_webcrypto_sign_key( .get::>(args.rid) .ok_or_else(bad_resource_id)?; let key = &resource.key; - validate_usage!(vec![KeyUsage::Sign], resource.crypto_key.usages); + validate_usage!(&[KeyUsage::Sign], resource.crypto_key.usages); let signature = ring::hmac::sign(&key, &data); signature.as_ref().to_vec() From be19cacfe514090c0eeb326860684e73a61fd9e0 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 5 Mar 2021 10:43:44 +0000 Subject: [PATCH 036/130] fix lint js --- op_crates/crypto/01_crypto.js | 5 ++--- op_crates/crypto/lib.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 151c6695182d59..d1d1c0a999eced 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -78,9 +78,8 @@ } async function generateKey(algorithm, extractable, keyUsages) { - - if(algorithm.publicExponent) { - if (!algorithm.publicExponent instanceof Uint8Array) { + if (algorithm.publicExponent) { + if (!(algorithm.publicExponent instanceof Uint8Array)) { throw new DOMException( "The provided publicExponent is not an Uint8Array", "TypeMismatchError", diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 9c9e322d9b08e4..ba0e292d7e5875 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -195,7 +195,7 @@ pub async fn op_webcrypto_generate_key( })?; let exponent = BigUint::from_bytes_be(exp); - + println!("{}", &exponent); // Generate RSA private key based of exponent, bits and Rng. let mut rng = OsRng; let private_key = RSAPrivateKey::new_with_exp( From a6143ceb062fcfaa2144b6344530af84d7070cb5 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 5 Mar 2021 10:48:05 +0000 Subject: [PATCH 037/130] fix(lint): use is_empty() --- op_crates/crypto/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index ba0e292d7e5875..7d9207b1497122 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -181,7 +181,7 @@ pub async fn op_webcrypto_generate_key( Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss => { validate_usage!(args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); - let public_exponent = if zero_copy.len() > 0 { + let public_exponent = if !zero_copy.is_empty() { Some(&*zero_copy[0]) } else { None From b3238d070197f90a2caa1128b49cf2d6682b5c08 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 5 Mar 2021 11:20:36 +0000 Subject: [PATCH 038/130] fix pass empty uint8array --- op_crates/crypto/01_crypto.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index d1d1c0a999eced..cbcb873b5be35c 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -91,7 +91,7 @@ algorithm, extractable, keyUsages, - }, algorithm.publicExponent || null); + }, algorithm.publicExponent || new Uint8Array()); // A DOMError. if (err) throw new Error(err); From 7a77aa42594f90e2dd769118bb510e88d4826165 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 5 Mar 2021 17:15:15 +0000 Subject: [PATCH 039/130] x --- generateKey.js | 19 ++++++----- op_crates/crypto/01_crypto.js | 7 ++-- op_crates/crypto/lib.rs | 60 ++++++++++++++++++++++++----------- 3 files changed, 55 insertions(+), 31 deletions(-) diff --git a/generateKey.js b/generateKey.js index 56e69d483b2831..ce57f70ed45e27 100644 --- a/generateKey.js +++ b/generateKey.js @@ -1,20 +1,19 @@ const key = await window.crypto.subtle.generateKey( { - name: "RSA-PSS", - modulusLength: 1024, - publicExponent: new Uint8Array([1, 0, 1]), - hash: "SHA-256", + name: "HMAC", + hash: "SHA-512" }, true, - ["sign", "verify"], + ["sign", "verify"] ); -console.log(key); + const enc = new TextEncoder(); const encoded = enc.encode("Hey"); -const signature = await window.crypto.subtle.sign( - "RSA-PSS", - key.privateKey, - encoded, + +let signature = await window.crypto.subtle.sign( + "HMAC", + key, + encoded ); console.log(signature); diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index cbcb873b5be35c..8663b88014bf3b 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -111,12 +111,15 @@ const hash = simpleParam ? null : algorithm.hash || null; algorithm = simpleParam ? algorithm : algorithm.name; - return await core.jsonOpAsync("op_webcrypto_sign_key", { + let { signature, err } = await core.jsonOpAsync("op_webcrypto_sign_key", { rid, algorithm, saltLength, hash, - }, data).data; + }, data); + + if(err) throw new DOMException(err); + return signature; } const subtle = { diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 7d9207b1497122..a95f9290c6da8b 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -179,7 +179,7 @@ pub async fn op_webcrypto_generate_key( let key = match algorithm { Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss => { - validate_usage!(args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); + validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); let public_exponent = if !zero_copy.is_empty() { Some(&*zero_copy[0]) @@ -195,7 +195,7 @@ pub async fn op_webcrypto_generate_key( })?; let exponent = BigUint::from_bytes_be(exp); - println!("{}", &exponent); + // Generate RSA private key based of exponent, bits and Rng. let mut rng = OsRng; let private_key = RSAPrivateKey::new_with_exp( @@ -207,10 +207,13 @@ pub async fn op_webcrypto_generate_key( let public_key = private_key.to_public_key(); // Create webcrypto keypair. - let webcrypto_key_public = - WebCryptoKey::new_public(algorithm, extractable, vec![]); + let webcrypto_key_public = WebCryptoKey::new_public( + algorithm, + extractable, + args.key_usages.clone(), + ); let webcrypto_key_private = - WebCryptoKey::new_private(algorithm, extractable, vec![]); + WebCryptoKey::new_private(algorithm, extractable, args.key_usages); let crypto_key = WebCryptoKeyPair::new( webcrypto_key_public.clone(), webcrypto_key_private.clone(), @@ -232,7 +235,7 @@ pub async fn op_webcrypto_generate_key( } Algorithm::Ecdh => { validate_usage!( - args.key_usages, + &args.key_usages, vec![KeyUsage::DeriveKey, KeyUsage::DeriveBits] ); @@ -250,10 +253,13 @@ pub async fn op_webcrypto_generate_key( // Extract public key. let public_key = private_key.compute_public_key()?; // Create webcrypto keypair. - let webcrypto_key_public = - WebCryptoKey::new_public(algorithm, extractable, vec![]); + let webcrypto_key_public = WebCryptoKey::new_public( + algorithm, + extractable, + args.key_usages.clone(), + ); let webcrypto_key_private = - WebCryptoKey::new_private(algorithm, extractable, vec![]); + WebCryptoKey::new_private(algorithm, extractable, args.key_usages); let crypto_key = WebCryptoKeyPair::new( webcrypto_key_public.clone(), webcrypto_key_private.clone(), @@ -274,7 +280,7 @@ pub async fn op_webcrypto_generate_key( } } Algorithm::Ecdsa => { - validate_usage!(args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); + validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); let curve: &EcdsaSigningAlgorithm = args .algorithm @@ -289,10 +295,13 @@ pub async fn op_webcrypto_generate_key( let private_key = EcdsaKeyPair::from_pkcs8(&curve, pkcs8.as_ref())?; // Create webcrypto keypair. - let webcrypto_key_public = - WebCryptoKey::new_public(algorithm, extractable, vec![]); + let webcrypto_key_public = WebCryptoKey::new_public( + algorithm, + extractable, + args.key_usages.clone(), + ); let webcrypto_key_private = - WebCryptoKey::new_private(algorithm, extractable, vec![]); + WebCryptoKey::new_private(algorithm, extractable, args.key_usages); let crypto_key = WebCryptoKeyPair::new( webcrypto_key_public, webcrypto_key_private.clone(), @@ -313,7 +322,7 @@ pub async fn op_webcrypto_generate_key( } } Algorithm::Hmac => { - validate_usage!(args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); + validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); let hash: HmacAlgorithm = args .algorithm @@ -329,7 +338,8 @@ pub async fn op_webcrypto_generate_key( // }; let key = HmacKey::generate(hash, &rng)?; - let crypto_key = WebCryptoKey::new_secret(algorithm, extractable, vec![]); + let crypto_key = + WebCryptoKey::new_secret(algorithm, extractable, args.key_usages); let resource = CryptoKeyResource { crypto_key: crypto_key.clone(), key, @@ -375,7 +385,10 @@ pub async fn op_webcrypto_sign_key( .ok_or_else(bad_resource_id)?; let private_key = &resource.key; - validate_usage!(&[KeyUsage::Sign], resource.crypto_key.usages); + + if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { + return Ok(json!({ "err": DOMError("Invalid key usage".to_string()) })); + } let padding = match resource .hash @@ -405,7 +418,10 @@ pub async fn op_webcrypto_sign_key( .ok_or_else(bad_resource_id)?; let private_key = &resource.key; - validate_usage!(&[KeyUsage::Sign], resource.crypto_key.usages); + + if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { + return Ok(json!({ "err": DOMError("Invalid key usage".to_string()) })); + } let rng = OsRng; let salt_len = args.salt_length.ok_or_else(|| { @@ -439,7 +455,10 @@ pub async fn op_webcrypto_sign_key( .get::>(args.rid) .ok_or_else(bad_resource_id)?; let key_pair = &resource.key; - validate_usage!(&[KeyUsage::Sign], resource.crypto_key.usages); + + if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { + return Ok(json!({ "err": DOMError("Invalid key usage".to_string()) })); + } // We only support P256-SHA256 & P384-SHA384. These are recommended signature pairs. // https://briansmith.org/rustdoc/ring/signature/index.html#statics @@ -463,7 +482,10 @@ pub async fn op_webcrypto_sign_key( .get::>(args.rid) .ok_or_else(bad_resource_id)?; let key = &resource.key; - validate_usage!(&[KeyUsage::Sign], resource.crypto_key.usages); + + if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { + return Ok(json!({ "err": DOMError("Invalid key usage".to_string()) })); + } let signature = ring::hmac::sign(&key, &data); signature.as_ref().to_vec() From 0fa956bb899c87525e610a25e1c6e46ab0067f5b Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 6 Mar 2021 15:24:09 +0000 Subject: [PATCH 040/130] add tests --- cli/tests/unit/webcrypto_test.ts | 38 +++++++++++++++++++++++++++++++- generateKey.js | 19 ---------------- op_crates/crypto/01_crypto.js | 6 ++--- op_crates/crypto/lib.rs | 24 +++++++++++++------- webcrypto_example.ts | 18 +++++++++++++++ 5 files changed, 74 insertions(+), 31 deletions(-) delete mode 100644 generateKey.js create mode 100644 webcrypto_example.ts diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts index d4b03093fb01a6..bf60d4d3a5dcd8 100644 --- a/cli/tests/unit/webcrypto_test.ts +++ b/cli/tests/unit/webcrypto_test.ts @@ -1,6 +1,6 @@ import { assert, assertEquals, unitTest } from "./test_util.ts"; -unitTest(async function testGenerateRSAKey(): void { +unitTest(async function testGenerateRSAKey() { const subtle = window.crypto.subtle; assert(subtle); @@ -20,3 +20,39 @@ unitTest(async function testGenerateRSAKey(): void { assertEquals(keyPair.privateKey.extractable, true); assert(keyPair.privateKey.usages.includes("sign")); }); + +unitTest(async function testGenerateHMACKey() { + const key = await window.crypto.subtle.generateKey( + { + name: "HMAC", + hash: { name: "SHA-512" }, + }, + true, + ["sign", "verify"], + ); + + assert(key); + assertEquals(key.extractable, true); + assert(key.usages.includes("sign")); +}); + +unitTest(async function testSignECDSA() { + const key = await window.crypto.subtle.generateKey( + { + name: "ECDSA", + namedCurve: "P-384", + }, + true, + ["sign", "verify"], + ); + + const encoder = new TextEncoder(); + const encoded = encoder.encode("Hello, World!"); + const signature = await window.crypto.subtle.sign( + { name: "ECDSA", hash: "SHA-384" }, + key.privateKey, + encoded, + ); + + assert(signature); +}); diff --git a/generateKey.js b/generateKey.js deleted file mode 100644 index ce57f70ed45e27..00000000000000 --- a/generateKey.js +++ /dev/null @@ -1,19 +0,0 @@ -const key = await window.crypto.subtle.generateKey( - { - name: "HMAC", - hash: "SHA-512" - }, - true, - ["sign", "verify"] -); - -const enc = new TextEncoder(); -const encoded = enc.encode("Hey"); - -let signature = await window.crypto.subtle.sign( - "HMAC", - key, - encoded -); - -console.log(signature); diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 8663b88014bf3b..a0cd54986718e1 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -111,15 +111,15 @@ const hash = simpleParam ? null : algorithm.hash || null; algorithm = simpleParam ? algorithm : algorithm.name; - let { signature, err } = await core.jsonOpAsync("op_webcrypto_sign_key", { + const { signature, err } = await core.jsonOpAsync("op_webcrypto_sign_key", { rid, algorithm, saltLength, hash, }, data); - if(err) throw new DOMException(err); - return signature; + if (err) throw new DOMException(err); + return new Uint8Array(signature); } const subtle = { diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index a95f9290c6da8b..db72b4cd4038aa 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -36,7 +36,7 @@ use rsa::BigUint; use rsa::RSAPrivateKey; use rsa::RSAPublicKey; use sha1::Sha1; -use sha2::{Sha256, Sha384, Sha512}; +use sha2::{Sha256, Sha384, Sha512, Digest}; use std::path::PathBuf; pub use rand; // Re-export rand @@ -428,26 +428,34 @@ pub async fn op_webcrypto_sign_key( WebCryptoError::MissingArgument("saltLength".to_string()) })? as usize; - let padding = match resource + let (padding, digest_in) = match resource .hash .ok_or_else(|| WebCryptoError::MissingArgument("hash".to_string()))? { WebCryptoHash::Sha1 => { - PaddingScheme::new_pss_with_salt::(rng, salt_len) + let mut hasher = Sha1::new(); + hasher.update(&data); + (PaddingScheme::new_pss_with_salt::(rng, salt_len), hasher.finalize()[..].to_vec()) } WebCryptoHash::Sha256 => { - PaddingScheme::new_pss_with_salt::(rng, salt_len) + let mut hasher = Sha256::new(); + hasher.update(&data); + (PaddingScheme::new_pss_with_salt::(rng, salt_len), hasher.finalize()[..].to_vec()) } WebCryptoHash::Sha384 => { - PaddingScheme::new_pss_with_salt::(rng, salt_len) + let mut hasher = Sha384::new(); + hasher.update(&data); + (PaddingScheme::new_pss_with_salt::(rng, salt_len), hasher.finalize()[..].to_vec()) } WebCryptoHash::Sha512 => { - PaddingScheme::new_pss_with_salt::(rng, salt_len) + let mut hasher = Sha512::new(); + hasher.update(&data); + (PaddingScheme::new_pss_with_salt::(rng, salt_len), hasher.finalize()[..].to_vec()) } }; // Sign data based on computed padding and return buffer - private_key.sign(padding, &data)? + private_key.sign(padding, &digest_in)? } Algorithm::Ecdsa => { let resource = state @@ -493,7 +501,7 @@ pub async fn op_webcrypto_sign_key( _ => return Err(WebCryptoError::Unsupported.into()), }; - Ok(json!({ "data": signature })) + Ok(json!({ "signature": signature })) } pub fn get_declaration() -> PathBuf { diff --git a/webcrypto_example.ts b/webcrypto_example.ts new file mode 100644 index 00000000000000..c132572bf47985 --- /dev/null +++ b/webcrypto_example.ts @@ -0,0 +1,18 @@ +const key = await window.crypto.subtle.generateKey( + { + name: "ECDSA", + namedCurve: "P-384", + }, + true, + ["sign", "verify"], +); + +const enc = new TextEncoder(); +const encoded = enc.encode("Hey"); +const signature = await window.crypto.subtle.sign( + { name: "ECDSA", hash: "SHA-384" }, + key.privateKey, + encoded, +); + +console.log(signature); From 756583f3b525f30b1b2c1d53793aeced4ae114ac Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 6 Mar 2021 15:27:45 +0000 Subject: [PATCH 041/130] how on earth did i forget cargo fmt --- op_crates/crypto/lib.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index db72b4cd4038aa..a26d925919e79d 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -36,7 +36,7 @@ use rsa::BigUint; use rsa::RSAPrivateKey; use rsa::RSAPublicKey; use sha1::Sha1; -use sha2::{Sha256, Sha384, Sha512, Digest}; +use sha2::{Digest, Sha256, Sha384, Sha512}; use std::path::PathBuf; pub use rand; // Re-export rand @@ -435,22 +435,34 @@ pub async fn op_webcrypto_sign_key( WebCryptoHash::Sha1 => { let mut hasher = Sha1::new(); hasher.update(&data); - (PaddingScheme::new_pss_with_salt::(rng, salt_len), hasher.finalize()[..].to_vec()) + ( + PaddingScheme::new_pss_with_salt::(rng, salt_len), + hasher.finalize()[..].to_vec(), + ) } WebCryptoHash::Sha256 => { let mut hasher = Sha256::new(); hasher.update(&data); - (PaddingScheme::new_pss_with_salt::(rng, salt_len), hasher.finalize()[..].to_vec()) + ( + PaddingScheme::new_pss_with_salt::(rng, salt_len), + hasher.finalize()[..].to_vec(), + ) } WebCryptoHash::Sha384 => { let mut hasher = Sha384::new(); hasher.update(&data); - (PaddingScheme::new_pss_with_salt::(rng, salt_len), hasher.finalize()[..].to_vec()) + ( + PaddingScheme::new_pss_with_salt::(rng, salt_len), + hasher.finalize()[..].to_vec(), + ) } WebCryptoHash::Sha512 => { let mut hasher = Sha512::new(); hasher.update(&data); - (PaddingScheme::new_pss_with_salt::(rng, salt_len), hasher.finalize()[..].to_vec()) + ( + PaddingScheme::new_pss_with_salt::(rng, salt_len), + hasher.finalize()[..].to_vec(), + ) } }; From fda1c6bc3c120c47e27a057c01238bd7559da7d4 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 7 Mar 2021 09:24:05 +0000 Subject: [PATCH 042/130] spawn blocking for key generation --- Cargo.lock | 1 + op_crates/crypto/Cargo.toml | 3 +-- op_crates/crypto/lib.rs | 49 +++++++++++++++++++++++++++++-------- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 27d25a407a0fac..31de4207784418 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -589,6 +589,7 @@ dependencies = [ "serde", "sha-1", "sha2", + "tokio", ] [[package]] diff --git a/op_crates/crypto/Cargo.toml b/op_crates/crypto/Cargo.toml index eae876cc12e2b6..8c20bc3f63994f 100644 --- a/op_crates/crypto/Cargo.toml +++ b/op_crates/crypto/Cargo.toml @@ -21,5 +21,4 @@ rsa = { git = "https://github.com/RustCrypto/RSA", rev = "616b08d" } sha-1 = "0.9.4" sha2 = "0.9.3" serde = { version = "1.0.123", features = ["derive"] } - - +tokio = { version = "1.2.0", features = ["full"] } diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index a26d925919e79d..d49906766a77ce 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -176,7 +176,6 @@ pub async fn op_webcrypto_generate_key( let algorithm = args.algorithm.name; let mut state = state.borrow_mut(); - let key = match algorithm { Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss => { validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); @@ -198,11 +197,19 @@ pub async fn op_webcrypto_generate_key( // Generate RSA private key based of exponent, bits and Rng. let mut rng = OsRng; - let private_key = RSAPrivateKey::new_with_exp( - &mut rng, - modulus_length as usize, - &exponent, - )?; + + let private_key: RSAPrivateKey = tokio::task::spawn_blocking( + move || -> Result { + Ok(RSAPrivateKey::new_with_exp( + &mut rng, + modulus_length as usize, + &exponent, + )?) + }, + ) + .await + .unwrap()?; + // Extract public key from private key. let public_key = private_key.to_public_key(); @@ -249,7 +256,16 @@ pub async fn op_webcrypto_generate_key( .try_into()?; // Generate private key from agreement and ring rng. let rng = RingRand::SystemRandom::new(); - let private_key = EphemeralPrivateKey::generate(&agreement, &rng)?; + + let private_key: EphemeralPrivateKey = tokio::task::spawn_blocking( + move || -> Result { + let pk = EphemeralPrivateKey::generate(&agreement, &rng)?; + Ok(pk) + }, + ) + .await + .unwrap()?; + // Extract public key. let public_key = private_key.compute_public_key()?; // Create webcrypto keypair. @@ -291,8 +307,14 @@ pub async fn op_webcrypto_generate_key( .try_into()?; let rng = RingRand::SystemRandom::new(); - let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)?; - let private_key = EcdsaKeyPair::from_pkcs8(&curve, pkcs8.as_ref())?; + let private_key: EcdsaKeyPair = tokio::task::spawn_blocking( + move || -> Result { + let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)?; + Ok(EcdsaKeyPair::from_pkcs8(&curve, pkcs8.as_ref())?) + }, + ) + .await + .unwrap()?; // Create webcrypto keypair. let webcrypto_key_public = WebCryptoKey::new_public( @@ -337,7 +359,14 @@ pub async fn op_webcrypto_generate_key( // alg.chaining_len = length as usize; // }; - let key = HmacKey::generate(hash, &rng)?; + let key: HmacKey = tokio::task::spawn_blocking( + move || -> Result { + Ok(HmacKey::generate(hash, &rng)?) + }, + ) + .await + .unwrap()?; + let crypto_key = WebCryptoKey::new_secret(algorithm, extractable, args.key_usages); let resource = CryptoKeyResource { From 85d20d55ce389c2063cffad860e7834974e92af6 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 7 Mar 2021 10:24:53 +0000 Subject: [PATCH 043/130] use macro to auto impl resource --- op_crates/crypto/lib.rs | 46 ++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index d49906766a77ce..49d2be9c76aa89 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -87,40 +87,24 @@ struct CryptoKeyResource { hash: Option, } -impl Resource for CryptoKeyResource { - fn name(&self) -> Cow { - "RSAPublicCryptoKey".into() - } -} - -impl Resource for CryptoKeyResource { - fn name(&self) -> Cow { - "RSAPrivateCryptoKey".into() - } -} - -impl Resource for CryptoKeyResource { - fn name(&self) -> Cow { - "ECDSACryptoKey".into() - } -} - -impl Resource for CryptoKeyResource { - fn name(&self) -> Cow { - "ECDHPublicKey".into() - } -} - -impl Resource for CryptoKeyResource { - fn name(&self) -> Cow { - "ECDHPrivateKey".into() +// `impl_resource` will use the type name as the resource name. +macro_rules! impl_resource { + ($($t:ty),+) => { + $(impl Resource for CryptoKeyResource<$t> { + fn name(&self) -> Cow { + stringify!($t).into() + } + })* } } -impl Resource for CryptoKeyResource { - fn name(&self) -> Cow { - "HMACKey".into() - } +impl_resource! { + RSAPublicKey, + RSAPrivateKey, + EcdsaKeyPair, + ring::agreement::PublicKey, + EphemeralPrivateKey, + HmacKey } #[derive(Deserialize)] From 2847fba3a13574048bba78916bfeef1b86d7347f Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 7 Mar 2021 13:16:10 +0000 Subject: [PATCH 044/130] x --- op_crates/crypto/01_crypto.js | 1 - 1 file changed, 1 deletion(-) diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index a0cd54986718e1..c7842e7866ab6c 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -134,7 +134,6 @@ window.__bootstrap = window.__bootstrap || {}; window.__bootstrap.crypto = { getRandomValues, - generateKey, subtle, }; })(this); From d7f076aa49677a312a348c5070f712a9c77ca854 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 7 Mar 2021 13:22:52 +0000 Subject: [PATCH 045/130] fix use Uint8Array type for publicModulus --- op_crates/crypto/lib.deno_crypto.d.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/op_crates/crypto/lib.deno_crypto.d.ts b/op_crates/crypto/lib.deno_crypto.d.ts index ce2bc87924ca0b..158619fce1a45e 100644 --- a/op_crates/crypto/lib.deno_crypto.d.ts +++ b/op_crates/crypto/lib.deno_crypto.d.ts @@ -25,6 +25,7 @@ type KeyUsage = | "unwrapKey" | "verify" | "wrapKey"; + type NamedCurve = string; interface HmacKeyGenParams extends Algorithm { @@ -46,7 +47,7 @@ interface RsaHashedKeyGenParams extends RsaKeyGenParams { interface RsaKeyGenParams extends Algorithm { modulusLength: number; - publicExponent: number; + publicExponent: Uint8Array; } interface RsaPssParams extends Algorithm { From 25b60d132b6fa88393cb81c1f67beb55218039a1 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 7 Mar 2021 13:56:03 +0000 Subject: [PATCH 046/130] nice little readme --- op_crates/crypto/README.md | 19 ++++++++++++++++++- op_crates/crypto/error.rs | 2 ++ op_crates/crypto/key.rs | 2 ++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/op_crates/crypto/README.md b/op_crates/crypto/README.md index 0e1c248e64ce46..4213aba597a3a7 100644 --- a/op_crates/crypto/README.md +++ b/op_crates/crypto/README.md @@ -1,3 +1,20 @@ # deno crypto -Op crate that implements crypto functions. +Op crate that implements the WebCrypto API functions. + +## Supported algorithms + +SubtleCrypto for Deno is in it's early stages; below is the supported algorithms +and functions. + +| Algorithm name | generateKey | sign | +| --------------------------------------------------------------------- | ------------------ | ------------------ | +| [RSASSA-PKCS1-v1_5](https://www.w3.org/TR/WebCryptoAPI/#rsassa-pkcs1) | :white_check_mark: | :white_check_mark: | +| [RSA-PSS](https://www.w3.org/TR/WebCryptoAPI/#rsa-pss) | :white_check_mark: | :white_check_mark: | +| [RSA-OAEP](https://www.w3.org/TR/WebCryptoAPI/#rsa-oaep) | :white_check_mark: | | +| [ECDSA](https://www.w3.org/TR/WebCryptoAPI/#ecdsa) | :white_check_mark: | :white_check_mark: | +| [ECDH](https://www.w3.org/TR/WebCryptoAPI/#ecdh) | :white_check_mark: | | +| [HMAC](https://www.w3.org/TR/WebCryptoAPI/#hmac) | :white_check_mark: | :white_check_mark: | + +All WebCrypto algorithms can be found +[here](https://www.w3.org/TR/WebCryptoAPI/#algorithm-overview). diff --git a/op_crates/crypto/error.rs b/op_crates/crypto/error.rs index 717158d03ace32..f281a18fd4cf72 100644 --- a/op_crates/crypto/error.rs +++ b/op_crates/crypto/error.rs @@ -1,3 +1,5 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + use serde::Serialize; use std::fmt; diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index 16baeca417afd7..1b46a9437fb1e7 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -1,3 +1,5 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + use crate::error::WebCryptoError; use ring::agreement::Algorithm as RingAlgorithm; use ring::hmac::Algorithm as HmacAlgorithm; From 327b3bf2be9e335312873c47c6fdbb603d2ee3ff Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 8 Mar 2021 14:15:40 +0000 Subject: [PATCH 047/130] fix(tests): close crypto key resources --- cli/tests/unit/webcrypto_test.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts index bf60d4d3a5dcd8..3316cb97aa654a 100644 --- a/cli/tests/unit/webcrypto_test.ts +++ b/cli/tests/unit/webcrypto_test.ts @@ -1,5 +1,23 @@ import { assert, assertEquals, unitTest } from "./test_util.ts"; +// Close all crypto key resources to avoid resource leaks. +function closeResource() { + const resources = Deno.resources(); + const rids = Object.keys(resources).map((k) => { + if ( + ["RSAPublicKey", "RSAPrivateKey", "EcdsaKeyPair", "HmacKey"].includes( + resources[k], + ) + ) { + return Number(k); + } + }); + + for (let rid in rids) { + Deno.close(rids[rid]); + } +} + unitTest(async function testGenerateRSAKey() { const subtle = window.crypto.subtle; assert(subtle); @@ -19,13 +37,14 @@ unitTest(async function testGenerateRSAKey() { assert(keyPair.publicKey); assertEquals(keyPair.privateKey.extractable, true); assert(keyPair.privateKey.usages.includes("sign")); + closeResource(); }); unitTest(async function testGenerateHMACKey() { const key = await window.crypto.subtle.generateKey( { name: "HMAC", - hash: { name: "SHA-512" }, + hash: "SHA-512", }, true, ["sign", "verify"], @@ -34,6 +53,7 @@ unitTest(async function testGenerateHMACKey() { assert(key); assertEquals(key.extractable, true); assert(key.usages.includes("sign")); + closeResource(); }); unitTest(async function testSignECDSA() { @@ -55,4 +75,5 @@ unitTest(async function testSignECDSA() { ); assert(signature); + closeResource(); }); From 3cfccad13ca08d671fc501386ddf8b220686af33 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 8 Mar 2021 14:27:43 +0000 Subject: [PATCH 048/130] normalize hash.name --- op_crates/crypto/01_crypto.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index c7842e7866ab6c..001ec1591479a5 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -87,6 +87,11 @@ } } + // Normalizes { hash: { name: "SHA-256" } } to { hash: "SHA-256" } + algorithm.hash = typeof algorithm.hash == "string" + ? algorithm.hash + : algorithm.hash.name; + const { key, err } = await core.jsonOpAsync("op_webcrypto_generate_key", { algorithm, extractable, From 6d07749ceab8a5ce02d2192fef5195b4ebd7fb82 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 8 Mar 2021 15:13:27 +0000 Subject: [PATCH 049/130] x --- cli/tests/unit/webcrypto_test.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts index 3316cb97aa654a..e8ab794728b932 100644 --- a/cli/tests/unit/webcrypto_test.ts +++ b/cli/tests/unit/webcrypto_test.ts @@ -3,18 +3,16 @@ import { assert, assertEquals, unitTest } from "./test_util.ts"; // Close all crypto key resources to avoid resource leaks. function closeResource() { const resources = Deno.resources(); - const rids = Object.keys(resources).map((k) => { + + for (const i of Object.keys(resources)) { + const rid = Number(i); if ( ["RSAPublicKey", "RSAPrivateKey", "EcdsaKeyPair", "HmacKey"].includes( - resources[k], + resources[i], ) ) { - return Number(k); + Deno.close(rid); } - }); - - for (let rid in rids) { - Deno.close(rids[rid]); } } From 0feb8f2c3d40f0238aae556be1ea6c3f7956ff7f Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 27 Mar 2021 15:24:35 +0000 Subject: [PATCH 050/130] merge --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8793ada17ca44d..12f15772f6cd7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -584,7 +584,7 @@ name = "deno_crypto" version = "0.16.0" dependencies = [ "deno_core", - "rand 0.7.3", + "rand 0.8.3", "ring", "rsa", "serde", @@ -1994,9 +1994,9 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d51546d704f52ef14b3c962b5776e53d5b862e5790e40a350d366c209bd7f7a" +checksum = "4547ee5541c18742396ae2c895d0717d0f886d8823b8399cdaf7b07d63ad0480" dependencies = [ "autocfg 0.1.7", "byteorder", @@ -2005,7 +2005,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.7.3", + "rand 0.8.3", "smallvec", "zeroize", ] @@ -2632,7 +2632,7 @@ dependencies = [ [[package]] name = "rsa" version = "0.3.0" -source = "git+https://github.com/RustCrypto/RSA?rev=616b08d#616b08d94bbb03c8fdb1a57188c38701faf6877b" +source = "git+https://github.com/littledivy/RSA?rev=5d3a76c#5d3a76c429a19658cf78280539a25e5b12eda200" dependencies = [ "byteorder", "digest", @@ -2642,7 +2642,7 @@ dependencies = [ "num-iter", "num-traits", "pem", - "rand 0.7.3", + "rand 0.8.3", "simple_asn1", "subtle", "zeroize", From c50e411f115ac2d31b4ad7d2b9a44e984b39e52e Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 27 Mar 2021 15:46:35 +0000 Subject: [PATCH 051/130] fix fmt --- op_crates/crypto/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/op_crates/crypto/README.md b/op_crates/crypto/README.md index 7b423c8f1619b6..26fa7106ddfb02 100644 --- a/op_crates/crypto/README.md +++ b/op_crates/crypto/README.md @@ -20,4 +20,3 @@ and functions. All WebCrypto algorithms can be found [here](https://www.w3.org/TR/WebCryptoAPI/#algorithm-overview). - From af2e3ce85f5dad29c2896fad4210df0db46a242c Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 27 Mar 2021 15:57:12 +0000 Subject: [PATCH 052/130] fix clippy just got new lint rules --- op_crates/crypto/error.rs | 6 +++--- op_crates/crypto/lib.rs | 22 +++++++++++----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/op_crates/crypto/error.rs b/op_crates/crypto/error.rs index f281a18fd4cf72..1e058a1abac2b8 100644 --- a/op_crates/crypto/error.rs +++ b/op_crates/crypto/error.rs @@ -25,12 +25,12 @@ impl fmt::Display for WebCryptoError { impl std::error::Error for WebCryptoError {} #[derive(Debug, Serialize)] -pub struct DOMError(pub String); +pub struct DomError(pub String); -impl fmt::Display for DOMError { +impl fmt::Display for DomError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &self.0) } } -impl std::error::Error for DOMError {} +impl std::error::Error for DomError {} diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 49d2be9c76aa89..8a16b56c0c1ba7 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -44,7 +44,7 @@ pub use rand; // Re-export rand mod error; mod key; -use crate::error::DOMError; +use crate::error::DomError; use crate::error::WebCryptoError; use crate::key::Algorithm; use crate::key::KeyUsage; @@ -128,7 +128,7 @@ struct WebCryptoGenerateKeyArg { #[derive(Serialize)] #[serde(rename_all = "camelCase")] -enum JSCryptoKey { +enum JsCryptoKey { Single { key: WebCryptoKey, rid: u32, @@ -144,7 +144,7 @@ macro_rules! validate_usage { ($e: expr, $u: expr) => { for usage in $e { if !$u.contains(&usage) { - return Ok(json!({ "err": DOMError("Invalid key usage".to_string()) })) + return Ok(json!({ "err": DomError("Invalid key usage".to_string()) })) } } } @@ -210,7 +210,7 @@ pub async fn op_webcrypto_generate_key( webcrypto_key_private.clone(), ); - JSCryptoKey::Pair { + JsCryptoKey::Pair { key: crypto_key, private_rid: state.resource_table.add(CryptoKeyResource { crypto_key: webcrypto_key_private, @@ -265,7 +265,7 @@ pub async fn op_webcrypto_generate_key( webcrypto_key_private.clone(), ); - JSCryptoKey::Pair { + JsCryptoKey::Pair { key: crypto_key, private_rid: state.resource_table.add(CryptoKeyResource { crypto_key: webcrypto_key_private, @@ -319,7 +319,7 @@ pub async fn op_webcrypto_generate_key( hash: args.algorithm.hash, }); - JSCryptoKey::Pair { + JsCryptoKey::Pair { key: crypto_key, private_rid: rid, // NOTE: We're using the same Resource for public and private key since they are part @@ -358,7 +358,7 @@ pub async fn op_webcrypto_generate_key( key, hash: args.algorithm.hash, }; - JSCryptoKey::Single { + JsCryptoKey::Single { key: crypto_key, rid: state.resource_table.add(resource), } @@ -400,7 +400,7 @@ pub async fn op_webcrypto_sign_key( let private_key = &resource.key; if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { - return Ok(json!({ "err": DOMError("Invalid key usage".to_string()) })); + return Ok(json!({ "err": DomError("Invalid key usage".to_string()) })); } let padding = match resource @@ -433,7 +433,7 @@ pub async fn op_webcrypto_sign_key( let private_key = &resource.key; if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { - return Ok(json!({ "err": DOMError("Invalid key usage".to_string()) })); + return Ok(json!({ "err": DomError("Invalid key usage".to_string()) })); } let rng = OsRng; @@ -490,7 +490,7 @@ pub async fn op_webcrypto_sign_key( let key_pair = &resource.key; if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { - return Ok(json!({ "err": DOMError("Invalid key usage".to_string()) })); + return Ok(json!({ "err": DomError("Invalid key usage".to_string()) })); } // We only support P256-SHA256 & P384-SHA384. These are recommended signature pairs. @@ -517,7 +517,7 @@ pub async fn op_webcrypto_sign_key( let key = &resource.key; if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { - return Ok(json!({ "err": DOMError("Invalid key usage".to_string()) })); + return Ok(json!({ "err": DomError("Invalid key usage".to_string()) })); } let signature = ring::hmac::sign(&key, &data); From 108ef5958aec4f992bba1e07c41ae29d85f4cccc Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 27 Mar 2021 16:28:57 +0000 Subject: [PATCH 053/130] fix more lints --- op_crates/crypto/key.rs | 6 +++--- op_crates/crypto/lib.rs | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index 1b46a9437fb1e7..9e77df217246a0 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -66,9 +66,9 @@ impl TryInto<&EcdsaSigningAlgorithm> for WebCryptoNamedCurve { } } -impl Into for WebCryptoHash { - fn into(self) -> HmacAlgorithm { - match self { +impl From for HmacAlgorithm { + fn from(hash: WebCryptoHash) -> HmacAlgorithm { + match hash { WebCryptoHash::Sha1 => ring::hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, WebCryptoHash::Sha256 => ring::hmac::HMAC_SHA256, WebCryptoHash::Sha384 => ring::hmac::HMAC_SHA384, diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 8a16b56c0c1ba7..0b56a8f777c5bb 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -184,11 +184,11 @@ pub async fn op_webcrypto_generate_key( let private_key: RSAPrivateKey = tokio::task::spawn_blocking( move || -> Result { - Ok(RSAPrivateKey::new_with_exp( + RSAPrivateKey::new_with_exp( &mut rng, modulus_length as usize, &exponent, - )?) + ) }, ) .await @@ -243,8 +243,7 @@ pub async fn op_webcrypto_generate_key( let private_key: EphemeralPrivateKey = tokio::task::spawn_blocking( move || -> Result { - let pk = EphemeralPrivateKey::generate(&agreement, &rng)?; - Ok(pk) + EphemeralPrivateKey::generate(&agreement, &rng) }, ) .await @@ -345,7 +344,7 @@ pub async fn op_webcrypto_generate_key( let key: HmacKey = tokio::task::spawn_blocking( move || -> Result { - Ok(HmacKey::generate(hash, &rng)?) + HmacKey::generate(hash, &rng) }, ) .await From 8315c481cc2173114ad08651396594c8297f3a43 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 28 Mar 2021 07:27:45 +0000 Subject: [PATCH 054/130] fix hash name normalisation --- cli/tests/unit/webcrypto_test.ts | 2 +- op_crates/crypto/01_crypto.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts index e8ab794728b932..8ee9b29aeef1a2 100644 --- a/cli/tests/unit/webcrypto_test.ts +++ b/cli/tests/unit/webcrypto_test.ts @@ -8,7 +8,7 @@ function closeResource() { const rid = Number(i); if ( ["RSAPublicKey", "RSAPrivateKey", "EcdsaKeyPair", "HmacKey"].includes( - resources[i], + resources[rid], ) ) { Deno.close(rid); diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 001ec1591479a5..f29fa151e5d90b 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -88,9 +88,9 @@ } // Normalizes { hash: { name: "SHA-256" } } to { hash: "SHA-256" } - algorithm.hash = typeof algorithm.hash == "string" - ? algorithm.hash - : algorithm.hash.name; + if(algorithm.hash && typeof algorithm.hash !== "string") { + algorithm.hash = algorithm.hash.name; + } const { key, err } = await core.jsonOpAsync("op_webcrypto_generate_key", { algorithm, From 4927c1cca4f523f6ac60dc89fcf3f18ee1e6bc91 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 28 Mar 2021 07:34:12 +0000 Subject: [PATCH 055/130] fmt --- op_crates/crypto/01_crypto.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index f29fa151e5d90b..e4cb16e1976f41 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -88,7 +88,7 @@ } // Normalizes { hash: { name: "SHA-256" } } to { hash: "SHA-256" } - if(algorithm.hash && typeof algorithm.hash !== "string") { + if (algorithm.hash && typeof algorithm.hash !== "string") { algorithm.hash = algorithm.hash.name; } From 79a973468f17fa479b93bdb20215c65af6d69b05 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 29 Mar 2021 08:11:39 +0530 Subject: [PATCH 056/130] RSA 0.8.0 --- op_crates/crypto/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/op_crates/crypto/Cargo.toml b/op_crates/crypto/Cargo.toml index 3ef3b18166f318..ae0e25bf80ae4b 100644 --- a/op_crates/crypto/Cargo.toml +++ b/op_crates/crypto/Cargo.toml @@ -17,7 +17,7 @@ path = "lib.rs" deno_core = { version = "0.82.0", path = "../../core" } rand = "0.8.3" ring = { version = "0.16.20", features = ["std"] } -rsa = { git = "https://github.com/littledivy/RSA", rev = "5d3a76c" } +rsa = "0.4.0" sha-1 = "0.9.4" sha2 = "0.9.3" serde = { version = "1.0.123", features = ["derive"] } From c7109795587526452e4f3108f1137b6ed1ce2872 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 29 Mar 2021 07:29:37 +0000 Subject: [PATCH 057/130] fix cargo lock --- Cargo.lock | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12f15772f6cd7e..afa71ee3768651 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2631,8 +2631,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.3.0" -source = "git+https://github.com/littledivy/RSA?rev=5d3a76c#5d3a76c429a19658cf78280539a25e5b12eda200" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ef841a26fc5d040ced0417c6c6a64ee851f42489df11cdf0218e545b6f8d28" dependencies = [ "byteorder", "digest", From 83a754b53e3dd0365f5d6805c32ed2a9fcf1ceb1 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 30 Mar 2021 09:03:57 +0000 Subject: [PATCH 058/130] generateKey WPT --- op_crates/crypto/01_crypto.js | 92 ++++++++++++++++++++++++++++++----- op_crates/crypto/key.rs | 22 ++++----- runtime/js/99_main.js | 1 + tools/wpt/expectation.json | 14 +++++- 4 files changed, 105 insertions(+), 24 deletions(-) diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index e4cb16e1976f41..18bc7cd6555816 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -53,9 +53,19 @@ #keyType; constructor(key, rid) { - this.#usages = key.usages; + this.#usages = key.keyUsages; this.#extractable = key.extractable; - this.#algorithm = key.algorithm; + let algorithm = key.algorithm; + algorithm.name = algorithm.name?.toUpperCase(); + if (algorithm.name.startsWith("RSASSA-PKCS1")) { + // As per spec, `v` cannot be upper case. + algorithm.name = "RSASSA-PKCS1-v1_5"; + } + let hash = algorithm.hash; + if (typeof hash == "string") { + hash = { name: hash }; + } + this.#algorithm = { ...algorithm, hash }; this.#keyType = key.keyType; this[ridSymbol] = rid; } @@ -72,12 +82,13 @@ return this.#algorithm; } - get keyType() { + get type() { return this.#keyType; } } - async function generateKey(algorithm, extractable, keyUsages) { + // Normalize an algorithm object. makes it less painful to serialize. + function normalize(algorithm) { if (algorithm.publicExponent) { if (!(algorithm.publicExponent instanceof Uint8Array)) { throw new DOMException( @@ -87,24 +98,79 @@ } } + const hash = algorithm.hash; // Normalizes { hash: { name: "SHA-256" } } to { hash: "SHA-256" } - if (algorithm.hash && typeof algorithm.hash !== "string") { - algorithm.hash = algorithm.hash.name; + if (hash && typeof hash !== "string") { + hash = hash.name; + } + // Algorithm names are not case-sensitive. We use lowercase for internal serialization. + const name = algorithm.name.toLowerCase(); + return { ...algorithm, name, hash }; + } + + function validateUsages(usages, keyType) { + let validUsages = []; + if (keyType == "public") { + ["encrypt", "verify", "wrapKey"].forEach((usage) => { + if (usages.includes(usage)) { + validUsages.push(usage); + } + }); + } else if (keyType == "private") { + ["decrypt", "sign", "unwrapKey", "deriveKey", "deriveBits"].forEach( + (usage) => { + if (usages.includes(usage)) { + validUsages.push(usage); + } + }, + ); + } /* secret */ else { + validUsages = usages; } + return validUsages; + } + + async function generateKey(algorithm, extractable, keyUsages) { + let normalizedAlgorithm = normalize(algorithm); + const { key, err } = await core.jsonOpAsync("op_webcrypto_generate_key", { - algorithm, + algorithm: normalizedAlgorithm, extractable, keyUsages, - }, algorithm.publicExponent || new Uint8Array()); + }, normalizedAlgorithm.publicExponent || new Uint8Array()); // A DOMError. if (err) throw new Error(err); - return key.single ? new CryptoKey(key.single.key, key.single.rid) : { - privateKey: new CryptoKey(key.pair.key.privateKey, key.pair.private_rid), - publicKey: new CryptoKey(key.pair.key.publicKey, key.pair.public_rid), - }; + if (key.single) { + const { keyType } = key.single.key; + const usages = validateUsages(keyUsages, keyType); + return new CryptoKey( + { keyType, algorithm, extractable, keyUsages: usages }, + key.single.rid, + ); + } /* CryptoKeyPair */ else { + const privateKeyType = key.pair.key.privateKey.keyType; + const privateKeyUsages = validateUsages(keyUsages, privateKeyType); + + const publicKeyType = key.pair.key.publicKey.keyType; + const publicKeyUsages = validateUsages(keyUsages, publicKeyType); + return { + privateKey: new CryptoKey({ + keyType: privateKeyType, + algorithm, + extractable, + keyUsages: privateKeyUsages, + }, key.pair.private_rid), + publicKey: new CryptoKey({ + keyType: publicKeyType, + algorithm, + extractable: true, + keyUsages: publicKeyUsages, + }, key.pair.public_rid), + }; + } } async function sign(algorithm, key, data) { @@ -135,10 +201,12 @@ window.crypto = { getRandomValues, subtle, + CryptoKey, }; window.__bootstrap = window.__bootstrap || {}; window.__bootstrap.crypto = { getRandomValues, subtle, + CryptoKey, }; })(this); diff --git a/op_crates/crypto/key.rs b/op_crates/crypto/key.rs index 9e77df217246a0..f8c3f597a08740 100644 --- a/op_crates/crypto/key.rs +++ b/op_crates/crypto/key.rs @@ -34,7 +34,7 @@ pub enum WebCryptoNamedCurve { P256, #[serde(rename = "P-384")] P384, - #[serde(rename = "P-512")] + #[serde(rename = "P-521")] P521, } @@ -92,25 +92,25 @@ pub enum KeyUsage { #[derive(Serialize, Deserialize, Clone, Copy)] pub enum Algorithm { - #[serde(rename = "RSASSA-PKCS1-v1_5")] + #[serde(rename = "rsassa-pkcs1-v1_5")] RsassaPkcs1v15, - #[serde(rename = "RSA-PSS")] + #[serde(rename = "rsa-pss")] RsaPss, - #[serde(rename = "RSA-OAEP")] + #[serde(rename = "rsa-oaep")] RsaOaep, - #[serde(rename = "ECDSA")] + #[serde(rename = "ecdsa")] Ecdsa, - #[serde(rename = "ECDH")] + #[serde(rename = "ecdh")] Ecdh, - #[serde(rename = "AES-CTR")] + #[serde(rename = "aes-ctr")] AesCtr, - #[serde(rename = "AES-CBC")] + #[serde(rename = "aes-cbc")] AesCbc, - #[serde(rename = "AES-GCM")] + #[serde(rename = "aes-gcm")] AesGcm, - #[serde(rename = "RSA-PSS")] + #[serde(rename = "aes-kw")] AesKw, - #[serde(rename = "HMAC")] + #[serde(rename = "hmac")] Hmac, } diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index a2fff2571c4fb5..ac640051cf3eac 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -254,6 +254,7 @@ delete Object.prototype.__proto__; CountQueuingStrategy: util.nonEnumerable( streams.CountQueuingStrategy, ), + CryptoKey: util.nonEnumerable(crypto.CryptoKey), CustomEvent: util.nonEnumerable(CustomEvent), DOMException: util.nonEnumerable(DOMException), ErrorEvent: util.nonEnumerable(ErrorEvent), diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 852f488a3553be..ce0b76af3bc58b 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -1,6 +1,18 @@ { "WebCryptoAPI": { - "getRandomValues.any.js": true + "getRandomValues.any.js": true, + "generateKey": { + "successes_HMAC.https.any.js": true, + "failures_ECDH.https.any.js": false, + "failures_ECDSA.https.any.js": false, + "failures_HMAC.https.any.js": false, + "failures_RSA-PSS.https.any.js": false, + "failures_RSASSA-PKCS1-v1_5.https.any.js": false, + "successes_ECDH.https.any.js": false, + "successes_ECDSA.https.any.js": false, + "successes_RSA-PSS.https.any.js": true, + "successes_RSASSA-PKCS1-v1_5.https.any.js": true + } }, "console": { "console-is-a-namespace.any.js": true, From c423dca11a5f69b4ffe4448fe0f141c1e8cdc369 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 30 Mar 2021 11:05:47 +0000 Subject: [PATCH 059/130] fix lint --- op_crates/crypto/01_crypto.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 18bc7cd6555816..73493ac3b3f5bd 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -55,7 +55,7 @@ constructor(key, rid) { this.#usages = key.keyUsages; this.#extractable = key.extractable; - let algorithm = key.algorithm; + const algorithm = key.algorithm; algorithm.name = algorithm.name?.toUpperCase(); if (algorithm.name.startsWith("RSASSA-PKCS1")) { // As per spec, `v` cannot be upper case. @@ -132,7 +132,7 @@ } async function generateKey(algorithm, extractable, keyUsages) { - let normalizedAlgorithm = normalize(algorithm); + const normalizedAlgorithm = normalize(algorithm); const { key, err } = await core.jsonOpAsync("op_webcrypto_generate_key", { algorithm: normalizedAlgorithm, From 0b4832881c3f67e33fd3e4b017207d9c710dc54f Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 30 Mar 2021 12:33:28 +0000 Subject: [PATCH 060/130] update wpt --- op_crates/crypto/lib.rs | 22 +++++++++++----- tools/wpt/expectation.json | 53 +++++++++++++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 0b56a8f777c5bb..d54e8e9b39330e 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -231,19 +231,24 @@ pub async fn op_webcrypto_generate_key( ); // Determine agreement from algorithm named_curve. - let agreement: &RingAlgorithm = args + let agreement: Result<&RingAlgorithm, WebCryptoError> = args .algorithm .named_curve .ok_or_else(|| { WebCryptoError::MissingArgument("namedCurve".to_string()) })? - .try_into()?; + .try_into(); + if agreement.is_err() { + return Ok( + json!({ "err": DomError("namedCurve not supported".to_string()) }), + ); + } // Generate private key from agreement and ring rng. let rng = RingRand::SystemRandom::new(); let private_key: EphemeralPrivateKey = tokio::task::spawn_blocking( move || -> Result { - EphemeralPrivateKey::generate(&agreement, &rng) + EphemeralPrivateKey::generate(&agreement.unwrap(), &rng) }, ) .await @@ -281,17 +286,22 @@ pub async fn op_webcrypto_generate_key( Algorithm::Ecdsa => { validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); - let curve: &EcdsaSigningAlgorithm = args + let curve: Result<&EcdsaSigningAlgorithm, WebCryptoError> = args .algorithm .named_curve .ok_or_else(|| { WebCryptoError::MissingArgument("namedCurve".to_string()) })? - .try_into()?; - + .try_into(); + if curve.is_err() { + return Ok( + json!({ "err": DomError("namedCurve not supported".to_string()) }), + ); + } let rng = RingRand::SystemRandom::new(); let private_key: EcdsaKeyPair = tokio::task::spawn_blocking( move || -> Result { + let curve = curve.unwrap(); let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)?; Ok(EcdsaKeyPair::from_pkcs8(&curve, pkcs8.as_ref())?) }, diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index ce0b76af3bc58b..77d73a87cb2c0f 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -3,13 +3,52 @@ "getRandomValues.any.js": true, "generateKey": { "successes_HMAC.https.any.js": true, - "failures_ECDH.https.any.js": false, - "failures_ECDSA.https.any.js": false, - "failures_HMAC.https.any.js": false, - "failures_RSA-PSS.https.any.js": false, - "failures_RSASSA-PKCS1-v1_5.https.any.js": false, - "successes_ECDH.https.any.js": false, - "successes_ECDSA.https.any.js": false, + "successes_ECDH.https.any.js": [ + "Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveKey])", + "Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey])", + "Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey])", + "Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey])", + "Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveBits])", + "Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits])", + "Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", + "Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", + "Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveKey])", + "Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveKey])", + "Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveBits, deriveKey])", + "Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveBits, deriveKey])", + "Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveBits])", + "Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveBits])", + "Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", + "Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", + "Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveKey])", + "Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveKey])", + "Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveBits, deriveKey])", + "Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveBits, deriveKey])", + "Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveBits])", + "Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveBits])", + "Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", + "Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])" + ], + "successes_ECDSA.https.any.js": [ + "Success: generateKey({name: ECDSA, namedCurve: P-521}, false, [sign])", + "Success: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign])", + "Success: generateKey({name: ECDSA, namedCurve: P-521}, false, [verify, sign])", + "Success: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign])", + "Success: generateKey({name: ECDSA, namedCurve: P-521}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify])", + "Success: generateKey({name: ecdsa, namedCurve: P-521}, false, [sign])", + "Success: generateKey({name: ecdsa, namedCurve: P-521}, true, [sign])", + "Success: generateKey({name: ecdsa, namedCurve: P-521}, false, [verify, sign])", + "Success: generateKey({name: ecdsa, namedCurve: P-521}, true, [verify, sign])", + "Success: generateKey({name: ecdsa, namedCurve: P-521}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({name: ecdsa, namedCurve: P-521}, true, [sign, verify, sign, sign, verify])", + "Success: generateKey({name: Ecdsa, namedCurve: P-521}, false, [sign])", + "Success: generateKey({name: Ecdsa, namedCurve: P-521}, true, [sign])", + "Success: generateKey({name: Ecdsa, namedCurve: P-521}, false, [verify, sign])", + "Success: generateKey({name: Ecdsa, namedCurve: P-521}, true, [verify, sign])", + "Success: generateKey({name: Ecdsa, namedCurve: P-521}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({name: Ecdsa, namedCurve: P-521}, true, [sign, verify, sign, sign, verify])" + ], "successes_RSA-PSS.https.any.js": true, "successes_RSASSA-PKCS1-v1_5.https.any.js": true } From 8b9b4b969d69aca9a1a3572bb330b483351c7d58 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 30 Mar 2021 13:29:30 +0000 Subject: [PATCH 061/130] fix sign: normalize correctly --- op_crates/crypto/01_crypto.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index 73493ac3b3f5bd..a95325da981999 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -173,14 +173,12 @@ } } - async function sign(algorithm, key, data) { + async function sign(alg, key, data) { const rid = key[ridSymbol]; - const simpleParam = typeof algorithm == "string"; - - // Normalize params. We've got serde doing the null to Option serialization. - const saltLength = simpleParam ? null : algorithm.saltLength || null; - const hash = simpleParam ? null : algorithm.hash || null; - algorithm = simpleParam ? algorithm : algorithm.name; + const simpleAlg = typeof alg == "string"; + const saltLength = simpleAlg ? null : alg.saltLength; + const hash = simpleAlg ? null : alg.hash; + const algorithm = (simpleParam ? alg : alg.name).toLowerCase(); const { signature, err } = await core.jsonOpAsync("op_webcrypto_sign_key", { rid, From 15b327818c60d089c0ffb5c3f64b026dc6b9a059 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 30 Mar 2021 13:32:43 +0000 Subject: [PATCH 062/130] fix --- op_crates/crypto/01_crypto.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index a95325da981999..eb18482f78f132 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -178,7 +178,7 @@ const simpleAlg = typeof alg == "string"; const saltLength = simpleAlg ? null : alg.saltLength; const hash = simpleAlg ? null : alg.hash; - const algorithm = (simpleParam ? alg : alg.name).toLowerCase(); + const algorithm = (simpleAlg ? alg : alg.name).toLowerCase(); const { signature, err } = await core.jsonOpAsync("op_webcrypto_sign_key", { rid, From a1a9e1ef42f3154f6499639d77e3c586dd2f6703 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 31 Mar 2021 16:45:34 +0000 Subject: [PATCH 063/130] update wpt --- test_util/wpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_util/wpt b/test_util/wpt index 681d273a49e7b5..9418994ebf232a 160000 --- a/test_util/wpt +++ b/test_util/wpt @@ -1 +1 @@ -Subproject commit 681d273a49e7b5228394285b0c017f1b4c0d33b0 +Subproject commit 9418994ebf232a010010d9089105e17985acab87 From cbf9800053a9ad7b124d1d11de044ff1f981d8ff Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 1 Apr 2021 15:55:02 +0000 Subject: [PATCH 064/130] fix serde::Value --- op_crates/crypto/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index d54e8e9b39330e..5d5fc78e881d23 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -109,7 +109,7 @@ impl_resource! { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] -struct WebCryptoAlgorithmArg { +pub struct WebCryptoAlgorithmArg { name: Algorithm, modulus_length: Option, hash: Option, @@ -120,7 +120,7 @@ struct WebCryptoAlgorithmArg { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] -struct WebCryptoGenerateKeyArg { +pub struct WebCryptoGenerateKeyArg { algorithm: WebCryptoAlgorithmArg, extractable: bool, key_usages: Vec, @@ -152,10 +152,9 @@ macro_rules! validate_usage { pub async fn op_webcrypto_generate_key( state: Rc>, - args: Value, + args: WebCryptoGenerateKeyArg, zero_copy: BufVec, ) -> Result { - let args: WebCryptoGenerateKeyArg = serde_json::from_value(args)?; let extractable = args.extractable; let algorithm = args.algorithm.name; From f3fb477e83d357a8f552806bdcf2b89b7e4a39ac Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 2 Apr 2021 15:57:16 +0000 Subject: [PATCH 065/130] update expectations for new wpt --- tools/wpt/expectation.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 5804e95e6a08cd..e8d849952e3530 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -409,7 +409,9 @@ ], "patched-global.any.js": true, "reentrant-strategies.any.js": true, - "tee.any.js": true, + "tee.any.js": [ + "ReadableStream teeing: failing to cancel when canceling both branches in sequence with delay" + ], "templated.any.js": [ "ReadableStream (empty) reader: canceling via the stream should fail" ] From 455fe3161d401fb60e1d011b5d07243615c49092 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 2 Apr 2021 16:09:54 +0000 Subject: [PATCH 066/130] fmt --- op_crates/crypto/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 646be9069fc27e..44f40053230886 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -2,8 +2,8 @@ #![deny(warnings)] -use deno_core::error::null_opbuf; use deno_core::error::bad_resource_id; +use deno_core::error::null_opbuf; use deno_core::error::AnyError; use deno_core::serde_json; use deno_core::serde_json::json; From 38f1eb737bcb95521956337981e4f3a61375cf23 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 2 Apr 2021 16:19:55 +0000 Subject: [PATCH 067/130] merge --- op_crates/crypto/lib.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index 44f40053230886..b14511486cdd4a 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -8,7 +8,6 @@ use deno_core::error::AnyError; use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; -use deno_core::BufVec; use deno_core::JsRuntime; use deno_core::OpState; use deno_core::Resource; @@ -154,7 +153,7 @@ macro_rules! validate_usage { pub async fn op_webcrypto_generate_key( state: Rc>, args: WebCryptoGenerateKeyArg, - zero_copy: BufVec, + zero_copy: Option, ) -> Result { let extractable = args.extractable; let algorithm = args.algorithm.name; @@ -163,21 +162,14 @@ pub async fn op_webcrypto_generate_key( let key = match algorithm { Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss => { validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); - - let public_exponent = if !zero_copy.is_empty() { - Some(&*zero_copy[0]) - } else { - None - }; - - let exp = public_exponent.ok_or_else(|| { + let exp = zero_copy.ok_or_else(|| { WebCryptoError::MissingArgument("publicExponent".to_string()) })?; let modulus_length = args.algorithm.modulus_length.ok_or_else(|| { WebCryptoError::MissingArgument("modulusLength".to_string()) })?; - let exponent = BigUint::from_bytes_be(exp); + let exponent = BigUint::from_bytes_be(&exp); // Generate RSA private key based of exponent, bits and Rng. let mut rng = OsRng; @@ -390,13 +382,12 @@ struct WebCryptoSignArg { pub async fn op_webcrypto_sign_key( state: Rc>, args: Value, - zero_copy: BufVec, + zero_copy: Option, ) -> Result { - assert_eq!(zero_copy.len(), 1); - + let zero_copy = zero_copy.ok_or_else(null_opbuf)?; let state = state.borrow(); let args: WebCryptoSignArg = serde_json::from_value(args)?; - let data = &*zero_copy[0]; + let data = &*zero_copy; let algorithm = args.algorithm; let signature = match algorithm { From f4aee8e44f1c962a45d8aa46d919beb022c5f875 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 4 Apr 2021 10:09:22 +0000 Subject: [PATCH 068/130] fix(wpt/streams): ignore failure --- op_crates/crypto/lib.rs | 7 ------- tools/wpt/expectation.json | 1 + 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/op_crates/crypto/lib.rs b/op_crates/crypto/lib.rs index b14511486cdd4a..3e1b5200a727bf 100644 --- a/op_crates/crypto/lib.rs +++ b/op_crates/crypto/lib.rs @@ -337,13 +337,6 @@ pub async fn op_webcrypto_generate_key( .ok_or_else(|| WebCryptoError::MissingArgument("hash".to_string()))? .into(); let rng = RingRand::SystemRandom::new(); - - // if let Some(length) = args.algorithm.length { - // let mut alg = hash.digest_algorithm(); - // alg.output_len = length as usize; - // alg.chaining_len = length as usize; - // }; - let key: HmacKey = tokio::task::spawn_blocking( move || -> Result { HmacKey::generate(hash, &rng) diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index e8d849952e3530..55c741d539031c 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -410,6 +410,7 @@ "patched-global.any.js": true, "reentrant-strategies.any.js": true, "tee.any.js": [ + "ReadableStream teeing: canceling both branches in sequence with delay", "ReadableStream teeing: failing to cancel when canceling both branches in sequence with delay" ], "templated.any.js": [ From 02f42ef2a5a00f2396dcbb834a3700dcc3d5055c Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 4 Apr 2021 14:54:33 +0000 Subject: [PATCH 069/130] maybe fix wpt --- tools/wpt/expectation.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 55c741d539031c..3e0381e82b27d9 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -409,10 +409,7 @@ ], "patched-global.any.js": true, "reentrant-strategies.any.js": true, - "tee.any.js": [ - "ReadableStream teeing: canceling both branches in sequence with delay", - "ReadableStream teeing: failing to cancel when canceling both branches in sequence with delay" - ], + "tee.any.js": false, "templated.any.js": [ "ReadableStream (empty) reader: canceling via the stream should fail" ] From 8fb184f8f980994a80bfa90b36bdc71323db4d2e Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 8 Apr 2021 16:46:45 +0000 Subject: [PATCH 070/130] re-run CI From abf96455213d5276a771845f2a9f2f670fe309d7 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 8 Apr 2021 16:58:24 +0000 Subject: [PATCH 071/130] cleanup --- webcrypto_example.ts | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 webcrypto_example.ts diff --git a/webcrypto_example.ts b/webcrypto_example.ts deleted file mode 100644 index c132572bf47985..00000000000000 --- a/webcrypto_example.ts +++ /dev/null @@ -1,18 +0,0 @@ -const key = await window.crypto.subtle.generateKey( - { - name: "ECDSA", - namedCurve: "P-384", - }, - true, - ["sign", "verify"], -); - -const enc = new TextEncoder(); -const encoded = enc.encode("Hey"); -const signature = await window.crypto.subtle.sign( - { name: "ECDSA", hash: "SHA-384" }, - key.privateKey, - encoded, -); - -console.log(signature); From 53b4e12c4f03cf1ac683c5c6e2ff3e9372b88b5a Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 20 Apr 2021 08:33:42 +0000 Subject: [PATCH 072/130] chore: rename reg_json_async -> reg_async --- runtime/ops/crypto.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/runtime/ops/crypto.rs b/runtime/ops/crypto.rs index 252ac5839c7165..f349ffd09c4053 100644 --- a/runtime/ops/crypto.rs +++ b/runtime/ops/crypto.rs @@ -17,10 +17,6 @@ pub fn init(rt: &mut deno_core::JsRuntime, maybe_seed: Option) { "op_crypto_get_random_values", op_crypto_get_random_values, ); - super::reg_json_async( - rt, - "op_webcrypto_generate_key", - op_webcrypto_generate_key, - ); - super::reg_json_async(rt, "op_webcrypto_sign_key", op_webcrypto_sign_key); + super::reg_async(rt, "op_webcrypto_generate_key", op_webcrypto_generate_key); + super::reg_async(rt, "op_webcrypto_sign_key", op_webcrypto_sign_key); } From 12ede5a20b6771cb5075e4178416a4828120b91c Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 20 Apr 2021 09:56:23 +0000 Subject: [PATCH 073/130] merge: use opAsync --- op_crates/crypto/01_crypto.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/op_crates/crypto/01_crypto.js b/op_crates/crypto/01_crypto.js index d02938d289ecaf..de404ee3dcf642 100644 --- a/op_crates/crypto/01_crypto.js +++ b/op_crates/crypto/01_crypto.js @@ -134,7 +134,7 @@ async function generateKey(algorithm, extractable, keyUsages) { const normalizedAlgorithm = normalize(algorithm); - const { key, err } = await core.jsonOpAsync("op_webcrypto_generate_key", { + const { key, err } = await core.opAsync("op_webcrypto_generate_key", { algorithm: normalizedAlgorithm, extractable, keyUsages, @@ -180,7 +180,7 @@ const hash = simpleAlg ? null : alg.hash; const algorithm = (simpleAlg ? alg : alg.name).toLowerCase(); - const { signature, err } = await core.jsonOpAsync("op_webcrypto_sign_key", { + const { signature, err } = await core.opAsync("op_webcrypto_sign_key", { rid, algorithm, saltLength, From 091da36cb0cc898b68ff8a6d2349b2255f9b0cdb Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 21 Apr 2021 15:29:36 +0000 Subject: [PATCH 074/130] fix CI --- .gitmodules | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitmodules b/.gitmodules index f2a3f541fd1e44..81a678bad6b666 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,6 +2,10 @@ path = third_party url = https://github.com/denoland/deno_third_party.git shallow = true +[submodule "test_util/wpt"] + path = test_util/wpt + url = https://github.com/denoland/wpt.git + shallow = true [submodule "test_util/std"] path = test_util/std url = https://github.com/denoland/deno_std From e9ebf05b2463f73917071ed1acc91c35c42edbce Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 21 Apr 2021 15:37:27 +0000 Subject: [PATCH 075/130] fix(ci): update Cargo.lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index ee44746ff31ed5..48a11ee5bdc235 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -902,7 +902,7 @@ checksum = "eb20b44f890c460fe78e04c13ea49e69821b58b7a36e7905f43719f6dd9badfa" dependencies = [ "bumpalo", "fnv", - "num-bigint", + "num-bigint 0.2.6", "swc_atoms", "swc_common", "swc_ecmascript", From 50ba4cd4a3e4852fbf641cb5ff9a7e59cafd70a1 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 21 Apr 2021 15:54:49 +0000 Subject: [PATCH 076/130] retry ci From ae4a9aa286552c15e875f9c3c64cc876be9f6d33 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 17 May 2021 11:48:37 +0000 Subject: [PATCH 077/130] fix(merge): register op --- extensions/crypto/lib.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index e7d1e7b13ad5da..496848670de6af 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -6,6 +6,7 @@ use deno_core::error::bad_resource_id; use deno_core::error::null_opbuf; 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; @@ -23,6 +24,7 @@ use rand::rngs::OsRng; use rand::rngs::StdRng; use rand::thread_rng; use rand::Rng; +use rand::SeedableRng; use ring::agreement::Algorithm as RingAlgorithm; use ring::agreement::EphemeralPrivateKey; use ring::hmac::Algorithm as HmacAlgorithm; @@ -36,7 +38,6 @@ use rsa::RSAPrivateKey; use rsa::RSAPublicKey; use sha1::Sha1; use sha2::{Digest, Sha256, Sha384, Sha512}; -use rand::SeedableRng; use std::path::PathBuf; pub use rand; // Re-export rand @@ -59,10 +60,17 @@ pub fn init(maybe_seed: Option) -> Extension { prefix "deno:extensions/crypto", "01_crypto.js", )) - .ops(vec![( - "op_crypto_get_random_values", - op_sync(op_crypto_get_random_values), - )]) + .ops(vec![ + ( + "op_crypto_get_random_values", + op_sync(op_crypto_get_random_values), + ), + ( + "op_webcrypto_generate_key", + op_async(op_webcrypto_generate_key), + ), + ("op_webcrypto_sign_key", op_async(op_webcrypto_sign_key)), + ]) .state(move |state| { if let Some(seed) = maybe_seed { state.put(StdRng::seed_from_u64(seed)); From c8572085360e7510ccaf4d4f06e054f0cdef5f1d Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 4 Jun 2021 09:53:58 +0000 Subject: [PATCH 078/130] update lock --- Cargo.lock | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e0c29450e97a2..c2a45bcdf1c5c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -415,6 +415,12 @@ dependencies = [ "libc", ] +[[package]] +name = "cpuid-bool" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" + [[package]] name = "crc" version = "1.8.1" @@ -1238,7 +1244,7 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" dependencies = [ - "autocfg", + "autocfg 1.0.1", "proc-macro-hack", "proc-macro2 1.0.26", "quote 1.0.9", @@ -1263,7 +1269,7 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" dependencies = [ - "autocfg", + "autocfg 1.0.1", "futures-channel", "futures-core", "futures-io", @@ -1715,7 +1721,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" dependencies = [ - "autocfg", + "autocfg 1.0.1", "hashbrown 0.9.1", "serde", ] From 4f3f2dd38b845b868ea59d1245091e9375582ccf Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 5 Jun 2021 11:48:17 +0000 Subject: [PATCH 079/130] bump tokio --- extensions/crypto/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/crypto/Cargo.toml b/extensions/crypto/Cargo.toml index 3d8c060fa2331e..5e8f99a5661a79 100644 --- a/extensions/crypto/Cargo.toml +++ b/extensions/crypto/Cargo.toml @@ -21,5 +21,5 @@ rsa = "0.4.0" sha-1 = "0.9.4" sha2 = "0.9.3" serde = { version = "1.0.123", features = ["derive"] } -tokio = { version = "1.2.0", features = ["full"] } +tokio = { version = "1.6.1", features = ["full"] } From 85598594439c78b48928e2de83b1af2913f56e26 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 5 Jun 2021 12:17:22 +0000 Subject: [PATCH 080/130] update expectations --- tools/wpt/expectation.json | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 80577e4175f76c..d633180f16665e 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -28,20 +28,6 @@ "rsa.https.any.html": false }, "generateKey": { - "failures_AES-CBC.https.any.html": false, - "failures_AES-CTR.https.any.html": false, - "failures_AES-GCM.https.any.html": false, - "failures_AES-KW.https.any.html": false, - "failures_ECDH.https.any.html": false, - "failures_ECDSA.https.any.html": false, - "failures_HMAC.https.any.html": false, - "failures_RSA-OAEP.https.any.html": false, - "failures_RSA-PSS.https.any.html": false, - "failures_RSASSA-PKCS1-v1_5.https.any.html": false, - "successes_AES-CBC.https.any.html": false, - "successes_AES-CTR.https.any.html": false, - "successes_AES-GCM.https.any.html": false, - "successes_AES-KW.https.any.html": false, "successes_HMAC.https.any.js": true, "successes_ECDH.https.any.js": [ "Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveKey])", From 972db5b99ac16f7aac4f72fad93df499b9669540 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 5 Jun 2021 14:30:37 +0000 Subject: [PATCH 081/130] Remove custom errors and enable wpt --- extensions/crypto/01_crypto.js | 8 +-- extensions/crypto/error.rs | 36 ------------ extensions/crypto/key.rs | 15 +++-- extensions/crypto/lib.rs | 103 +++++++++++---------------------- tools/wpt/expectation.json | 24 ++++++-- 5 files changed, 66 insertions(+), 120 deletions(-) delete mode 100644 extensions/crypto/error.rs diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index d8f725ba5cb234..0321731ab92548 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -134,15 +134,12 @@ async function generateKey(algorithm, extractable, keyUsages) { const normalizedAlgorithm = normalize(algorithm); - const { key, err } = await core.opAsync("op_webcrypto_generate_key", { + const { key } = await core.opAsync("op_webcrypto_generate_key", { algorithm: normalizedAlgorithm, extractable, keyUsages, }, normalizedAlgorithm.publicExponent || new Uint8Array()); - // A DOMError. - if (err) throw new Error(err); - if (key.single) { const { keyType } = key.single.key; const usages = validateUsages(keyUsages, keyType); @@ -180,14 +177,13 @@ const hash = simpleAlg ? null : alg.hash; const algorithm = (simpleAlg ? alg : alg.name).toLowerCase(); - const { signature, err } = await core.opAsync("op_webcrypto_sign_key", { + const { signature } = await core.opAsync("op_webcrypto_sign_key", { rid, algorithm, saltLength, hash, }, data); - if (err) throw new DOMException(err); return new Uint8Array(signature); } diff --git a/extensions/crypto/error.rs b/extensions/crypto/error.rs deleted file mode 100644 index 1e058a1abac2b8..00000000000000 --- a/extensions/crypto/error.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -use serde::Serialize; -use std::fmt; - -#[derive(Debug)] -pub enum WebCryptoError { - MissingArgument(String), - Unsupported, - UnsupportedHash, -} - -impl fmt::Display for WebCryptoError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - WebCryptoError::MissingArgument(s) => { - write!(f, "Missing argument {}", &s) - } - WebCryptoError::Unsupported => write!(f, "Unsupported algorithm"), - WebCryptoError::UnsupportedHash => write!(f, "Unsupported hash"), - } - } -} - -impl std::error::Error for WebCryptoError {} - -#[derive(Debug, Serialize)] -pub struct DomError(pub String); - -impl fmt::Display for DomError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", &self.0) - } -} - -impl std::error::Error for DomError {} diff --git a/extensions/crypto/key.rs b/extensions/crypto/key.rs index f8c3f597a08740..ebd1ac0b94a5d3 100644 --- a/extensions/crypto/key.rs +++ b/extensions/crypto/key.rs @@ -1,6 +1,7 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use crate::error::WebCryptoError; +use deno_core::error::type_error; +use deno_core::error::AnyError; use ring::agreement::Algorithm as RingAlgorithm; use ring::hmac::Algorithm as HmacAlgorithm; use ring::signature::EcdsaSigningAlgorithm; @@ -39,19 +40,21 @@ pub enum WebCryptoNamedCurve { } impl TryInto<&RingAlgorithm> for WebCryptoNamedCurve { - type Error = WebCryptoError; + type Error = AnyError; fn try_into(self) -> Result<&'static RingAlgorithm, Self::Error> { match self { WebCryptoNamedCurve::P256 => Ok(&ring::agreement::ECDH_P256), WebCryptoNamedCurve::P384 => Ok(&ring::agreement::ECDH_P384), - WebCryptoNamedCurve::P521 => Err(WebCryptoError::Unsupported), + WebCryptoNamedCurve::P521 => { + Err(type_error("Unsupported algorithm".to_string())) + } } } } impl TryInto<&EcdsaSigningAlgorithm> for WebCryptoNamedCurve { - type Error = WebCryptoError; + type Error = AnyError; fn try_into(self) -> Result<&'static EcdsaSigningAlgorithm, Self::Error> { match self { @@ -61,7 +64,9 @@ impl TryInto<&EcdsaSigningAlgorithm> for WebCryptoNamedCurve { WebCryptoNamedCurve::P384 => { Ok(&ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING) } - WebCryptoNamedCurve::P521 => Err(WebCryptoError::Unsupported), + WebCryptoNamedCurve::P521 => { + Err(type_error("Unsupported algorithm".to_string())) + } } } } diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index 496848670de6af..31b6cd9a31390c 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -4,6 +4,7 @@ use deno_core::error::bad_resource_id; 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; @@ -34,6 +35,7 @@ use ring::signature::EcdsaKeyPair; use ring::signature::EcdsaSigningAlgorithm; use rsa::padding::PaddingScheme; use rsa::BigUint; +use rsa::PublicKeyParts; use rsa::RSAPrivateKey; use rsa::RSAPublicKey; use sha1::Sha1; @@ -42,11 +44,8 @@ use std::path::PathBuf; pub use rand; // Re-export rand -mod error; mod key; -use crate::error::DomError; -use crate::error::WebCryptoError; use crate::key::Algorithm; use crate::key::KeyUsage; use crate::key::WebCryptoHash; @@ -160,10 +159,7 @@ macro_rules! validate_usage { ($e: expr, $u: expr) => { for usage in $e { if !$u.contains(&usage) { - return Ok(GenerateKeyResult { - key: None, - err: Some(DomError("Invalid key usage".to_string())), - }); + return Err(type_error("Invalid usage")); } } }; @@ -171,8 +167,7 @@ macro_rules! validate_usage { #[derive(Serialize)] pub struct GenerateKeyResult { - key: Option, - err: Option, + key: JsCryptoKey, } pub async fn op_webcrypto_generate_key( @@ -188,10 +183,10 @@ pub async fn op_webcrypto_generate_key( Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss => { validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); let exp = zero_copy.ok_or_else(|| { - WebCryptoError::MissingArgument("publicExponent".to_string()) + type_error("Missing argument publicExponent".to_string()) })?; let modulus_length = args.algorithm.modulus_length.ok_or_else(|| { - WebCryptoError::MissingArgument("modulusLength".to_string()) + type_error("Missing argument modulusLength".to_string()) })?; let exponent = BigUint::from_bytes_be(&exp); @@ -209,10 +204,12 @@ pub async fn op_webcrypto_generate_key( }, ) .await - .unwrap()?; + .unwrap() + .map_err(|e| type_error(e.to_string()))?; - // Extract public key from private key. - let public_key = private_key.to_public_key(); + let public_key = + RSAPublicKey::new(private_key.n().clone(), private_key.e().clone()) + .map_err(|e| type_error(e.to_string()))?; // Create webcrypto keypair. let webcrypto_key_public = WebCryptoKey::new_public( @@ -248,22 +245,16 @@ pub async fn op_webcrypto_generate_key( ); // Determine agreement from algorithm named_curve. - let agreement: Result<&RingAlgorithm, WebCryptoError> = args + let agreement: Result<&RingAlgorithm, AnyError> = args .algorithm .named_curve - .ok_or_else(|| { - WebCryptoError::MissingArgument("namedCurve".to_string()) - })? + .ok_or_else(|| type_error("Missing argument namedCurve".to_string()))? .try_into(); if agreement.is_err() { - return Ok(GenerateKeyResult { - key: None, - err: Some(DomError("namedCurve not supported".to_string())), - }); + return Err(type_error("namedCurve not supported".to_string())); } - // Generate private key from agreement and ring rng. - let rng = RingRand::SystemRandom::new(); + let rng = RingRand::SystemRandom::new(); let private_key: EphemeralPrivateKey = tokio::task::spawn_blocking( move || -> Result { EphemeralPrivateKey::generate(&agreement.unwrap(), &rng) @@ -304,18 +295,13 @@ pub async fn op_webcrypto_generate_key( Algorithm::Ecdsa => { validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); - let curve: Result<&EcdsaSigningAlgorithm, WebCryptoError> = args + let curve: Result<&EcdsaSigningAlgorithm, AnyError> = args .algorithm .named_curve - .ok_or_else(|| { - WebCryptoError::MissingArgument("namedCurve".to_string()) - })? + .ok_or_else(|| type_error("Missing argument namedCurve".to_string()))? .try_into(); if curve.is_err() { - return Ok(GenerateKeyResult { - key: None, - err: Some(DomError("namedCurve not supported".to_string())), - }); + return Err(type_error("namedCurve not supported".to_string())); } let rng = RingRand::SystemRandom::new(); let private_key: EcdsaKeyPair = tokio::task::spawn_blocking( @@ -361,7 +347,7 @@ pub async fn op_webcrypto_generate_key( let hash: HmacAlgorithm = args .algorithm .hash - .ok_or_else(|| WebCryptoError::MissingArgument("hash".to_string()))? + .ok_or_else(|| type_error("Missing argument hash".to_string()))? .into(); let rng = RingRand::SystemRandom::new(); let key: HmacKey = tokio::task::spawn_blocking( @@ -384,13 +370,10 @@ pub async fn op_webcrypto_generate_key( rid: state.resource_table.add(resource), } } - _ => return Err(WebCryptoError::Unsupported.into()), + _ => return Err(type_error("Unsupported algorithm".to_string())), }; - Ok(GenerateKeyResult { - key: Some(key), - err: None, - }) + Ok(GenerateKeyResult { key }) } #[derive(Deserialize)] @@ -404,8 +387,7 @@ pub struct WebCryptoSignArg { #[derive(Serialize)] pub struct SignResult { - signature: Option>, - err: Option, + signature: Vec, } pub async fn op_webcrypto_sign_key( @@ -428,15 +410,12 @@ pub async fn op_webcrypto_sign_key( let private_key = &resource.key; if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { - return Ok(SignResult { - signature: None, - err: Some(DomError("Invalid key usage".to_string())), - }); + return Err(type_error("Invalid key usage".to_string())); } let padding = match resource .hash - .ok_or_else(|| WebCryptoError::MissingArgument("hash".to_string()))? + .ok_or_else(|| type_error("Missing argument hash".to_string()))? { WebCryptoHash::Sha1 => PaddingScheme::PKCS1v15Sign { hash: Some(rsa::hash::Hash::SHA1), @@ -464,20 +443,18 @@ pub async fn op_webcrypto_sign_key( let private_key = &resource.key; if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { - return Ok(SignResult { - signature: None, - err: Some(DomError("Invalid key usage".to_string())), - }); + return Err(type_error("Invalid key usage".to_string())); } let rng = OsRng; - let salt_len = args.salt_length.ok_or_else(|| { - WebCryptoError::MissingArgument("saltLength".to_string()) - })? as usize; + let salt_len = args + .salt_length + .ok_or_else(|| type_error("Missing argument saltLength".to_string()))? + as usize; let (padding, digest_in) = match resource .hash - .ok_or_else(|| WebCryptoError::MissingArgument("hash".to_string()))? + .ok_or_else(|| type_error("Missing argument hash".to_string()))? { WebCryptoHash::Sha1 => { let mut hasher = Sha1::new(); @@ -524,10 +501,7 @@ pub async fn op_webcrypto_sign_key( let key_pair = &resource.key; if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { - return Ok(SignResult { - signature: None, - err: Some(DomError("Invalid key usage".to_string())), - }); + return Err(type_error("Invalid key usage".to_string())); } // We only support P256-SHA256 & P384-SHA384. These are recommended signature pairs. @@ -535,11 +509,10 @@ pub async fn op_webcrypto_sign_key( if let Some(hash) = args.hash { match hash { WebCryptoHash::Sha256 | WebCryptoHash::Sha384 => (), - _ => return Err(WebCryptoError::UnsupportedHash.into()), + _ => return Err(type_error("Unsupported algorithm")), } }; - // Sign data using SecureRng and key. let rng = RingRand::SystemRandom::new(); let signature = key_pair.sign(&rng, &data)?; @@ -554,22 +527,16 @@ pub async fn op_webcrypto_sign_key( let key = &resource.key; if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { - return Ok(SignResult { - signature: None, - err: Some(DomError("Invalid key usage".to_string())), - }); + return Err(type_error("Invalid key usage".to_string())); } let signature = ring::hmac::sign(&key, &data); signature.as_ref().to_vec() } - _ => return Err(WebCryptoError::Unsupported.into()), + _ => return Err(type_error("Unsupported algorithm".to_string())), }; - Ok(SignResult { - signature: Some(signature), - err: None, - }) + Ok(SignResult { signature }) } pub fn get_declaration() -> PathBuf { diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index d633180f16665e..961f3518fbe203 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -28,8 +28,22 @@ "rsa.https.any.html": false }, "generateKey": { - "successes_HMAC.https.any.js": true, - "successes_ECDH.https.any.js": [ + "failures_AES-CBC.https.any.html": false, + "failures_AES-CTR.https.any.html": false, + "failures_AES-GCM.https.any.html": false, + "failures_AES-KW.https.any.html": false, + "failures_ECDH.https.any.html": false, + "failures_ECDSA.https.any.html": false, + "failures_HMAC.https.any.html": false, + "failures_RSA-OAEP.https.any.html": false, + "failures_RSA-PSS.https.any.html": false, + "failures_RSASSA-PKCS1-v1_5.https.any.html": false, + "successes_AES-CBC.https.any.html": false, + "successes_AES-CTR.https.any.html": false, + "successes_AES-GCM.https.any.html": false, + "successes_AES-KW.https.any.html": false, + "successes_HMAC.https.any.html": true, + "successes_ECDH.https.any.html": [ "Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveKey])", "Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey])", "Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey])", @@ -55,7 +69,7 @@ "Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", "Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])" ], - "successes_ECDSA.https.any.js": [ + "successes_ECDSA.https.any.html": [ "Success: generateKey({name: ECDSA, namedCurve: P-521}, false, [sign])", "Success: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign])", "Success: generateKey({name: ECDSA, namedCurve: P-521}, false, [verify, sign])", @@ -75,8 +89,8 @@ "Success: generateKey({name: Ecdsa, namedCurve: P-521}, false, [sign, verify, sign, sign, verify])", "Success: generateKey({name: Ecdsa, namedCurve: P-521}, true, [sign, verify, sign, sign, verify])" ], - "successes_RSA-PSS.https.any.js": true, - "successes_RSASSA-PKCS1-v1_5.https.any.js": true + "successes_RSA-PSS.https.any.html": true, + "successes_RSASSA-PKCS1-v1_5.https.any.html": true }, "historical.any.html": true, "idlharness.https.any.html": [ From d4f5202edf89adfcef329c52110a53667053ba2e Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 5 Jun 2021 16:33:42 +0000 Subject: [PATCH 082/130] fix(RSA): whitelist good public exponents --- Cargo.lock | 2 ++ extensions/crypto/Cargo.toml | 2 ++ extensions/crypto/lib.rs | 12 +++++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 1eb174049d2f38..8c0cff8ddddd5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -656,6 +656,8 @@ name = "deno_crypto" version = "0.21.1" dependencies = [ "deno_core", + "lazy_static", + "num-traits", "rand 0.8.3", "ring", "rsa", diff --git a/extensions/crypto/Cargo.toml b/extensions/crypto/Cargo.toml index bb89634bedd14f..26cbe7e832ee34 100644 --- a/extensions/crypto/Cargo.toml +++ b/extensions/crypto/Cargo.toml @@ -23,3 +23,5 @@ sha2 = "0.9.3" serde = { version = "1.0.123", features = ["derive"] } tokio = { version = "1.6.1", features = ["full"] } uuid = { version = "0.8.2", features = ["v4"] } +lazy_static = "1.4.0" +num-traits = "0.2.14" \ No newline at end of file diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index 2472e2edca43fe..d8c660205ce3e4 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -21,6 +21,8 @@ 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; @@ -53,6 +55,12 @@ use crate::key::WebCryptoKey; use crate::key::WebCryptoKeyPair; use crate::key::WebCryptoNamedCurve; +// Whitelist 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) -> Extension { Extension::builder() .js(include_js_files!( @@ -191,7 +199,9 @@ pub async fn op_webcrypto_generate_key( })?; let exponent = BigUint::from_bytes_be(&exp); - + if exponent != *PUB_EXPONENT_1 && exponent != *PUB_EXPONENT_2 { + return Err(type_error("Bad public exponent")); + } // Generate RSA private key based of exponent, bits and Rng. let mut rng = OsRng; From 4c9599f9bfb520460774d1e662cd3246b0fd8e2c Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 5 Jun 2021 17:37:00 +0000 Subject: [PATCH 083/130] update expectations --- tools/wpt/expectation.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index a9f76dd3bcd35e..f274f5b432410b 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -92,14 +92,9 @@ "successes_RSA-PSS.https.any.html": true, "successes_RSASSA-PKCS1-v1_5.https.any.html": true }, - "historical.any.html": true, + "historical.any.html": false, "idlharness.https.any.html": [ - "Crypto interface: existence and properties of interface object", "Crypto interface object length", - "Crypto interface object name", - "Crypto interface: existence and properties of interface prototype object", - "Crypto interface: existence and properties of interface prototype object's \"constructor\" property", - "Crypto interface: existence and properties of interface prototype object's @@unscopables property", "Crypto interface: attribute subtle", "Crypto interface: operation getRandomValues(ArrayBufferView)", "Crypto must be primary interface of crypto", From a2103a58eae5e48dfe31a6ab493e902e5efb9d26 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 5 Jun 2021 18:06:00 +0000 Subject: [PATCH 084/130] update expectations --- tools/wpt/expectation.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index f274f5b432410b..3b015e90a1f497 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -94,7 +94,12 @@ }, "historical.any.html": false, "idlharness.https.any.html": [ + "Crypto interface: existence and properties of interface object", "Crypto interface object length", + "Crypto interface object name", + "Crypto interface: existence and properties of interface prototype object", + "Crypto interface: existence and properties of interface prototype object's \"constructor\" property", + "Crypto interface: existence and properties of interface prototype object's @@unscopables property", "Crypto interface: attribute subtle", "Crypto interface: operation getRandomValues(ArrayBufferView)", "Crypto must be primary interface of crypto", @@ -102,12 +107,7 @@ "Crypto interface: crypto must inherit property \"subtle\" with the proper type", "Crypto interface: crypto must inherit property \"getRandomValues(ArrayBufferView)\" with the proper type", "Crypto interface: calling getRandomValues(ArrayBufferView) on crypto with too few arguments must throw TypeError", - "CryptoKey interface: existence and properties of interface object", "CryptoKey interface object length", - "CryptoKey interface object name", - "CryptoKey interface: existence and properties of interface prototype object", - "CryptoKey interface: existence and properties of interface prototype object's \"constructor\" property", - "CryptoKey interface: existence and properties of interface prototype object's @@unscopables property", "CryptoKey interface: attribute type", "CryptoKey interface: attribute extractable", "CryptoKey interface: attribute algorithm", From de0a3e2e0c0e050df305685fd651273ba1403bd4 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 6 Jun 2021 08:20:31 +0000 Subject: [PATCH 085/130] fix: expose CryptoKey --- runtime/js/99_main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index efc15bad5a7076..3f1a1f148f9c84 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -315,6 +315,7 @@ delete Object.prototype.__proto__; ), crypto: util.readOnly(crypto.crypto), Crypto: util.nonEnumerable(crypto.Crypto), + CryptoKey: util.nonEnumerable(crypto.CryptoKey), fetch: util.writable(fetch.fetch), performance: util.writable(performance.performance), setInterval: util.writable(timers.setInterval), From 80e7c7c878e7b4602b9f5b5ef954113d313a378e Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 6 Jun 2021 08:29:40 +0000 Subject: [PATCH 086/130] fix lint --- Cargo.lock | 2 +- extensions/crypto/01_crypto.js | 2 +- runtime/js/99_main.js | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e701b188a63f45..b4663fb2ed7b39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -656,9 +656,9 @@ name = "deno_crypto" version = "0.21.1" dependencies = [ "deno_core", + "deno_web", "lazy_static", "num-traits", - "deno_web", "rand 0.8.3", "ring", "rsa", diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index 1fdf779dfa2602..dd193754978054 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -151,7 +151,7 @@ return new Uint8Array(signature); } - // TODO: This will be a class. Waiting for Casper's digest PR to add it. + // TODO(littledivy): This will be a class. Waiting for Casper's digest PR to add it. const subtle = { generateKey, sign, diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index 3f1a1f148f9c84..efc15bad5a7076 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -315,7 +315,6 @@ delete Object.prototype.__proto__; ), crypto: util.readOnly(crypto.crypto), Crypto: util.nonEnumerable(crypto.Crypto), - CryptoKey: util.nonEnumerable(crypto.CryptoKey), fetch: util.writable(fetch.fetch), performance: util.writable(performance.performance), setInterval: util.writable(timers.setInterval), From bada218cedf26901ab3b1533800d949a62ebb2cc Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 6 Jun 2021 09:58:53 +0000 Subject: [PATCH 087/130] update wpt expectations --- tools/wpt/expectation.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index bd78f04f0769a7..2284e8d0928fd0 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -92,11 +92,13 @@ "successes_RSA-PSS.https.any.html": true, "successes_RSASSA-PKCS1-v1_5.https.any.html": true }, - "historical.any.html": false, + "historical.any.html": [ + "Non-secure context window does not have access to crypto.subtle", + "Non-secure context window does not have access to CryptoKey" + ], "idlharness.https.any.html": [ "Crypto interface: attribute subtle", "Crypto interface: operation getRandomValues(ArrayBufferView)", - "Crypto interface: crypto must inherit property \"subtle\" with the proper type", "CryptoKey interface object length", "CryptoKey interface: attribute type", "CryptoKey interface: attribute extractable", From 28052f061fdb68a6ad3656995fa502888aebf92c Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 6 Jun 2021 11:45:52 +0000 Subject: [PATCH 088/130] fix --- extensions/crypto/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index 51f0751ea333cb..66f019caf50eb0 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -42,7 +42,6 @@ use rsa::RSAPublicKey; use sha1::Sha1; use sha2::{Digest, Sha256, Sha384, Sha512}; use std::path::PathBuf; -use std::rc::Rc; pub use rand; // Re-export rand From b50f36013a610bfed266d9ac8a00834ac645c116 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 6 Jun 2021 11:46:16 +0000 Subject: [PATCH 089/130] fmt --- extensions/crypto/01_crypto.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index 1b90b89ad23462..27e8edbeca0be8 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -207,13 +207,13 @@ async generateKey(algorithm, extractable, keyUsages) { const normalizedAlgorithm = normalize(algorithm); - + const { key } = await core.opAsync("op_webcrypto_generate_key", { algorithm: normalizedAlgorithm, extractable, keyUsages, }, normalizedAlgorithm.publicExponent || new Uint8Array()); - + if (key.single) { const { keyType } = key.single.key; const usages = validateUsages(keyUsages, keyType); @@ -224,7 +224,7 @@ } /* CryptoKeyPair */ else { const privateKeyType = key.pair.key.privateKey.keyType; const privateKeyUsages = validateUsages(keyUsages, privateKeyType); - + const publicKeyType = key.pair.key.publicKey.keyType; const publicKeyUsages = validateUsages(keyUsages, publicKeyType); return { @@ -243,7 +243,6 @@ }; } } - } const subtle = webidl.createBranded(SubtleCrypto); From 543e65289d70ff11b4167ef776147df422db7143 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 6 Jun 2021 11:50:18 +0000 Subject: [PATCH 090/130] fix types --- extensions/crypto/01_crypto.js | 5 ---- extensions/crypto/lib.deno_crypto.d.ts | 36 +++++++++++--------------- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index 27e8edbeca0be8..4b8ded1ccdc981 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -252,11 +252,6 @@ webidl.illegalConstructor(); } - get subtle() { - webidl.assertBranded(this, Crypto); - return subtle; - } - getRandomValues(arrayBufferView) { webidl.assertBranded(this, Crypto); const prefix = "Failed to execute 'getRandomValues' on 'Crypto'"; diff --git a/extensions/crypto/lib.deno_crypto.d.ts b/extensions/crypto/lib.deno_crypto.d.ts index b886c5ae720458..0798af59f506ad 100644 --- a/extensions/crypto/lib.deno_crypto.d.ts +++ b/extensions/crypto/lib.deno_crypto.d.ts @@ -111,6 +111,21 @@ interface SubtleCrypto { | DataView | ArrayBuffer, ): Promise; + digest( + algorithm: AlgorithmIdentifier, + data: + | Int8Array + | Int16Array + | Int32Array + | Uint8Array + | Uint16Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | DataView + | ArrayBuffer, + ): Promise; } declare interface Crypto { @@ -138,28 +153,7 @@ interface Algorithm { name: string; } -/** 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 { - digest( - algorithm: AlgorithmIdentifier, - data: - | Int8Array - | Int16Array - | Int32Array - | Uint8Array - | Uint16Array - | Uint32Array - | Uint8ClampedArray - | Float32Array - | Float64Array - | DataView - | ArrayBuffer, - ): Promise; -} - declare var SubtleCrypto: { prototype: SubtleCrypto; new (): SubtleCrypto; }; - -type AlgorithmIdentifier = string | Algorithm; From 57cfe8f5bbf7037f0a2ed2182f8a26f30674782c Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 6 Jun 2021 13:56:14 +0000 Subject: [PATCH 091/130] update wpt expectations --- tools/wpt/expectation.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 37a484891c0b14..c3c4cf0e46b9d3 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -121,12 +121,8 @@ "SubtleCrypto interface: calling encrypt(AlgorithmIdentifier, CryptoKey, BufferSource) on crypto.subtle with too few arguments must throw TypeError", "SubtleCrypto interface: crypto.subtle must inherit property \"decrypt(AlgorithmIdentifier, CryptoKey, BufferSource)\" with the proper type", "SubtleCrypto interface: calling decrypt(AlgorithmIdentifier, CryptoKey, BufferSource) on crypto.subtle with too few arguments must throw TypeError", - "SubtleCrypto interface: crypto.subtle must inherit property \"sign(AlgorithmIdentifier, CryptoKey, BufferSource)\" with the proper type", - "SubtleCrypto interface: calling sign(AlgorithmIdentifier, CryptoKey, BufferSource) on crypto.subtle with too few arguments must throw TypeError", "SubtleCrypto interface: crypto.subtle must inherit property \"verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource)\" with the proper type", "SubtleCrypto interface: calling verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource) on crypto.subtle with too few arguments must throw TypeError", - "SubtleCrypto interface: crypto.subtle must inherit property \"generateKey(AlgorithmIdentifier, boolean, sequence)\" with the proper type", - "SubtleCrypto interface: calling generateKey(AlgorithmIdentifier, boolean, sequence) on crypto.subtle with too few arguments must throw TypeError", "SubtleCrypto interface: crypto.subtle must inherit property \"deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence)\" with the proper type", "SubtleCrypto interface: calling deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence) on crypto.subtle with too few arguments must throw TypeError", "SubtleCrypto interface: crypto.subtle must inherit property \"deriveBits(AlgorithmIdentifier, CryptoKey, unsigned long)\" with the proper type", From 0b88bf44700bcbc4c51fc158d7363c8fea24058b Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 6 Jun 2021 16:25:58 +0000 Subject: [PATCH 092/130] wip webidl migration --- extensions/crypto/00_webidl.js | 63 ++++++++++++++++++++++++++++++++++ extensions/crypto/01_crypto.js | 10 ++++++ 2 files changed, 73 insertions(+) diff --git a/extensions/crypto/00_webidl.js b/extensions/crypto/00_webidl.js index 4545526bf945c1..69af2683035f80 100644 --- a/extensions/crypto/00_webidl.js +++ b/extensions/crypto/00_webidl.js @@ -12,6 +12,23 @@ return webidl.converters["DOMString"](V, opts); }; + webidl.converters["KeyType"] = webidl.createEnumConverter("KeyType", [ + "public", + "private", + "secret", + ]); + + webidl.converters["KeyUsage"] = webidl.createEnumConverter("KeyUsage", [ + "encrypt", + "decrypt", + "sign", + "verify", + "deriveKey", + "deriveBits", + "wrapKey", + "unwrapKey", + ]); + const algorithmDictionary = [ { key: "name", @@ -23,4 +40,50 @@ "Algorithm", algorithmDictionary, ); + + const cryptoKeyDictionary = [ + { + key: "type", + converter: webidl.converters["KeyType"], + required: true, + }, + { + key: "extractable", + converter: webidl.converters["boolean"], + required: true, + }, + { + key: "algorithm", + converter: webidl.converters["DOMString"], + required: true, + }, + { + key: "usages", + converter: webidl.createSequenceConverter( + webidl.converters["KeyUsage"], + ), + required: true, + }, + ]; + + webidl.converters["CryptoKey"] = webidl.createDictionaryConverter( + "CryptoKey", + cryptoKeyDictionary, + ); + + const cryptoKeyPairDictionary = [ + { + key: "publicKey", + converter: webidl.converters["CryptoKey"], + }, + { + key: "privateKey", + converter: webidl.converters["CryptoKey"], + }, + ]; + + webidl.converters["CryptoKeyPair"] = webidl.createDictionaryConverter( + "CryptoKeyPair", + cryptoKeyPairDictionary, + ); })(this); diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index 4b8ded1ccdc981..4717039240d8b0 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -189,6 +189,11 @@ } async sign(alg, key, data) { + const prefix = "Failed to execute 'sign' on 'SubtleCrypto'"; + + webidl.assertBranded(this, SubtleCrypto); + webidl.requiredArguments(arguments.length, 3); + const rid = key[ridSymbol]; const simpleAlg = typeof alg == "string"; const saltLength = simpleAlg ? null : alg.saltLength; @@ -206,6 +211,11 @@ } async generateKey(algorithm, extractable, keyUsages) { + const prefix = "Failed to execute 'generateKey' on 'SubtleCrypto'"; + + webidl.assertBranded(this, SubtleCrypto); + webidl.requiredArguments(arguments.length, 3); + const normalizedAlgorithm = normalize(algorithm); const { key } = await core.opAsync("op_webcrypto_generate_key", { From 55f5dbcbad2dea413072564a8e527b0ec50221d8 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 6 Jun 2021 23:33:31 +0530 Subject: [PATCH 093/130] Update 01_crypto.js --- extensions/crypto/01_crypto.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index 4717039240d8b0..78546aba548fec 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -189,8 +189,6 @@ } async sign(alg, key, data) { - const prefix = "Failed to execute 'sign' on 'SubtleCrypto'"; - webidl.assertBranded(this, SubtleCrypto); webidl.requiredArguments(arguments.length, 3); @@ -211,8 +209,6 @@ } async generateKey(algorithm, extractable, keyUsages) { - const prefix = "Failed to execute 'generateKey' on 'SubtleCrypto'"; - webidl.assertBranded(this, SubtleCrypto); webidl.requiredArguments(arguments.length, 3); From 7897232d5bcbc08c78fe16f15be822ea0ba12c86 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 7 Jun 2021 16:36:24 +0000 Subject: [PATCH 094/130] more webidl progress --- extensions/crypto/00_webidl.js | 104 +++++++++++++++++++++++++++++++++ extensions/crypto/01_crypto.js | 96 ++++++++++++++++++------------ extensions/crypto/key.rs | 30 +++++----- extensions/crypto/lib.rs | 7 ++- tools/wpt/expectation.json | 12 ++-- 5 files changed, 186 insertions(+), 63 deletions(-) diff --git a/extensions/crypto/00_webidl.js b/extensions/crypto/00_webidl.js index 69af2683035f80..a5424c732838a2 100644 --- a/extensions/crypto/00_webidl.js +++ b/extensions/crypto/00_webidl.js @@ -29,6 +29,14 @@ "unwrapKey", ]); + webidl.converters["HashAlgorithmIdentifier"] = (V, opts) => { + if (typeof V == "object") { + return webidl.converters["object"](V, opts); + } + + return webidl.converters["DOMString"](V, opts); + }; + const algorithmDictionary = [ { key: "name", @@ -41,6 +49,92 @@ algorithmDictionary, ); + const rsaKeyGenDictionary = [ + ...algorithmDictionary, + { + key: "publicExponent", + converter: webidl.converters["BufferSource"], + }, + { + key: "modulusLength", + converter: webidl.converters["unsigned long"], + }, + ]; + + webidl.converters["RsaKeyGenParams"] = webidl.createDictionaryConverter( + "RsaKeyGenParams", + rsaKeyGenDictionary, + ); + + const rsaHashedKeyGenDictionary = [ + ...rsaKeyGenDictionary, + { + key: "hash", + converter: webidl.converters["HashAlgorithmIdentifier"], + }, + ]; + + webidl.converters["RsaHashedKeyGenParams"] = webidl.createDictionaryConverter( + "RsaHashedKeyGenParams", + rsaHashedKeyGenDictionary, + ); + + const ecKeyGenDictionary = [ + ...algorithmDictionary, + { + key: "namedCurve", + converter: webidl.converters["DOMString"], + }, + ]; + + webidl.converters["EcKeyGenParams"] = webidl.createDictionaryConverter( + "EcKeyGenParams", + ecKeyGenDictionary, + ); + + const hmacKeyGenDictionary = [ + ...algorithmDictionary, + { + key: "hash", + converter: webidl.converters["HashAlgorithmIdentifier"], + }, + { + key: "length", + converter: webidl.converters["unsigned long"], + }, + ]; + + webidl.converters["HmacKeyGenParams"] = webidl.createDictionaryConverter( + "HmacKeyGenParams", + hmacKeyGenDictionary, + ); + + const rsaPssDictionary = [ + ...algorithmDictionary, + { + key: "saltLength", + converters: webidl.converters["unsigned long"], + }, + ]; + + webidl.converters["RsaPssParams"] = webidl.createDictionaryConverter( + "RsaPssParams", + rsaPssDictionary, + ); + + const ecdsaDictionary = [ + ...algorithmDictionary, + { + key: "hash", + converters: webidl.converters["HashAlgorithmIdentifier"], + }, + ]; + + webidl.converters["EcdsaParams"] = webidl.createDictionaryConverter( + "EcdsaParams", + ecdsaDictionary, + ); + const cryptoKeyDictionary = [ { key: "type", @@ -86,4 +180,14 @@ "CryptoKeyPair", cryptoKeyPairDictionary, ); + + window.__bootstrap.crypto = { + algDict: { + "RsaHashedKeyGenParams": rsaKeyGenDictionary, + "EcKeyGenParams": ecKeyGenDictionary, + "HmacKeyGenParams": hmacKeyGenDictionary, + "RsaPssParams": rsaPssDictionary, + "EcdsaParams": ecdsaDictionary, + }, + }; })(this); diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index 2ed054097d0a3f..2982c058ce784f 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -4,6 +4,7 @@ ((window) => { const core = window.Deno.core; const webidl = window.__bootstrap.webidl; + const { algDict } = window.__bootstrap.crypto; const supportedAlgorithms = { "digest": { @@ -12,8 +13,23 @@ "SHA-384": {}, "SHA-512": {}, }, + "generateKey": { + "RSASSA-PKCS1-v1_5": "RsaHashedKeyGenParams", + "RSA-PSS": "RsaHashedKeyGenParams", + "RSA-OAEP": "RsaHashedKeyGenParams", + "ECDSA": "EcKeyGenParams", + "ECDH": "EcKeyGenParams", + "HMAC": "HmacKeyGenParams", + }, + "sign": { + "RSASSA-PKCS1-v1_5": {}, + "RSA-PSS": "RsaPssParams", + "ECDSA": "EcdsaParams", + "HMAC": {}, + }, }; + // See https://www.w3.org/TR/WebCryptoAPI/#dfn-normalize-an-algorithm function normalizeAlgorithm(algorithm, op) { if (typeof algorithm == "string") { return normalizeAlgorithm({ name: algorithm }, op); @@ -34,13 +50,38 @@ ); } - // TODO(caspervonb) Step 6 (create from webidl definition), when the need arises. - // See https://www.w3.org/TR/WebCryptoAPI/#dfn-normalize-an-algorithm - const normalizedAlgorithm = {}; + const desiredType = registeredAlgorithms[algorithmName]; + + if (typeof desiredType !== "string") { + return { name: algorithmName }; + } + + const normalizedAlgorithm = webidl.converters[desiredType](algorithm, {}); + normalizedAlgorithm.name = algorithmName; - // TODO(caspervonb) Step 9 and 10, when the need arises. - // See https://www.w3.org/TR/WebCryptoAPI/#dfn-normalize-an-algorithm + for (const member of algDict[desiredType]) { + //for (const member of members) { + const idlValue = normalizedAlgorithm[member.key]; + if (member.converters == webidl.converters["BufferSource"]) { + normalizedAlgorithm[member.key] = new Uint8Array( + ArrayBuffer.isView(idlValue) ? idlValue.buffer : idlValue, + ); + } else if ( + member.converters == webidl.converters["HashAlgorithmIdentifier"] + ) { + normalizedAlgorithm[member.key] = normalizeAlgorithm( + idlValue, + "digest", + ); + } else if ( + member.converters == webidl.converters["AlgorithmIdentifier"] + ) { + normalizedAlgorithm[member.key] = normalizeAlgorithm(idlValue, op); + } + //} + } + return normalizedAlgorithm; } @@ -58,8 +99,7 @@ } } - // Represents a rid in a CryptoKey instance. - const ridSymbol = Symbol(); + const ridSymbol = Symbol("[[rid]]"); // The CryptoKey class. A JavaScript representation of a WebCrypto key. // Stores rid of the actual key along with read-only properties. @@ -73,11 +113,7 @@ this.#usages = key.keyUsages; this.#extractable = key.extractable; const algorithm = key.algorithm; - algorithm.name = algorithm.name?.toUpperCase(); - if (algorithm.name.startsWith("RSASSA-PKCS1")) { - // As per spec, `v` cannot be upper case. - algorithm.name = "RSASSA-PKCS1-v1_5"; - } + algorithm.name = algorithm.name; let hash = algorithm.hash; if (typeof hash == "string") { hash = { name: hash }; @@ -104,27 +140,6 @@ } } - // Normalize an algorithm object. makes it less painful to serialize. - function normalize(algorithm) { - if (algorithm.publicExponent) { - if (!(algorithm.publicExponent instanceof Uint8Array)) { - throw new DOMException( - "The provided publicExponent is not an Uint8Array", - "TypeMismatchError", - ); - } - } - - const hash = algorithm.hash; - // Normalizes { hash: { name: "SHA-256" } } to { hash: "SHA-256" } - if (hash && typeof hash !== "string") { - hash = hash.name; - } - // Algorithm names are not case-sensitive. We use lowercase for internal serialization. - const name = algorithm.name.toLowerCase(); - return { ...algorithm, name, hash }; - } - function validateUsages(usages, keyType) { let validUsages = []; if (keyType == "public") { @@ -189,9 +204,16 @@ } async sign(alg, key, data) { + const prefix = "Failed to execute 'sign' on 'SubtleCrypto'"; + webidl.assertBranded(this, SubtleCrypto); webidl.requiredArguments(arguments.length, 3); + data = webidl.converters.BufferSource(data, { + prefix, + context: "Argument 3", + }); + const rid = key[ridSymbol]; const simpleAlg = typeof alg == "string"; const saltLength = simpleAlg ? null : alg.saltLength; @@ -203,7 +225,7 @@ algorithm, saltLength, hash, - }, data); + }, new Uint8Array(ArrayBuffer.isView(data) ? data.buffer : data)); return new Uint8Array(signature); } @@ -212,13 +234,13 @@ webidl.assertBranded(this, SubtleCrypto); webidl.requiredArguments(arguments.length, 3); - const normalizedAlgorithm = normalize(algorithm); + algorithm = normalizeAlgorithm(algorithm, "generateKey"); const { key } = await core.opAsync("op_webcrypto_generate_key", { - algorithm: normalizedAlgorithm, + algorithm, extractable, keyUsages, - }, normalizedAlgorithm.publicExponent || new Uint8Array()); + }, algorithm.publicExponent || new Uint8Array()); if (key.single) { const { keyType } = key.single.key; diff --git a/extensions/crypto/key.rs b/extensions/crypto/key.rs index ebd1ac0b94a5d3..3126d8ed73250e 100644 --- a/extensions/crypto/key.rs +++ b/extensions/crypto/key.rs @@ -1,6 +1,6 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use deno_core::error::type_error; +use deno_core::error::not_supported; use deno_core::error::AnyError; use ring::agreement::Algorithm as RingAlgorithm; use ring::hmac::Algorithm as HmacAlgorithm; @@ -46,9 +46,7 @@ impl TryInto<&RingAlgorithm> for WebCryptoNamedCurve { match self { WebCryptoNamedCurve::P256 => Ok(&ring::agreement::ECDH_P256), WebCryptoNamedCurve::P384 => Ok(&ring::agreement::ECDH_P384), - WebCryptoNamedCurve::P521 => { - Err(type_error("Unsupported algorithm".to_string())) - } + WebCryptoNamedCurve::P521 => Err(not_supported()), } } } @@ -64,9 +62,7 @@ impl TryInto<&EcdsaSigningAlgorithm> for WebCryptoNamedCurve { WebCryptoNamedCurve::P384 => { Ok(&ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING) } - WebCryptoNamedCurve::P521 => { - Err(type_error("Unsupported algorithm".to_string())) - } + WebCryptoNamedCurve::P521 => Err(not_supported()), } } } @@ -97,25 +93,25 @@ pub enum KeyUsage { #[derive(Serialize, Deserialize, Clone, Copy)] pub enum Algorithm { - #[serde(rename = "rsassa-pkcs1-v1_5")] + #[serde(rename = "RSASSA-PKCS1-v1_5")] RsassaPkcs1v15, - #[serde(rename = "rsa-pss")] + #[serde(rename = "RSA-PSS")] RsaPss, - #[serde(rename = "rsa-oaep")] + #[serde(rename = "RSA-OAEP")] RsaOaep, - #[serde(rename = "ecdsa")] + #[serde(rename = "ECDSA")] Ecdsa, - #[serde(rename = "ecdh")] + #[serde(rename = "ECDH")] Ecdh, - #[serde(rename = "aes-ctr")] + #[serde(rename = "AES-CTR")] AesCtr, - #[serde(rename = "aes-cbc")] + #[serde(rename = "AES-CBC")] AesCbc, - #[serde(rename = "aes-gcm")] + #[serde(rename = "AES-GCM")] AesGcm, - #[serde(rename = "aes-kw")] + #[serde(rename = "AES-KW")] AesKw, - #[serde(rename = "hmac")] + #[serde(rename = "HMAC")] Hmac, } diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index 66f019caf50eb0..4df9e7f57a9746 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -1,6 +1,7 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. use deno_core::error::bad_resource_id; +use deno_core::error::not_supported; use deno_core::error::null_opbuf; use deno_core::error::type_error; use deno_core::error::AnyError; @@ -269,7 +270,7 @@ pub async fn op_webcrypto_generate_key( .ok_or_else(|| type_error("Missing argument namedCurve".to_string()))? .try_into(); if agreement.is_err() { - return Err(type_error("namedCurve not supported".to_string())); + return Err(not_supported()); } let rng = RingRand::SystemRandom::new(); @@ -319,7 +320,7 @@ pub async fn op_webcrypto_generate_key( .ok_or_else(|| type_error("Missing argument namedCurve".to_string()))? .try_into(); if curve.is_err() { - return Err(type_error("namedCurve not supported".to_string())); + return Err(not_supported()); } let rng = RingRand::SystemRandom::new(); let private_key: EcdsaKeyPair = tokio::task::spawn_blocking( @@ -388,7 +389,7 @@ pub async fn op_webcrypto_generate_key( rid: state.resource_table.add(resource), } } - _ => return Err(type_error("Unsupported algorithm".to_string())), + _ => return Err(not_supported()), }; Ok(GenerateKeyResult { key }) diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 3ff56cafbc56e4..10ffc23a6cf24a 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -32,12 +32,12 @@ "failures_AES-CTR.https.any.html": false, "failures_AES-GCM.https.any.html": false, "failures_AES-KW.https.any.html": false, - "failures_ECDH.https.any.html": false, - "failures_ECDSA.https.any.html": false, - "failures_HMAC.https.any.html": false, - "failures_RSA-OAEP.https.any.html": false, - "failures_RSA-PSS.https.any.html": false, - "failures_RSASSA-PKCS1-v1_5.https.any.html": false, + "failures_ECDH.https.any.html": true, + "failures_ECDSA.https.any.html": true, + "failures_HMAC.https.any.html": true, + "failures_RSA-OAEP.https.any.html": true, + "failures_RSA-PSS.https.any.html": true, + "failures_RSASSA-PKCS1-v1_5.https.any.html": true, "successes_AES-CBC.https.any.html": false, "successes_AES-CTR.https.any.html": false, "successes_AES-GCM.https.any.html": false, From ee0f39724bf9301b694045e68c2b8e64fa6d1207 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 7 Jun 2021 16:42:23 +0000 Subject: [PATCH 095/130] fix lint --- extensions/crypto/01_crypto.js | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index 2982c058ce784f..f51c1ce9cb3201 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -113,7 +113,6 @@ this.#usages = key.keyUsages; this.#extractable = key.extractable; const algorithm = key.algorithm; - algorithm.name = algorithm.name; let hash = algorithm.hash; if (typeof hash == "string") { hash = { name: hash }; From 05f6cca4ffa13977f60054083e39d3648625ac44 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 7 Jun 2021 16:54:21 +0000 Subject: [PATCH 096/130] remove unit tests cuz no we have wpt --- cli/tests/unit/webcrypto_test.ts | 77 -------------------------------- 1 file changed, 77 deletions(-) delete mode 100644 cli/tests/unit/webcrypto_test.ts diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts deleted file mode 100644 index 8ee9b29aeef1a2..00000000000000 --- a/cli/tests/unit/webcrypto_test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { assert, assertEquals, unitTest } from "./test_util.ts"; - -// Close all crypto key resources to avoid resource leaks. -function closeResource() { - const resources = Deno.resources(); - - for (const i of Object.keys(resources)) { - const rid = Number(i); - if ( - ["RSAPublicKey", "RSAPrivateKey", "EcdsaKeyPair", "HmacKey"].includes( - resources[rid], - ) - ) { - Deno.close(rid); - } - } -} - -unitTest(async function testGenerateRSAKey() { - const subtle = window.crypto.subtle; - assert(subtle); - - const keyPair = await subtle.generateKey( - { - name: "RSA-PSS", - modulusLength: 2048, - publicExponent: new Uint8Array([1, 0, 1]), - hash: "SHA-256", - }, - true, - ["sign", "verify"], - ); - - assert(keyPair.privateKey); - assert(keyPair.publicKey); - assertEquals(keyPair.privateKey.extractable, true); - assert(keyPair.privateKey.usages.includes("sign")); - closeResource(); -}); - -unitTest(async function testGenerateHMACKey() { - const key = await window.crypto.subtle.generateKey( - { - name: "HMAC", - hash: "SHA-512", - }, - true, - ["sign", "verify"], - ); - - assert(key); - assertEquals(key.extractable, true); - assert(key.usages.includes("sign")); - closeResource(); -}); - -unitTest(async function testSignECDSA() { - const key = await window.crypto.subtle.generateKey( - { - name: "ECDSA", - namedCurve: "P-384", - }, - true, - ["sign", "verify"], - ); - - const encoder = new TextEncoder(); - const encoded = encoder.encode("Hello, World!"); - const signature = await window.crypto.subtle.sign( - { name: "ECDSA", hash: "SHA-384" }, - key.privateKey, - encoded, - ); - - assert(signature); - closeResource(); -}); From d3982aa44322128fbca1a2c97a02b7b6eac4f582 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 7 Jun 2021 17:14:13 +0000 Subject: [PATCH 097/130] fix wpt --- extensions/crypto/lib.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index 4df9e7f57a9746..ad0fe1db7572ec 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -176,7 +176,7 @@ macro_rules! validate_usage { ($e: expr, $u: expr) => { for usage in $e { if !$u.contains(&usage) { - return Err(type_error("Invalid usage")); + return Err(custom_error("SyntaxError", "Invalid usage")); } } }; @@ -202,9 +202,10 @@ pub async fn op_webcrypto_generate_key( let exp = zero_copy.ok_or_else(|| { type_error("Missing argument publicExponent".to_string()) })?; - let modulus_length = args.algorithm.modulus_length.ok_or_else(|| { - type_error("Missing argument modulusLength".to_string()) - })?; + let modulus_length = args + .algorithm + .modulus_length + .ok_or_else(|| not_supported())?; let exponent = BigUint::from_bytes_be(&exp); if exponent != *PUB_EXPONENT_1 && exponent != *PUB_EXPONENT_2 { @@ -267,7 +268,7 @@ pub async fn op_webcrypto_generate_key( let agreement: Result<&RingAlgorithm, AnyError> = args .algorithm .named_curve - .ok_or_else(|| type_error("Missing argument namedCurve".to_string()))? + .ok_or_else(|| not_supported())? .try_into(); if agreement.is_err() { return Err(not_supported()); @@ -317,7 +318,7 @@ pub async fn op_webcrypto_generate_key( let curve: Result<&EcdsaSigningAlgorithm, AnyError> = args .algorithm .named_curve - .ok_or_else(|| type_error("Missing argument namedCurve".to_string()))? + .ok_or_else(|| not_supported())? .try_into(); if curve.is_err() { return Err(not_supported()); @@ -363,11 +364,8 @@ pub async fn op_webcrypto_generate_key( Algorithm::Hmac => { validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); - let hash: HmacAlgorithm = args - .algorithm - .hash - .ok_or_else(|| type_error("Missing argument hash".to_string()))? - .into(); + let hash: HmacAlgorithm = + args.algorithm.hash.ok_or_else(|| not_supported())?.into(); let rng = RingRand::SystemRandom::new(); let key: HmacKey = tokio::task::spawn_blocking( move || -> Result { From 887e2b3ba05a0de0c5d1fce63780ae009104643b Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 7 Jun 2021 17:17:05 +0000 Subject: [PATCH 098/130] fix --- extensions/crypto/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index ad0fe1db7572ec..e7ba353057725e 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -1,6 +1,7 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. use deno_core::error::bad_resource_id; +use deno_core::error::custom_error; use deno_core::error::not_supported; use deno_core::error::null_opbuf; use deno_core::error::type_error; From b2864aea25afca083485379fc88e5d15b6441f32 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 7 Jun 2021 17:20:52 +0000 Subject: [PATCH 099/130] fix lint --- extensions/crypto/lib.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index e7ba353057725e..1df58ae17e5153 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -203,10 +203,8 @@ pub async fn op_webcrypto_generate_key( let exp = zero_copy.ok_or_else(|| { type_error("Missing argument publicExponent".to_string()) })?; - let modulus_length = args - .algorithm - .modulus_length - .ok_or_else(|| not_supported())?; + let modulus_length = + args.algorithm.modulus_length.ok_or_else(not_supported)?; let exponent = BigUint::from_bytes_be(&exp); if exponent != *PUB_EXPONENT_1 && exponent != *PUB_EXPONENT_2 { @@ -269,7 +267,7 @@ pub async fn op_webcrypto_generate_key( let agreement: Result<&RingAlgorithm, AnyError> = args .algorithm .named_curve - .ok_or_else(|| not_supported())? + .ok_or_else(not_supported)? .try_into(); if agreement.is_err() { return Err(not_supported()); @@ -319,7 +317,7 @@ pub async fn op_webcrypto_generate_key( let curve: Result<&EcdsaSigningAlgorithm, AnyError> = args .algorithm .named_curve - .ok_or_else(|| not_supported())? + .ok_or_else(not_supported)? .try_into(); if curve.is_err() { return Err(not_supported()); @@ -366,7 +364,7 @@ pub async fn op_webcrypto_generate_key( validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); let hash: HmacAlgorithm = - args.algorithm.hash.ok_or_else(|| not_supported())?.into(); + args.algorithm.hash.ok_or_else(not_supported)?.into(); let rng = RingRand::SystemRandom::new(); let key: HmacKey = tokio::task::spawn_blocking( move || -> Result { From 14e23b155c3e3bc795b6586f242d03c737811c25 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 7 Jun 2021 17:35:45 +0000 Subject: [PATCH 100/130] update expectation --- tools/wpt/expectation.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 10ffc23a6cf24a..3ff56cafbc56e4 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -32,12 +32,12 @@ "failures_AES-CTR.https.any.html": false, "failures_AES-GCM.https.any.html": false, "failures_AES-KW.https.any.html": false, - "failures_ECDH.https.any.html": true, - "failures_ECDSA.https.any.html": true, - "failures_HMAC.https.any.html": true, - "failures_RSA-OAEP.https.any.html": true, - "failures_RSA-PSS.https.any.html": true, - "failures_RSASSA-PKCS1-v1_5.https.any.html": true, + "failures_ECDH.https.any.html": false, + "failures_ECDSA.https.any.html": false, + "failures_HMAC.https.any.html": false, + "failures_RSA-OAEP.https.any.html": false, + "failures_RSA-PSS.https.any.html": false, + "failures_RSASSA-PKCS1-v1_5.https.any.html": false, "successes_AES-CBC.https.any.html": false, "successes_AES-CTR.https.any.html": false, "successes_AES-GCM.https.any.html": false, From 68a8d59c42b5f87ad65cb3f97d46893ba3285be1 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 8 Jun 2021 09:24:25 +0000 Subject: [PATCH 101/130] update expectations --- tools/wpt/expectation.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 3ff56cafbc56e4..8f2007998c7ce2 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -90,7 +90,8 @@ "Success: generateKey({name: Ecdsa, namedCurve: P-521}, true, [sign, verify, sign, sign, verify])" ], "successes_RSA-PSS.https.any.html": true, - "successes_RSASSA-PKCS1-v1_5.https.any.html": true + "successes_RSASSA-PKCS1-v1_5.https.any.html": true, + "successes_RSA-OAEP.https.any.html": true }, "historical.any.html": [ "Non-secure context window does not have access to crypto.subtle", From 5d42e57885333e377b0d9d1449b1e90879c88479 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 8 Jun 2021 10:12:28 +0000 Subject: [PATCH 102/130] tweak converters --- extensions/crypto/00_webidl.js | 76 +++++++++++++++++++++++++--------- extensions/crypto/lib.rs | 7 +++- tools/wpt/expectation.json | 2 +- 3 files changed, 63 insertions(+), 22 deletions(-) diff --git a/extensions/crypto/00_webidl.js b/extensions/crypto/00_webidl.js index a5424c732838a2..8a669ee740745b 100644 --- a/extensions/crypto/00_webidl.js +++ b/extensions/crypto/00_webidl.js @@ -29,11 +29,31 @@ "unwrapKey", ]); + const SupportedHashIdentifiers = [ + "SHA-1", + "SHA-256", + "SHA-384", + "SHA-512", + ]; + + function validateHash(hash) { + const _hash = SupportedHashIdentifiers + .find((key) => key.toLowerCase() == hash.toLowerCase()); + if (_hash == undefined) { + throw new DOMException( + "hash not supported", + "NotSupportedError", + ); + } + } + webidl.converters["HashAlgorithmIdentifier"] = (V, opts) => { if (typeof V == "object") { + validateHash(V.name); return webidl.converters["object"](V, opts); } + validateHash(V); return webidl.converters["DOMString"](V, opts); }; @@ -49,54 +69,70 @@ algorithmDictionary, ); - const rsaKeyGenDictionary = [ + const RsaKeyGenDictionary = [ ...algorithmDictionary, { key: "publicExponent", converter: webidl.converters["BufferSource"], + required: true, }, { key: "modulusLength", converter: webidl.converters["unsigned long"], + required: true, }, ]; webidl.converters["RsaKeyGenParams"] = webidl.createDictionaryConverter( "RsaKeyGenParams", - rsaKeyGenDictionary, + RsaKeyGenDictionary, ); - const rsaHashedKeyGenDictionary = [ - ...rsaKeyGenDictionary, + const RsaHashedKeyGenDictionary = [ + ...RsaKeyGenDictionary, { key: "hash", converter: webidl.converters["HashAlgorithmIdentifier"], + required: true, }, ]; webidl.converters["RsaHashedKeyGenParams"] = webidl.createDictionaryConverter( "RsaHashedKeyGenParams", - rsaHashedKeyGenDictionary, + RsaHashedKeyGenDictionary, ); - const ecKeyGenDictionary = [ + const SupportedNamedCurves = ["P-256", "P-384"]; + const EcKeyGenDictionary = [ ...algorithmDictionary, { key: "namedCurve", - converter: webidl.converters["DOMString"], + converter: (V, opts) => { + const namedCurve = SupportedNamedCurves + .find((key) => key.toLowerCase() == V.toLowerCase()); + if (namedCurve == undefined) { + throw new DOMException( + "namedCurve not supported", + "NotSupportedError", + ); + } + return webidl.converters["DOMString"](namedCurve, opts); + }, + required: true, }, ]; webidl.converters["EcKeyGenParams"] = webidl.createDictionaryConverter( "EcKeyGenParams", - ecKeyGenDictionary, + EcKeyGenDictionary, ); - const hmacKeyGenDictionary = [ + const HmacKeyGenDictionary = [ ...algorithmDictionary, { key: "hash", converter: webidl.converters["HashAlgorithmIdentifier"], + required: true, }, { key: "length", @@ -106,33 +142,35 @@ webidl.converters["HmacKeyGenParams"] = webidl.createDictionaryConverter( "HmacKeyGenParams", - hmacKeyGenDictionary, + HmacKeyGenDictionary, ); - const rsaPssDictionary = [ + const RsaPssDictionary = [ ...algorithmDictionary, { key: "saltLength", converters: webidl.converters["unsigned long"], + required: true, }, ]; webidl.converters["RsaPssParams"] = webidl.createDictionaryConverter( "RsaPssParams", - rsaPssDictionary, + RsaPssDictionary, ); - const ecdsaDictionary = [ + const EcdsaDictionary = [ ...algorithmDictionary, { key: "hash", converters: webidl.converters["HashAlgorithmIdentifier"], + required: true, }, ]; webidl.converters["EcdsaParams"] = webidl.createDictionaryConverter( "EcdsaParams", - ecdsaDictionary, + EcdsaDictionary, ); const cryptoKeyDictionary = [ @@ -183,11 +221,11 @@ window.__bootstrap.crypto = { algDict: { - "RsaHashedKeyGenParams": rsaKeyGenDictionary, - "EcKeyGenParams": ecKeyGenDictionary, - "HmacKeyGenParams": hmacKeyGenDictionary, - "RsaPssParams": rsaPssDictionary, - "EcdsaParams": ecdsaDictionary, + "RsaHashedKeyGenParams": RsaKeyGenDictionary, + "EcKeyGenParams": EcKeyGenDictionary, + "HmacKeyGenParams": HmacKeyGenDictionary, + "RsaPssParams": RsaPssDictionary, + "EcdsaParams": EcdsaDictionary, }, }; })(this); diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index 1df58ae17e5153..43658712139b69 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -174,13 +174,16 @@ enum JsCryptoKey { } macro_rules! validate_usage { - ($e: expr, $u: expr) => { + ($e: expr, $u: expr) => {{ + if $e.len() <= 0 { + return Err(custom_error("SyntaxError", "Invalid usage")); + }; for usage in $e { if !$u.contains(&usage) { return Err(custom_error("SyntaxError", "Invalid usage")); } } - }; + }}; } #[derive(Serialize)] diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 8f2007998c7ce2..e0c6a3f4175960 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -32,7 +32,7 @@ "failures_AES-CTR.https.any.html": false, "failures_AES-GCM.https.any.html": false, "failures_AES-KW.https.any.html": false, - "failures_ECDH.https.any.html": false, + "failures_ECDH.https.any.html": true, "failures_ECDSA.https.any.html": false, "failures_HMAC.https.any.html": false, "failures_RSA-OAEP.https.any.html": false, From 4876d91537cf0878727127814b6efa96f99b5e6a Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 8 Jun 2021 13:55:46 +0000 Subject: [PATCH 103/130] finally :) --- extensions/crypto/lib.rs | 9 +- tools/wpt/expectation.json | 1681 +++++++++++++++++++++++++++++++++++- 2 files changed, 1677 insertions(+), 13 deletions(-) diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index 43658712139b69..5c9e4999e98be4 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -202,7 +202,6 @@ pub async fn op_webcrypto_generate_key( let mut state = state.borrow_mut(); let key = match algorithm { Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss => { - validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); let exp = zero_copy.ok_or_else(|| { type_error("Missing argument publicExponent".to_string()) })?; @@ -211,8 +210,14 @@ pub async fn op_webcrypto_generate_key( let exponent = BigUint::from_bytes_be(&exp); if exponent != *PUB_EXPONENT_1 && exponent != *PUB_EXPONENT_2 { - return Err(type_error("Bad public exponent")); + return Err(custom_error( + "DOMExceptionOperationError", + "Bad public exponent", + )); } + + validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); + // Generate RSA private key based of exponent, bits and Rng. let mut rng = OsRng; diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index e0c6a3f4175960..14cffcddc2f43c 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -28,16 +28,1651 @@ "rsa.https.any.html": false }, "generateKey": { - "failures_AES-CBC.https.any.html": false, - "failures_AES-CTR.https.any.html": false, - "failures_AES-GCM.https.any.html": false, - "failures_AES-KW.https.any.html": false, - "failures_ECDH.https.any.html": true, - "failures_ECDSA.https.any.html": false, - "failures_HMAC.https.any.html": false, - "failures_RSA-OAEP.https.any.html": false, - "failures_RSA-PSS.https.any.html": false, - "failures_RSASSA-PKCS1-v1_5.https.any.html": false, + "failures_AES-CBC.https.any.html": [ + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [decrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [decrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [decrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [decrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [wrapKey, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [decrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [decrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [decrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [decrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [wrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [decrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [decrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [decrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [decrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [wrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveBits])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CBC}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Empty usages: generateKey({length: 128, name: AES-CBC}, false, [])", + "Empty usages: generateKey({length: 128, name: AES-CBC}, true, [])", + "Empty usages: generateKey({length: 192, name: AES-CBC}, false, [])", + "Empty usages: generateKey({length: 192, name: AES-CBC}, true, [])", + "Empty usages: generateKey({length: 256, name: AES-CBC}, false, [])", + "Empty usages: generateKey({length: 256, name: AES-CBC}, true, [])" + ], + "failures_AES-CTR.https.any.html": [ + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [decrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [decrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [decrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [decrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [wrapKey, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [decrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [decrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [decrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [decrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [wrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [decrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [decrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [decrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [decrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [wrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveBits])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-CTR}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Empty usages: generateKey({length: 128, name: AES-CTR}, false, [])", + "Empty usages: generateKey({length: 128, name: AES-CTR}, true, [])", + "Empty usages: generateKey({length: 192, name: AES-CTR}, false, [])", + "Empty usages: generateKey({length: 192, name: AES-CTR}, true, [])", + "Empty usages: generateKey({length: 256, name: AES-CTR}, false, [])", + "Empty usages: generateKey({length: 256, name: AES-CTR}, true, [])" + ], + "failures_AES-GCM.https.any.html": [ + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [decrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [decrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [decrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [decrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [wrapKey, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [decrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [decrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [decrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [decrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [wrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, encrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [decrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, decrypt, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, encrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [decrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, decrypt, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [decrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [decrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [wrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveBits])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, false, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-GCM}, true, [encrypt, decrypt, wrapKey, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Empty usages: generateKey({length: 128, name: AES-GCM}, false, [])", + "Empty usages: generateKey({length: 128, name: AES-GCM}, true, [])", + "Empty usages: generateKey({length: 192, name: AES-GCM}, false, [])", + "Empty usages: generateKey({length: 192, name: AES-GCM}, true, [])", + "Empty usages: generateKey({length: 256, name: AES-GCM}, false, [])", + "Empty usages: generateKey({length: 256, name: AES-GCM}, true, [])" + ], + "failures_AES-KW.https.any.html": [ + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [encrypt])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [wrapKey, encrypt])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [unwrapKey, wrapKey, encrypt])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [unwrapKey, encrypt])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, encrypt])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [decrypt])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [wrapKey, decrypt])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [unwrapKey, wrapKey, decrypt])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [unwrapKey, decrypt])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, decrypt])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [sign])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [wrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [unwrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [verify])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [wrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [unwrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [wrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [wrapKey, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 128, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [encrypt])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [wrapKey, encrypt])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [unwrapKey, wrapKey, encrypt])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [unwrapKey, encrypt])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, encrypt])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [decrypt])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [wrapKey, decrypt])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [unwrapKey, wrapKey, decrypt])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [unwrapKey, decrypt])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, decrypt])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [sign])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [wrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [unwrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [verify])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [wrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [unwrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [wrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [wrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 192, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [encrypt])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [wrapKey, encrypt])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [unwrapKey, wrapKey, encrypt])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [unwrapKey, encrypt])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, encrypt])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [decrypt])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [wrapKey, decrypt])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [unwrapKey, wrapKey, decrypt])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [unwrapKey, decrypt])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, decrypt])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [sign])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [wrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [unwrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [verify])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [wrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [unwrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [wrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [wrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({length: 256, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey, deriveBits])", + "Bad algorithm property: generateKey({length: 64, name: AES-KW}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-KW}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-KW}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-KW}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-KW}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-KW}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-KW}, false, [])", + "Bad algorithm property: generateKey({length: 64, name: AES-KW}, true, [])", + "Bad algorithm property: generateKey({length: 64, name: AES-KW}, false, [wrapKey, unwrapKey, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 64, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-KW}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-KW}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-KW}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-KW}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-KW}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-KW}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-KW}, false, [])", + "Bad algorithm property: generateKey({length: 127, name: AES-KW}, true, [])", + "Bad algorithm property: generateKey({length: 127, name: AES-KW}, false, [wrapKey, unwrapKey, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 127, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-KW}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-KW}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-KW}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-KW}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-KW}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-KW}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-KW}, false, [])", + "Bad algorithm property: generateKey({length: 129, name: AES-KW}, true, [])", + "Bad algorithm property: generateKey({length: 129, name: AES-KW}, false, [wrapKey, unwrapKey, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 129, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-KW}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-KW}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-KW}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-KW}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-KW}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-KW}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-KW}, false, [])", + "Bad algorithm property: generateKey({length: 255, name: AES-KW}, true, [])", + "Bad algorithm property: generateKey({length: 255, name: AES-KW}, false, [wrapKey, unwrapKey, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 255, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-KW}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-KW}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-KW}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-KW}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-KW}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-KW}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-KW}, false, [])", + "Bad algorithm property: generateKey({length: 257, name: AES-KW}, true, [])", + "Bad algorithm property: generateKey({length: 257, name: AES-KW}, false, [wrapKey, unwrapKey, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 257, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-KW}, false, [wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-KW}, true, [wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-KW}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-KW}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-KW}, false, [unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-KW}, true, [unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-KW}, false, [])", + "Bad algorithm property: generateKey({length: 512, name: AES-KW}, true, [])", + "Bad algorithm property: generateKey({length: 512, name: AES-KW}, false, [wrapKey, unwrapKey, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({length: 512, name: AES-KW}, true, [wrapKey, unwrapKey, wrapKey, unwrapKey])", + "Empty usages: generateKey({length: 128, name: AES-KW}, false, [])", + "Empty usages: generateKey({length: 128, name: AES-KW}, true, [])", + "Empty usages: generateKey({length: 192, name: AES-KW}, false, [])", + "Empty usages: generateKey({length: 192, name: AES-KW}, true, [])", + "Empty usages: generateKey({length: 256, name: AES-KW}, false, [])", + "Empty usages: generateKey({length: 256, name: AES-KW}, true, [])" + ], + "failures_ECDH.https.any.html": [ + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [unwrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, unwrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, unwrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, unwrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])", + "Empty usages: generateKey({name: ECDH, namedCurve: P-521}, false, [])", + "Empty usages: generateKey({name: ECDH, namedCurve: P-521}, true, [])" + ], + "failures_ECDSA.https.any.html": [ + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [encrypt])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, encrypt])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign, encrypt])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify, encrypt])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [decrypt])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, decrypt])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign, decrypt])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify, decrypt])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [wrapKey])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, wrapKey])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign, wrapKey])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify, wrapKey])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [unwrapKey])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, unwrapKey])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign, unwrapKey])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify, unwrapKey])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [deriveKey])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, deriveKey])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign, deriveKey])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify, deriveKey])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [deriveBits])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, deriveBits])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign, deriveBits])", + "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify, deriveBits])", + "Empty usages: generateKey({name: ECDSA, namedCurve: P-521}, false, [])", + "Empty usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [])" + ], + "failures_HMAC.https.any.html": true, + "failures_RSA-OAEP.https.any.html": [ + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, sign])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, verify])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveKey])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, deriveBits])", + "Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveBits])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, wrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, decrypt, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, wrapKey, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, encrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [wrapKey, decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, wrapKey, decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, decrypt])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, wrapKey])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", + "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", + "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])", + "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", + "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])" + ], + "failures_RSA-PSS.https.any.html": true, + "failures_RSASSA-PKCS1-v1_5.https.any.html": true, "successes_AES-CBC.https.any.html": false, "successes_AES-CTR.https.any.html": false, "successes_AES-GCM.https.any.html": false, @@ -91,7 +1726,31 @@ ], "successes_RSA-PSS.https.any.html": true, "successes_RSASSA-PKCS1-v1_5.https.any.html": true, - "successes_RSA-OAEP.https.any.html": true + "successes_RSA-OAEP.https.any.html": false, + "successes_RSA-OAEP.https.any.html?1-10": false, + "successes_RSA-OAEP.https.any.html?101-110": false, + "successes_RSA-OAEP.https.any.html?11-20": false, + "successes_RSA-OAEP.https.any.html?111-120": false, + "successes_RSA-OAEP.https.any.html?121-130": false, + "successes_RSA-OAEP.https.any.html?131-140": false, + "successes_RSA-OAEP.https.any.html?141-150": false, + "successes_RSA-OAEP.https.any.html?151-last": false, + "successes_RSA-OAEP.https.any.html?21-30": false, + "successes_RSA-OAEP.https.any.html?31-40": false, + "successes_RSA-OAEP.https.any.html?41-50": false, + "successes_RSA-OAEP.https.any.html?51-60": false, + "successes_RSA-OAEP.https.any.html?61-70": false, + "successes_RSA-OAEP.https.any.html?71-80": false, + "successes_RSA-OAEP.https.any.html?81-90": false, + "successes_RSA-OAEP.https.any.html?91-100": false, + "successes_RSA-PSS.https.any.html?1-10": true, + "successes_RSA-PSS.https.any.html?11-20": true, + "successes_RSA-PSS.https.any.html?21-30": true, + "successes_RSA-PSS.https.any.html?31-last": true, + "successes_RSASSA-PKCS1-v1_5.https.any.html?1-10": true, + "successes_RSASSA-PKCS1-v1_5.https.any.html?11-20": true, + "successes_RSASSA-PKCS1-v1_5.https.any.html?21-30": true, + "successes_RSASSA-PKCS1-v1_5.https.any.html?31-last": true }, "historical.any.html": [ "Non-secure context window does not have access to crypto.subtle", From 8311e767e5f238b6ae4bdaaf9ac8410bd81a3aca Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 8 Jun 2021 14:48:07 +0000 Subject: [PATCH 104/130] re-add resource leak tests --- cli/tests/unit/webcrypto_test.ts | 55 ++++++++++++++++++++++++++++++++ extensions/crypto/01_crypto.js | 4 --- 2 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 cli/tests/unit/webcrypto_test.ts diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts new file mode 100644 index 00000000000000..4540e0732a43c8 --- /dev/null +++ b/cli/tests/unit/webcrypto_test.ts @@ -0,0 +1,55 @@ +import { assert, assertEquals, unitTest } from "./test_util.ts"; + +// Close all crypto key resources to avoid resource leaks. +function closeResource() { + const resources = Deno.resources(); + + for (const i of Object.keys(resources)) { + const rid = Number(i); + if ( + ["RSAPublicKey", "RSAPrivateKey", "EcdsaKeyPair", "HmacKey"].includes( + resources[rid], + ) + ) { + Deno.close(rid); + } + } +} + +unitTest(async function testGenerateRSAKey() { + const subtle = window.crypto.subtle; + assert(subtle); + + const keyPair = await subtle.generateKey( + { + name: "RSA-PSS", + modulusLength: 2048, + publicExponent: new Uint8Array([1, 0, 1]), + hash: "SHA-256", + }, + true, + ["sign", "verify"], + ); + + assert(keyPair.privateKey); + assert(keyPair.publicKey); + assertEquals(keyPair.privateKey.extractable, true); + assert(keyPair.privateKey.usages.includes("sign")); + closeResource(); +}); + +unitTest(async function testGenerateHMACKey() { + const key = await window.crypto.subtle.generateKey( + { + name: "HMAC", + hash: "SHA-512", + }, + true, + ["sign", "verify"], + ); + + assert(key); + assertEquals(key.extractable, true); + assert(key.usages.includes("sign")); + closeResource(); +}); diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index f51c1ce9cb3201..b22eac2c6b5a4f 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -61,7 +61,6 @@ normalizedAlgorithm.name = algorithmName; for (const member of algDict[desiredType]) { - //for (const member of members) { const idlValue = normalizedAlgorithm[member.key]; if (member.converters == webidl.converters["BufferSource"]) { normalizedAlgorithm[member.key] = new Uint8Array( @@ -79,7 +78,6 @@ ) { normalizedAlgorithm[member.key] = normalizeAlgorithm(idlValue, op); } - //} } return normalizedAlgorithm; @@ -101,8 +99,6 @@ const ridSymbol = Symbol("[[rid]]"); - // The CryptoKey class. A JavaScript representation of a WebCrypto key. - // Stores rid of the actual key along with read-only properties. class CryptoKey { #usages; #extractable; From d5c7d56b552c458fb6b35bcd6461bc8e38732d5c Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 9 Jun 2021 09:48:19 +0000 Subject: [PATCH 105/130] finish webidl migration --- cli/tests/unit/webcrypto_test.ts | 22 ++++++++++++++++++++++ extensions/crypto/00_webidl.js | 4 ++-- extensions/crypto/01_crypto.js | 19 +++++++++++-------- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts index 4540e0732a43c8..8ee9b29aeef1a2 100644 --- a/cli/tests/unit/webcrypto_test.ts +++ b/cli/tests/unit/webcrypto_test.ts @@ -53,3 +53,25 @@ unitTest(async function testGenerateHMACKey() { assert(key.usages.includes("sign")); closeResource(); }); + +unitTest(async function testSignECDSA() { + const key = await window.crypto.subtle.generateKey( + { + name: "ECDSA", + namedCurve: "P-384", + }, + true, + ["sign", "verify"], + ); + + const encoder = new TextEncoder(); + const encoded = encoder.encode("Hello, World!"); + const signature = await window.crypto.subtle.sign( + { name: "ECDSA", hash: "SHA-384" }, + key.privateKey, + encoded, + ); + + assert(signature); + closeResource(); +}); diff --git a/extensions/crypto/00_webidl.js b/extensions/crypto/00_webidl.js index 8a669ee740745b..6d665658ec42b2 100644 --- a/extensions/crypto/00_webidl.js +++ b/extensions/crypto/00_webidl.js @@ -149,7 +149,7 @@ ...algorithmDictionary, { key: "saltLength", - converters: webidl.converters["unsigned long"], + converter: webidl.converters["unsigned long"], required: true, }, ]; @@ -163,7 +163,7 @@ ...algorithmDictionary, { key: "hash", - converters: webidl.converters["HashAlgorithmIdentifier"], + converter: webidl.converters["HashAlgorithmIdentifier"], required: true, }, ]; diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index b22eac2c6b5a4f..886a27aec07927 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -204,22 +204,25 @@ webidl.assertBranded(this, SubtleCrypto); webidl.requiredArguments(arguments.length, 3); + const rid = key[ridSymbol]; + + key = webidl.converters["CryptoKey"](key, { + prefix, + context: "Argument 2", + }); + data = webidl.converters.BufferSource(data, { prefix, context: "Argument 3", }); - const rid = key[ridSymbol]; - const simpleAlg = typeof alg == "string"; - const saltLength = simpleAlg ? null : alg.saltLength; - const hash = simpleAlg ? null : alg.hash; - const algorithm = (simpleAlg ? alg : alg.name).toLowerCase(); + alg = normalizeAlgorithm(alg, "sign"); const { signature } = await core.opAsync("op_webcrypto_sign_key", { rid, - algorithm, - saltLength, - hash, + algorithm: alg.name, + saltLength: alg.saltLength, + hash: alg.hash, }, new Uint8Array(ArrayBuffer.isView(data) ? data.buffer : data)); return new Uint8Array(signature); From 371c1cf54e067fce5c237237428d16d59393ad72 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 24 Jun 2021 22:30:46 +0530 Subject: [PATCH 106/130] redo without resource table --- extensions/crypto/01_crypto.js | 286 ++++++++++++++++++++++------- extensions/crypto/key.rs | 50 ------ extensions/crypto/lib.rs | 316 +++++---------------------------- 3 files changed, 272 insertions(+), 380 deletions(-) diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index 886a27aec07927..cd2f7aa63a0d07 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -97,44 +97,58 @@ } } - const ridSymbol = Symbol("[[rid]]"); + const _handle = Symbol("[[handle]]"); + const _algorithm = Symbol("[[algorithm]]"); + const _extractable = Symbol("[[extractable]]"); + const _usages = Symbol("[[usages]]"); + const _type = Symbol("[[_type]]"); class CryptoKey { - #usages; - #extractable; - #algorithm; - #keyType; - - constructor(key, rid) { - this.#usages = key.keyUsages; - this.#extractable = key.extractable; - const algorithm = key.algorithm; - let hash = algorithm.hash; - if (typeof hash == "string") { - hash = { name: hash }; - } - this.#algorithm = { ...algorithm, hash }; - this.#keyType = key.keyType; - this[ridSymbol] = rid; + [_usages]; + [_algorithm]; + [_extractable]; + [_type]; + [_handle]; + + constructor() { + webidl.illegalConstructor(); } get usages() { - return this.#usages; + return this[_usages]; } get extractable() { - return this.#extractable; + return this[_extractable]; } get algorithm() { - return this.#algorithm; + return this[_algorithm]; } get type() { - return this.#keyType; + return this[_type]; + } + + get [Symbol.toStringTag]() { + return "CryptoKey"; + } + + [Symbol.for("Deno.customInspect")](inspect) { + return `${this.constructor.name} ${inspect({})}`; } } + function constructKey(algorithm, extractable, usages, type, handle) { + let key = Object.create(CryptoKey); + key[_algorithm] = algorithm; + key[_extractable] = extractable; + key[_usages] = usages; + key[_type] = type; + key[_handle] = handle; + return key; + } + function validateUsages(usages, keyType) { let validUsages = []; if (keyType == "public") { @@ -158,6 +172,8 @@ return validUsages; } + let keys = []; + class SubtleCrypto { constructor() { webidl.illegalConstructor(); @@ -198,14 +214,12 @@ return result.buffer; } - async sign(alg, key, data) { + async sign(algorithm, key, data) { const prefix = "Failed to execute 'sign' on 'SubtleCrypto'"; webidl.assertBranded(this, SubtleCrypto); webidl.requiredArguments(arguments.length, 3); - const rid = key[ridSymbol]; - key = webidl.converters["CryptoKey"](key, { prefix, context: "Argument 2", @@ -216,56 +230,206 @@ context: "Argument 3", }); - alg = normalizeAlgorithm(alg, "sign"); + algorithm = normalizeAlgorithm(algorithm, "sign"); - const { signature } = await core.opAsync("op_webcrypto_sign_key", { - rid, - algorithm: alg.name, - saltLength: alg.saltLength, - hash: alg.hash, - }, new Uint8Array(ArrayBuffer.isView(data) ? data.buffer : data)); + const index = key[_handle]; + const keyData = keys[index]; - return new Uint8Array(signature); + data = new Uint8Array(ArrayBuffer.isView(data) ? data.buffer : data); + + if (algorithm.name == "HMAC") { + const hashAlgorithm = key[_algorithm].hash; + + const signature = await core.opAsync("op_webcrypto_sign_key", { + key: keyData, + algorithm: "HMAC", + hash: hashAlgorithm, + }, data); + + return signature; + } else if (algorithm.name == "ECDSA") { + // 1. + if (key[_type] !== "private") { + throw new DOMError("InvalidAccessError", "Key type not supported"); + } + + const namedCurve = key[_algorithm].namedCurve; + // 2 to 6. + const signature = await core.opAsync("op_webcrypto_sign_key", { + key: keyData, + algorithm: "ECDSA", + hash: algorithm.hash, + namedCurve, + }, data); + + return signature; + } else if (algorithm.name == "RSA-PSS") { + // 1. + if (key[_type] !== "private") { + throw new DOMError("InvalidAccessError", "Key type not supported"); + } + + // 2. + const hashAlgorithm = key[_algorithm].hash; + const signature = await core.opAsync("op_webcrypto_sign_key", { + key: keyData, + algorithm: "RSA-PSS", + hash: hashAlgorithm, + saltLength: algorithm.saltLength, + }, data); + + return signature; + } else if (algorithm.name == "RSASSA-PKCS1-v1_5") { + // 1. + if (key[_type] !== "private") { + throw new DOMError("InvalidAccessError", "Key type not supported"); + } + + // 2. + const hashAlgorithm = key[_algorithm].hash; + const signature = await core.opAsync("op_webcrypto_sign_key", { + key: keyData, + algorithm: "RSASSA-PKCS1-v1_5", + hash: hashAlgorithm, + }, data); + + return signature; + } } async generateKey(algorithm, extractable, keyUsages) { + const prefix = "Failed to execute 'generateKey' on 'SubtleCrypto'"; + webidl.assertBranded(this, SubtleCrypto); webidl.requiredArguments(arguments.length, 3); algorithm = normalizeAlgorithm(algorithm, "generateKey"); - const { key } = await core.opAsync("op_webcrypto_generate_key", { - algorithm, - extractable, - keyUsages, - }, algorithm.publicExponent || new Uint8Array()); - - if (key.single) { - const { keyType } = key.single.key; - const usages = validateUsages(keyUsages, keyType); - return new CryptoKey( - { keyType, algorithm, extractable, keyUsages: usages }, - key.single.rid, + extractable = webidl.converters["boolean"](extractable, { + prefix, + context: "Argument 2", + }); + + // https://github.com/denoland/deno/pull/9614#issuecomment-866049433 + if (extractable) { + throw new DOMError( + "SecurityError", + "Extractable keys are not supported", + ); + } + + if (algorithm.name == "HMAC") { + // 1. + const illegal = keyUsages.find((usage) => + !["sign", "verify"].includes(usage) + ); + if (illegal) { + throw new SyntaxError("Invalid usage"); + } + + // 2. + if (algorithm.length == 0) { + throw new DOMError("OperationError", "Invalid key length"); + } + + // 3. + const rawMaterial = await core.opAsync( + "op_webcrypto_generate_key", + algorithm, + ); + const index = keys.push({ type: "raw", data: rawMaterial }) - 1; + + // 11 to 13. + const key = constructKey( + { name: "HMAC", hash: algorithm.hash }, + extractable, + keyUsages, + "secret", + index, + ); + + // 14. + return key; + } else if (algorithm.name == "ECDSA") { + // 1. + const illegal = keyUsages.find((usage) => + !["sign", "verify"].includes(usage) + ); + if (illegal) { + throw new SyntaxError("Invalid usage"); + } + + // 3. + const pkcsMaterial = await core.opAsync( + "op_webcrypto_generate_key", + algorithm, + ); + const index = keys.push({ type: "pkcs8", data: pkcsMaterial }) - 1; + + const alg = { name: "ECDSA", namedCurve: algorithm.namedCurve }; + const publicKey = constructKey( + alg, + extractable, + keyUsages, + "public", + index, + ); + const privateKey = constructKey( + alg, + extractable, + keyUsages, + "private", + index, + ); + + return { + publicKey, + privateKey, + }; + } else if ( + algorithm.name == "RSA-PSS" || algorithm.name == "RSASSA-PKCS1-v1_5" + ) { + // 1. + const illegal = keyUsages.find((usage) => + !["sign", "verify"].includes(usage) + ); + if (illegal) { + throw new SyntaxError("Invalid usage"); + } + + // 2. + const pkcsMaterial = await core.opAsync( + "op_webcrypto_generate_key", + algorithm, + ); + const index = keys.push({ type: "pkcs8", data: pkcsMaterial }) - 1; + + // 4 to 8. + const alg = { + name: algorithm.name, + modulusLength: algorithm.modulusLength, + publicExponent: algorithm.publicExponent, + hash: algorithm.hash, + }; + const publicKey = constructKey( + alg, + extractable, + keyUsages, + "public", + index, + ); + const privateKey = constructKey( + alg, + extractable, + keyUsages, + "private", + index, ); - } /* CryptoKeyPair */ else { - const privateKeyType = key.pair.key.privateKey.keyType; - const privateKeyUsages = validateUsages(keyUsages, privateKeyType); - const publicKeyType = key.pair.key.publicKey.keyType; - const publicKeyUsages = validateUsages(keyUsages, publicKeyType); + // 19 to 22. return { - privateKey: new CryptoKey({ - keyType: privateKeyType, - algorithm, - extractable, - keyUsages: privateKeyUsages, - }, key.pair.private_rid), - publicKey: new CryptoKey({ - keyType: publicKeyType, - algorithm, - extractable: true, - keyUsages: publicKeyUsages, - }, key.pair.public_rid), + publicKey, + privateKey, }; } } diff --git a/extensions/crypto/key.rs b/extensions/crypto/key.rs index 3126d8ed73250e..e043966fbe7bc6 100644 --- a/extensions/crypto/key.rs +++ b/extensions/crypto/key.rs @@ -124,56 +124,6 @@ pub struct WebCryptoKey { pub usages: Vec, } -impl WebCryptoKey { - pub fn new_private( - algorithm: Algorithm, - extractable: bool, - usages: Vec, - ) -> Self { - Self { - key_type: KeyType::Private, - extractable, - algorithm, - usages, - } - } - - pub fn new_public( - algorithm: Algorithm, - extractable: bool, - usages: Vec, - ) -> Self { - Self { - key_type: KeyType::Public, - extractable, - algorithm, - usages, - } - } - - pub fn new_secret( - algorithm: Algorithm, - extractable: bool, - usages: Vec, - ) -> Self { - Self { - key_type: KeyType::Secret, - extractable, - algorithm, - usages, - } - } -} - -impl WebCryptoKeyPair { - pub fn new(public_key: WebCryptoKey, private_key: WebCryptoKey) -> Self { - Self { - public_key, - private_key, - } - } -} - #[derive(Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct WebCryptoKeyPair { diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index 5c9e4999e98be4..f0aba8a4aca713 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -34,10 +34,12 @@ 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::BigUint; +use rsa::PrivateKeyEncoding; use rsa::PublicKeyParts; use rsa::RSAPrivateKey; use rsa::RSAPublicKey; @@ -114,32 +116,6 @@ pub fn op_crypto_get_random_values( Ok(()) } -struct CryptoKeyResource { - crypto_key: WebCryptoKey, - key: A, - hash: Option, -} - -// `impl_resource` will use the type name as the resource name. -macro_rules! impl_resource { - ($($t:ty),+) => { - $(impl Resource for CryptoKeyResource<$t> { - fn name(&self) -> Cow { - stringify!($t).into() - } - })* - } -} - -impl_resource! { - RSAPublicKey, - RSAPrivateKey, - EcdsaKeyPair, - ring::agreement::PublicKey, - EphemeralPrivateKey, - HmacKey -} - #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct WebCryptoAlgorithmArg { @@ -151,53 +127,12 @@ pub struct WebCryptoAlgorithmArg { named_curve: Option, } -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct WebCryptoGenerateKeyArg { - algorithm: WebCryptoAlgorithmArg, - extractable: bool, - key_usages: Vec, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -enum JsCryptoKey { - Single { - key: WebCryptoKey, - rid: u32, - }, - Pair { - key: WebCryptoKeyPair, - private_rid: u32, - public_rid: u32, - }, -} - -macro_rules! validate_usage { - ($e: expr, $u: expr) => {{ - if $e.len() <= 0 { - return Err(custom_error("SyntaxError", "Invalid usage")); - }; - for usage in $e { - if !$u.contains(&usage) { - return Err(custom_error("SyntaxError", "Invalid usage")); - } - } - }}; -} - -#[derive(Serialize)] -pub struct GenerateKeyResult { - key: JsCryptoKey, -} - pub async fn op_webcrypto_generate_key( state: Rc>, - args: WebCryptoGenerateKeyArg, + args: WebCryptoAlgorithmArg, zero_copy: Option, -) -> Result { - let extractable = args.extractable; - let algorithm = args.algorithm.name; +) -> Result { + let algorithm = args.name; let mut state = state.borrow_mut(); let key = match algorithm { @@ -205,8 +140,7 @@ pub async fn op_webcrypto_generate_key( let exp = zero_copy.ok_or_else(|| { type_error("Missing argument publicExponent".to_string()) })?; - let modulus_length = - args.algorithm.modulus_length.ok_or_else(not_supported)?; + let modulus_length = args.modulus_length.ok_or_else(not_supported)?; let exponent = BigUint::from_bytes_be(&exp); if exponent != *PUB_EXPONENT_1 && exponent != *PUB_EXPONENT_2 { @@ -216,9 +150,6 @@ pub async fn op_webcrypto_generate_key( )); } - validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); - - // Generate RSA private key based of exponent, bits and Rng. let mut rng = OsRng; let private_key: RSAPrivateKey = tokio::task::spawn_blocking( @@ -234,210 +165,79 @@ pub async fn op_webcrypto_generate_key( .unwrap() .map_err(|e| type_error(e.to_string()))?; - let public_key = - RSAPublicKey::new(private_key.n().clone(), private_key.e().clone()) - .map_err(|e| type_error(e.to_string()))?; - - // Create webcrypto keypair. - let webcrypto_key_public = WebCryptoKey::new_public( - algorithm, - extractable, - args.key_usages.clone(), - ); - let webcrypto_key_private = - WebCryptoKey::new_private(algorithm, extractable, args.key_usages); - let crypto_key = WebCryptoKeyPair::new( - webcrypto_key_public.clone(), - webcrypto_key_private.clone(), - ); - - JsCryptoKey::Pair { - key: crypto_key, - private_rid: state.resource_table.add(CryptoKeyResource { - crypto_key: webcrypto_key_private, - key: private_key, - hash: args.algorithm.hash, - }), - public_rid: state.resource_table.add(CryptoKeyResource { - crypto_key: webcrypto_key_public, - key: public_key, - hash: args.algorithm.hash, - }), - } - } - Algorithm::Ecdh => { - validate_usage!( - &args.key_usages, - vec![KeyUsage::DeriveKey, KeyUsage::DeriveBits] - ); - - // Determine agreement from algorithm named_curve. - let agreement: Result<&RingAlgorithm, AnyError> = args - .algorithm - .named_curve - .ok_or_else(not_supported)? - .try_into(); - if agreement.is_err() { - return Err(not_supported()); - } - - let rng = RingRand::SystemRandom::new(); - let private_key: EphemeralPrivateKey = tokio::task::spawn_blocking( - move || -> Result { - EphemeralPrivateKey::generate(&agreement.unwrap(), &rng) - }, - ) - .await - .unwrap()?; - - // Extract public key. - let public_key = private_key.compute_public_key()?; - // Create webcrypto keypair. - let webcrypto_key_public = WebCryptoKey::new_public( - algorithm, - extractable, - args.key_usages.clone(), - ); - let webcrypto_key_private = - WebCryptoKey::new_private(algorithm, extractable, args.key_usages); - let crypto_key = WebCryptoKeyPair::new( - webcrypto_key_public.clone(), - webcrypto_key_private.clone(), - ); - - JsCryptoKey::Pair { - key: crypto_key, - private_rid: state.resource_table.add(CryptoKeyResource { - crypto_key: webcrypto_key_private, - key: private_key, - hash: args.algorithm.hash, - }), - public_rid: state.resource_table.add(CryptoKeyResource { - crypto_key: webcrypto_key_public, - key: public_key, - hash: args.algorithm.hash, - }), - } + private_key.to_pkcs8()? } Algorithm::Ecdsa => { - validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); - - let curve: Result<&EcdsaSigningAlgorithm, AnyError> = args - .algorithm - .named_curve - .ok_or_else(not_supported)? - .try_into(); + let curve: Result<&EcdsaSigningAlgorithm, AnyError> = + args.named_curve.ok_or_else(not_supported)?.try_into(); if curve.is_err() { return Err(not_supported()); } let rng = RingRand::SystemRandom::new(); - let private_key: EcdsaKeyPair = tokio::task::spawn_blocking( - move || -> Result { + let private_key: Vec = tokio::task::spawn_blocking( + move || -> Result, ring::error::Unspecified> { let curve = curve.unwrap(); let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)?; - Ok(EcdsaKeyPair::from_pkcs8(&curve, pkcs8.as_ref())?) + Ok(pkcs8.as_ref().to_vec()) }, ) .await .unwrap()?; - // Create webcrypto keypair. - let webcrypto_key_public = WebCryptoKey::new_public( - algorithm, - extractable, - args.key_usages.clone(), - ); - let webcrypto_key_private = - WebCryptoKey::new_private(algorithm, extractable, args.key_usages); - let crypto_key = WebCryptoKeyPair::new( - webcrypto_key_public, - webcrypto_key_private.clone(), - ); - - let rid = state.resource_table.add(CryptoKeyResource { - crypto_key: webcrypto_key_private, - key: private_key, - hash: args.algorithm.hash, - }); - - JsCryptoKey::Pair { - key: crypto_key, - private_rid: rid, - // NOTE: We're using the same Resource for public and private key since they are part - // of the same interface in `ring`. - public_rid: rid, - } + private_key } Algorithm::Hmac => { - validate_usage!(&args.key_usages, vec![KeyUsage::Sign, KeyUsage::Verify]); + let hash: HmacAlgorithm = args.hash.ok_or_else(not_supported)?.into(); - let hash: HmacAlgorithm = - args.algorithm.hash.ok_or_else(not_supported)?.into(); let rng = RingRand::SystemRandom::new(); - let key: HmacKey = tokio::task::spawn_blocking( - move || -> Result { - HmacKey::generate(hash, &rng) - }, - ) - .await - .unwrap()?; + let mut key_bytes = [0; ring::digest::MAX_OUTPUT_LEN]; + let key_bytes = &mut key_bytes[..hash.digest_algorithm().output_len]; + rng.fill(key_bytes)?; - let crypto_key = - WebCryptoKey::new_secret(algorithm, extractable, args.key_usages); - let resource = CryptoKeyResource { - crypto_key: crypto_key.clone(), - key, - hash: args.algorithm.hash, - }; - JsCryptoKey::Single { - key: crypto_key, - rid: state.resource_table.add(resource), - } + key_bytes.to_vec() } _ => return Err(not_supported()), }; - Ok(GenerateKeyResult { key }) + Ok(key.into()) +} +#[derive(Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum KeyFormat { + Raw, + Pcks8, +} + +#[derive(Deserialize)] +#[serde(rename_all = "lowercase")] +pub struct KeyData { + r#type: KeyFormat, + data: ZeroCopyBuf, } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct WebCryptoSignArg { - rid: u32, + key: KeyData, algorithm: Algorithm, salt_length: Option, hash: Option, -} - -#[derive(Serialize)] -pub struct SignResult { - signature: Vec, + named_curve: Option, } pub async fn op_webcrypto_sign_key( state: Rc>, args: WebCryptoSignArg, zero_copy: Option, -) -> Result { +) -> Result { let zero_copy = zero_copy.ok_or_else(null_opbuf)?; - let state = state.borrow(); let data = &*zero_copy; let algorithm = args.algorithm; let signature = match algorithm { Algorithm::RsassaPkcs1v15 => { - let resource = state - .resource_table - .get::>(args.rid) - .ok_or_else(bad_resource_id)?; - - let private_key = &resource.key; - - if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { - return Err(type_error("Invalid key usage".to_string())); - } - - let padding = match resource + let private_key = RSAPrivateKey::from_pkcs8(&*args.key.data)?; + let padding = match args .hash .ok_or_else(|| type_error("Missing argument hash".to_string()))? { @@ -455,28 +255,18 @@ pub async fn op_webcrypto_sign_key( }, }; - // Sign data based on computed padding and return buffer private_key.sign(padding, &data)? } Algorithm::RsaPss => { - let resource = state - .resource_table - .get::>(args.rid) - .ok_or_else(bad_resource_id)?; + let private_key = RSAPrivateKey::from_pkcs8(&*args.key.data)?; - let private_key = &resource.key; - - if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { - return Err(type_error("Invalid key usage".to_string())); - } - - let rng = OsRng; let salt_len = args .salt_length .ok_or_else(|| type_error("Missing argument saltLength".to_string()))? as usize; - let (padding, digest_in) = match resource + let rng = OsRng; + let (padding, digest_in) = match args .hash .ok_or_else(|| type_error("Missing argument hash".to_string()))? { @@ -518,16 +308,10 @@ pub async fn op_webcrypto_sign_key( private_key.sign(padding, &digest_in)? } Algorithm::Ecdsa => { - let resource = state - .resource_table - .get::>(args.rid) - .ok_or_else(bad_resource_id)?; - let key_pair = &resource.key; - - if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { - return Err(type_error("Invalid key usage".to_string())); - } + 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 { @@ -544,15 +328,9 @@ pub async fn op_webcrypto_sign_key( signature.as_ref().to_vec() } Algorithm::Hmac => { - let resource = state - .resource_table - .get::>(args.rid) - .ok_or_else(bad_resource_id)?; - let key = &resource.key; - - if !resource.crypto_key.usages.contains(&KeyUsage::Sign) { - return Err(type_error("Invalid key usage".to_string())); - } + 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() @@ -560,7 +338,7 @@ pub async fn op_webcrypto_sign_key( _ => return Err(type_error("Unsupported algorithm".to_string())), }; - Ok(SignResult { signature }) + Ok(signature.into()) } pub fn op_crypto_random_uuid( From 19e99baca5c53ae2a1f95af2802fa669e96b2cb5 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 24 Jun 2021 22:39:50 +0530 Subject: [PATCH 107/130] some fies --- extensions/crypto/01_crypto.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index cd2f7aa63a0d07..b1607e1ca96ee6 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -101,7 +101,7 @@ const _algorithm = Symbol("[[algorithm]]"); const _extractable = Symbol("[[extractable]]"); const _usages = Symbol("[[usages]]"); - const _type = Symbol("[[_type]]"); + const _type = Symbol("[[type]]"); class CryptoKey { [_usages]; @@ -140,7 +140,7 @@ } function constructKey(algorithm, extractable, usages, type, handle) { - let key = Object.create(CryptoKey); + let key = webidl.createBranded(CryptoKey); key[_algorithm] = algorithm; key[_extractable] = extractable; key[_usages] = usages; @@ -311,7 +311,7 @@ }); // https://github.com/denoland/deno/pull/9614#issuecomment-866049433 - if (extractable) { + if (!extractable) { throw new DOMError( "SecurityError", "Extractable keys are not supported", @@ -401,6 +401,7 @@ const pkcsMaterial = await core.opAsync( "op_webcrypto_generate_key", algorithm, + algorithm.publicExponent || new Uint8Array(), ); const index = keys.push({ type: "pkcs8", data: pkcsMaterial }) - 1; From 62393c7f54fae3dfa895f73988320ab8b0564ca3 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 25 Jun 2021 13:45:32 +0530 Subject: [PATCH 108/130] Make WPT pass after redo --- cli/tests/unit/webcrypto_test.ts | 19 --- extensions/crypto/00_webidl.js | 2 +- extensions/crypto/01_crypto.js | 93 +++++------ extensions/crypto/key.rs | 48 ++---- extensions/crypto/lib.rs | 51 +++--- tools/wpt/expectation.json | 279 ++++++++++++++++++++++++++----- 6 files changed, 321 insertions(+), 171 deletions(-) diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts index 8ee9b29aeef1a2..4361d3a10b28ba 100644 --- a/cli/tests/unit/webcrypto_test.ts +++ b/cli/tests/unit/webcrypto_test.ts @@ -1,21 +1,5 @@ import { assert, assertEquals, unitTest } from "./test_util.ts"; -// Close all crypto key resources to avoid resource leaks. -function closeResource() { - const resources = Deno.resources(); - - for (const i of Object.keys(resources)) { - const rid = Number(i); - if ( - ["RSAPublicKey", "RSAPrivateKey", "EcdsaKeyPair", "HmacKey"].includes( - resources[rid], - ) - ) { - Deno.close(rid); - } - } -} - unitTest(async function testGenerateRSAKey() { const subtle = window.crypto.subtle; assert(subtle); @@ -35,7 +19,6 @@ unitTest(async function testGenerateRSAKey() { assert(keyPair.publicKey); assertEquals(keyPair.privateKey.extractable, true); assert(keyPair.privateKey.usages.includes("sign")); - closeResource(); }); unitTest(async function testGenerateHMACKey() { @@ -51,7 +34,6 @@ unitTest(async function testGenerateHMACKey() { assert(key); assertEquals(key.extractable, true); assert(key.usages.includes("sign")); - closeResource(); }); unitTest(async function testSignECDSA() { @@ -73,5 +55,4 @@ unitTest(async function testSignECDSA() { ); assert(signature); - closeResource(); }); diff --git a/extensions/crypto/00_webidl.js b/extensions/crypto/00_webidl.js index 6d665658ec42b2..cf626df4ea083a 100644 --- a/extensions/crypto/00_webidl.js +++ b/extensions/crypto/00_webidl.js @@ -102,7 +102,7 @@ RsaHashedKeyGenDictionary, ); - const SupportedNamedCurves = ["P-256", "P-384"]; + const SupportedNamedCurves = ["P-256", "P-384", "P-512"]; const EcKeyGenDictionary = [ ...algorithmDictionary, { diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index b1607e1ca96ee6..c5a91b2a1269a7 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -149,27 +149,10 @@ return key; } - function validateUsages(usages, keyType) { - let validUsages = []; - if (keyType == "public") { - ["encrypt", "verify", "wrapKey"].forEach((usage) => { - if (usages.includes(usage)) { - validUsages.push(usage); - } - }); - } else if (keyType == "private") { - ["decrypt", "sign", "unwrapKey", "deriveKey", "deriveBits"].forEach( - (usage) => { - if (usages.includes(usage)) { - validUsages.push(usage); - } - }, - ); - } /* secret */ else { - validUsages = usages; - } - - return validUsages; + // https://w3c.github.io/webcrypto/#concept-usage-intersection + // TODO(littledivy): When the need arises, make `b` a list. + function usageIntersection(a, b) { + return a.includes(b) ? [b] : []; } let keys = []; @@ -220,27 +203,22 @@ webidl.assertBranded(this, SubtleCrypto); webidl.requiredArguments(arguments.length, 3); - key = webidl.converters["CryptoKey"](key, { - prefix, - context: "Argument 2", - }); + algorithm = normalizeAlgorithm(algorithm, "sign"); data = webidl.converters.BufferSource(data, { prefix, context: "Argument 3", }); - algorithm = normalizeAlgorithm(algorithm, "sign"); - const index = key[_handle]; const keyData = keys[index]; data = new Uint8Array(ArrayBuffer.isView(data) ? data.buffer : data); if (algorithm.name == "HMAC") { - const hashAlgorithm = key[_algorithm].hash; + const hashAlgorithm = key[_algorithm].hash.name; - const signature = await core.opAsync("op_webcrypto_sign_key", { + const signature = await core.opAsync("op_crypto_sign_key", { key: keyData, algorithm: "HMAC", hash: hashAlgorithm, @@ -250,12 +228,15 @@ } else if (algorithm.name == "ECDSA") { // 1. if (key[_type] !== "private") { - throw new DOMError("InvalidAccessError", "Key type not supported"); + throw new DOMException( + "Key type not supported", + "InvalidAccessError", + ); } const namedCurve = key[_algorithm].namedCurve; // 2 to 6. - const signature = await core.opAsync("op_webcrypto_sign_key", { + const signature = await core.opAsync("op_crypto_sign_key", { key: keyData, algorithm: "ECDSA", hash: algorithm.hash, @@ -266,12 +247,15 @@ } else if (algorithm.name == "RSA-PSS") { // 1. if (key[_type] !== "private") { - throw new DOMError("InvalidAccessError", "Key type not supported"); + throw new DOMException( + "Key type not supported", + "InvalidAccessError", + ); } // 2. - const hashAlgorithm = key[_algorithm].hash; - const signature = await core.opAsync("op_webcrypto_sign_key", { + const hashAlgorithm = key[_algorithm].hash.name; + const signature = await core.opAsync("op_crypto_sign_key", { key: keyData, algorithm: "RSA-PSS", hash: hashAlgorithm, @@ -282,12 +266,15 @@ } else if (algorithm.name == "RSASSA-PKCS1-v1_5") { // 1. if (key[_type] !== "private") { - throw new DOMError("InvalidAccessError", "Key type not supported"); + throw new DOMException( + "Key type not supported", + "InvalidAccessError", + ); } // 2. - const hashAlgorithm = key[_algorithm].hash; - const signature = await core.opAsync("op_webcrypto_sign_key", { + const hashAlgorithm = key[_algorithm].hash.name; + const signature = await core.opAsync("op_crypto_sign_key", { key: keyData, algorithm: "RSASSA-PKCS1-v1_5", hash: hashAlgorithm, @@ -312,12 +299,16 @@ // https://github.com/denoland/deno/pull/9614#issuecomment-866049433 if (!extractable) { - throw new DOMError( - "SecurityError", + throw new DOMException( "Extractable keys are not supported", + "SecurityError", ); } + if (keyUsages.length == 0) { + throw new SyntaxError("Usages must not be empty"); + } + if (algorithm.name == "HMAC") { // 1. const illegal = keyUsages.find((usage) => @@ -329,19 +320,23 @@ // 2. if (algorithm.length == 0) { - throw new DOMError("OperationError", "Invalid key length"); + throw new DOMException("Invalid key length", "OperationError"); } // 3. const rawMaterial = await core.opAsync( - "op_webcrypto_generate_key", + "op_crypto_generate_key", algorithm, ); const index = keys.push({ type: "raw", data: rawMaterial }) - 1; // 11 to 13. const key = constructKey( - { name: "HMAC", hash: algorithm.hash }, + { + name: "HMAC", + hash: { name: algorithm.hash }, + length: algorithm.length, + }, extractable, keyUsages, "secret", @@ -361,7 +356,7 @@ // 3. const pkcsMaterial = await core.opAsync( - "op_webcrypto_generate_key", + "op_crypto_generate_key", algorithm, ); const index = keys.push({ type: "pkcs8", data: pkcsMaterial }) - 1; @@ -370,14 +365,14 @@ const publicKey = constructKey( alg, extractable, - keyUsages, + usageIntersection(keyUsages, "verify"), "public", index, ); const privateKey = constructKey( alg, extractable, - keyUsages, + usageIntersection(keyUsages, "sign"), "private", index, ); @@ -399,7 +394,7 @@ // 2. const pkcsMaterial = await core.opAsync( - "op_webcrypto_generate_key", + "op_crypto_generate_key", algorithm, algorithm.publicExponent || new Uint8Array(), ); @@ -410,19 +405,19 @@ name: algorithm.name, modulusLength: algorithm.modulusLength, publicExponent: algorithm.publicExponent, - hash: algorithm.hash, + hash: { name: algorithm.hash }, }; const publicKey = constructKey( alg, extractable, - keyUsages, + usageIntersection(keyUsages, "verify"), "public", index, ); const privateKey = constructKey( alg, extractable, - keyUsages, + usageIntersection(keyUsages, "sign"), "private", index, ); diff --git a/extensions/crypto/key.rs b/extensions/crypto/key.rs index e043966fbe7bc6..4adc55a4dabf47 100644 --- a/extensions/crypto/key.rs +++ b/extensions/crypto/key.rs @@ -18,7 +18,7 @@ pub enum KeyType { } #[derive(Serialize, Deserialize, Copy, Clone)] -pub enum WebCryptoHash { +pub enum CryptoHash { #[serde(rename = "SHA-1")] Sha1, #[serde(rename = "SHA-256")] @@ -30,7 +30,7 @@ pub enum WebCryptoHash { } #[derive(Serialize, Deserialize, Copy, Clone)] -pub enum WebCryptoNamedCurve { +pub enum CryptoNamedCurve { #[serde(rename = "P-256")] P256, #[serde(rename = "P-384")] @@ -39,41 +39,41 @@ pub enum WebCryptoNamedCurve { P521, } -impl TryInto<&RingAlgorithm> for WebCryptoNamedCurve { +impl TryInto<&RingAlgorithm> for CryptoNamedCurve { type Error = AnyError; fn try_into(self) -> Result<&'static RingAlgorithm, Self::Error> { match self { - WebCryptoNamedCurve::P256 => Ok(&ring::agreement::ECDH_P256), - WebCryptoNamedCurve::P384 => Ok(&ring::agreement::ECDH_P384), - WebCryptoNamedCurve::P521 => Err(not_supported()), + CryptoNamedCurve::P256 => Ok(&ring::agreement::ECDH_P256), + CryptoNamedCurve::P384 => Ok(&ring::agreement::ECDH_P384), + CryptoNamedCurve::P521 => Err(not_supported()), } } } -impl TryInto<&EcdsaSigningAlgorithm> for WebCryptoNamedCurve { +impl TryInto<&EcdsaSigningAlgorithm> for CryptoNamedCurve { type Error = AnyError; fn try_into(self) -> Result<&'static EcdsaSigningAlgorithm, Self::Error> { match self { - WebCryptoNamedCurve::P256 => { + CryptoNamedCurve::P256 => { Ok(&ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING) } - WebCryptoNamedCurve::P384 => { + CryptoNamedCurve::P384 => { Ok(&ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING) } - WebCryptoNamedCurve::P521 => Err(not_supported()), + CryptoNamedCurve::P521 => Err(not_supported()), } } } -impl From for HmacAlgorithm { - fn from(hash: WebCryptoHash) -> HmacAlgorithm { +impl From for HmacAlgorithm { + fn from(hash: CryptoHash) -> HmacAlgorithm { match hash { - WebCryptoHash::Sha1 => ring::hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, - WebCryptoHash::Sha256 => ring::hmac::HMAC_SHA256, - WebCryptoHash::Sha384 => ring::hmac::HMAC_SHA384, - WebCryptoHash::Sha512 => ring::hmac::HMAC_SHA512, + 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, } } } @@ -114,19 +114,3 @@ pub enum Algorithm { #[serde(rename = "HMAC")] Hmac, } - -#[derive(Serialize, Deserialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WebCryptoKey { - pub key_type: KeyType, - pub extractable: bool, - pub algorithm: Algorithm, - pub usages: Vec, -} - -#[derive(Serialize, Deserialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WebCryptoKeyPair { - pub public_key: WebCryptoKey, - pub private_key: WebCryptoKey, -} diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index f0aba8a4aca713..371821a5920969 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -52,11 +52,9 @@ pub use rand; // Re-export rand mod key; use crate::key::Algorithm; +use crate::key::CryptoHash; +use crate::key::CryptoNamedCurve; use crate::key::KeyUsage; -use crate::key::WebCryptoHash; -use crate::key::WebCryptoKey; -use crate::key::WebCryptoKeyPair; -use crate::key::WebCryptoNamedCurve; // Whitelist for RSA public exponents. lazy_static! { @@ -76,11 +74,8 @@ pub fn init(maybe_seed: Option) -> Extension { "op_crypto_get_random_values", op_sync(op_crypto_get_random_values), ), - ( - "op_webcrypto_generate_key", - op_async(op_webcrypto_generate_key), - ), - ("op_webcrypto_sign_key", op_async(op_webcrypto_sign_key)), + ("op_crypto_generate_key", op_async(op_crypto_generate_key)), + ("op_crypto_sign_key", op_async(op_crypto_sign_key)), ("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)), ("op_crypto_random_uuid", op_sync(op_crypto_random_uuid)), ]) @@ -118,18 +113,18 @@ pub fn op_crypto_get_random_values( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] -pub struct WebCryptoAlgorithmArg { +pub struct AlgorithmArg { name: Algorithm, modulus_length: Option, - hash: Option, + hash: Option, #[allow(dead_code)] length: Option, - named_curve: Option, + named_curve: Option, } -pub async fn op_webcrypto_generate_key( +pub async fn op_crypto_generate_key( state: Rc>, - args: WebCryptoAlgorithmArg, + args: AlgorithmArg, zero_copy: Option, ) -> Result { let algorithm = args.name; @@ -217,17 +212,17 @@ pub struct KeyData { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] -pub struct WebCryptoSignArg { +pub struct SignArg { key: KeyData, algorithm: Algorithm, salt_length: Option, - hash: Option, - named_curve: Option, + hash: Option, + named_curve: Option, } -pub async fn op_webcrypto_sign_key( +pub async fn op_crypto_sign_key( state: Rc>, - args: WebCryptoSignArg, + args: SignArg, zero_copy: Option, ) -> Result { let zero_copy = zero_copy.ok_or_else(null_opbuf)?; @@ -241,16 +236,16 @@ pub async fn op_webcrypto_sign_key( .hash .ok_or_else(|| type_error("Missing argument hash".to_string()))? { - WebCryptoHash::Sha1 => PaddingScheme::PKCS1v15Sign { + CryptoHash::Sha1 => PaddingScheme::PKCS1v15Sign { hash: Some(rsa::hash::Hash::SHA1), }, - WebCryptoHash::Sha256 => PaddingScheme::PKCS1v15Sign { + CryptoHash::Sha256 => PaddingScheme::PKCS1v15Sign { hash: Some(rsa::hash::Hash::SHA2_256), }, - WebCryptoHash::Sha384 => PaddingScheme::PKCS1v15Sign { + CryptoHash::Sha384 => PaddingScheme::PKCS1v15Sign { hash: Some(rsa::hash::Hash::SHA2_384), }, - WebCryptoHash::Sha512 => PaddingScheme::PKCS1v15Sign { + CryptoHash::Sha512 => PaddingScheme::PKCS1v15Sign { hash: Some(rsa::hash::Hash::SHA2_512), }, }; @@ -270,7 +265,7 @@ pub async fn op_webcrypto_sign_key( .hash .ok_or_else(|| type_error("Missing argument hash".to_string()))? { - WebCryptoHash::Sha1 => { + CryptoHash::Sha1 => { let mut hasher = Sha1::new(); hasher.update(&data); ( @@ -278,7 +273,7 @@ pub async fn op_webcrypto_sign_key( hasher.finalize()[..].to_vec(), ) } - WebCryptoHash::Sha256 => { + CryptoHash::Sha256 => { let mut hasher = Sha256::new(); hasher.update(&data); ( @@ -286,7 +281,7 @@ pub async fn op_webcrypto_sign_key( hasher.finalize()[..].to_vec(), ) } - WebCryptoHash::Sha384 => { + CryptoHash::Sha384 => { let mut hasher = Sha384::new(); hasher.update(&data); ( @@ -294,7 +289,7 @@ pub async fn op_webcrypto_sign_key( hasher.finalize()[..].to_vec(), ) } - WebCryptoHash::Sha512 => { + CryptoHash::Sha512 => { let mut hasher = Sha512::new(); hasher.update(&data); ( @@ -316,7 +311,7 @@ pub async fn op_webcrypto_sign_key( // https://briansmith.org/rustdoc/ring/signature/index.html#statics if let Some(hash) = args.hash { match hash { - WebCryptoHash::Sha256 | WebCryptoHash::Sha384 => (), + CryptoHash::Sha256 | CryptoHash::Sha384 => (), _ => return Err(type_error("Unsupported algorithm")), } }; diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 14cffcddc2f43c..2b68e84ac8fb28 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -1435,6 +1435,66 @@ "Empty usages: generateKey({length: 256, name: AES-KW}, true, [])" ], "failures_ECDH.https.any.html": [ + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [unwrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, unwrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, unwrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, unwrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, encrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, decrypt])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, sign])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, verify])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, wrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [unwrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, unwrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, unwrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, unwrapKey])", + "Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])", "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [encrypt])", "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, encrypt])", "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, encrypt])", @@ -1465,6 +1525,18 @@ "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, unwrapKey])", "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, unwrapKey])", "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveKey])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveKey])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveBits, deriveKey])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveBits, deriveKey])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveBits])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveBits])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", + "Empty usages: generateKey({name: ECDH, namedCurve: P-256}, false, [])", + "Empty usages: generateKey({name: ECDH, namedCurve: P-384}, false, [])", "Empty usages: generateKey({name: ECDH, namedCurve: P-521}, false, [])", "Empty usages: generateKey({name: ECDH, namedCurve: P-521}, true, [])" ], @@ -1493,10 +1565,25 @@ "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, deriveBits])", "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign, deriveBits])", "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify, deriveBits])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [sign])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, true, [sign])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [verify, sign])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, true, [verify, sign])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, true, [])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [sign, verify, sign, sign, verify])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, true, [sign, verify, sign, sign, verify])", + "Empty usages: generateKey({name: ECDSA, namedCurve: P-256}, false, [])", + "Empty usages: generateKey({name: ECDSA, namedCurve: P-384}, false, [])", "Empty usages: generateKey({name: ECDSA, namedCurve: P-521}, false, [])", "Empty usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [])" ], - "failures_HMAC.https.any.html": true, + "failures_HMAC.https.any.html": [ + "Empty usages: generateKey({hash: SHA-1, length: 160, name: HMAC}, false, [])", + "Empty usages: generateKey({hash: SHA-256, length: 256, name: HMAC}, false, [])", + "Empty usages: generateKey({hash: SHA-384, length: 384, name: HMAC}, false, [])", + "Empty usages: generateKey({hash: SHA-512, length: 512, name: HMAC}, false, [])" + ], "failures_RSA-OAEP.https.any.html": [ "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign])", "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, sign])", @@ -1667,56 +1754,122 @@ "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", - "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])", - "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", - "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])" + "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])" + ], + "failures_RSA-PSS.https.any.html": [ + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, false, [sign])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, false, [verify, sign])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, false, [])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, true, [])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, false, [sign, verify, sign, sign, verify])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [verify, sign])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign, verify, sign, sign, verify])", + "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", + "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])" + ], + "failures_RSASSA-PKCS1-v1_5.https.any.html": [ + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, false, [sign])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, false, [verify, sign])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, false, [])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, true, [])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, false, [sign, verify, sign, sign, verify])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [verify, sign])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [])", + "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign, verify, sign, sign, verify])", + "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", + "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])" ], - "failures_RSA-PSS.https.any.html": true, - "failures_RSASSA-PKCS1-v1_5.https.any.html": true, "successes_AES-CBC.https.any.html": false, "successes_AES-CTR.https.any.html": false, "successes_AES-GCM.https.any.html": false, "successes_AES-KW.https.any.html": false, - "successes_HMAC.https.any.html": true, - "successes_ECDH.https.any.html": [ - "Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveKey])", - "Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey])", - "Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey])", - "Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey])", - "Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveBits])", - "Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits])", - "Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", - "Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", - "Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveKey])", - "Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveKey])", - "Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveBits, deriveKey])", - "Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveBits, deriveKey])", - "Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveBits])", - "Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveBits])", - "Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", - "Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", - "Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveKey])", - "Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveKey])", - "Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveBits, deriveKey])", - "Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveBits, deriveKey])", - "Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveBits])", - "Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveBits])", - "Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", - "Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])" + "successes_HMAC.https.any.html": [ + "Success: generateKey({hash: SHA-1, length: 160, name: HMAC}, false, [sign])", + "Success: generateKey({hash: SHA-1, length: 160, name: HMAC}, false, [verify, sign])", + "Success: generateKey({hash: SHA-1, length: 160, name: HMAC}, false, [verify])", + "Success: generateKey({hash: SHA-1, length: 160, name: HMAC}, false, [sign, verify, sign, verify])", + "Success: generateKey({hash: SHA-256, length: 256, name: HMAC}, false, [sign])", + "Success: generateKey({hash: SHA-256, length: 256, name: HMAC}, false, [verify, sign])", + "Success: generateKey({hash: SHA-256, length: 256, name: HMAC}, false, [verify])", + "Success: generateKey({hash: SHA-256, length: 256, name: HMAC}, false, [sign, verify, sign, verify])", + "Success: generateKey({hash: SHA-384, length: 384, name: HMAC}, false, [sign])", + "Success: generateKey({hash: SHA-384, length: 384, name: HMAC}, false, [verify, sign])", + "Success: generateKey({hash: SHA-384, length: 384, name: HMAC}, false, [verify])", + "Success: generateKey({hash: SHA-384, length: 384, name: HMAC}, false, [sign, verify, sign, verify])", + "Success: generateKey({hash: SHA-512, length: 512, name: HMAC}, false, [sign])", + "Success: generateKey({hash: SHA-512, length: 512, name: HMAC}, false, [verify, sign])", + "Success: generateKey({hash: SHA-512, length: 512, name: HMAC}, false, [verify])", + "Success: generateKey({hash: SHA-512, length: 512, name: HMAC}, false, [sign, verify, sign, verify])", + "Success: generateKey({hash: SHA-1, length: 160, name: hmac}, false, [sign])", + "Success: generateKey({hash: SHA-1, length: 160, name: hmac}, false, [verify, sign])", + "Success: generateKey({hash: SHA-1, length: 160, name: hmac}, false, [verify])", + "Success: generateKey({hash: SHA-1, length: 160, name: hmac}, false, [sign, verify, sign, verify])", + "Success: generateKey({hash: SHA-256, length: 256, name: hmac}, false, [sign])", + "Success: generateKey({hash: SHA-256, length: 256, name: hmac}, false, [verify, sign])", + "Success: generateKey({hash: SHA-256, length: 256, name: hmac}, false, [verify])", + "Success: generateKey({hash: SHA-256, length: 256, name: hmac}, false, [sign, verify, sign, verify])", + "Success: generateKey({hash: SHA-384, length: 384, name: hmac}, false, [sign])", + "Success: generateKey({hash: SHA-384, length: 384, name: hmac}, false, [verify, sign])", + "Success: generateKey({hash: SHA-384, length: 384, name: hmac}, false, [verify])", + "Success: generateKey({hash: SHA-384, length: 384, name: hmac}, false, [sign, verify, sign, verify])", + "Success: generateKey({hash: SHA-512, length: 512, name: hmac}, false, [sign])", + "Success: generateKey({hash: SHA-512, length: 512, name: hmac}, false, [verify, sign])", + "Success: generateKey({hash: SHA-512, length: 512, name: hmac}, false, [verify])", + "Success: generateKey({hash: SHA-512, length: 512, name: hmac}, false, [sign, verify, sign, verify])", + "Success: generateKey({hash: SHA-1, length: 160, name: Hmac}, false, [sign])", + "Success: generateKey({hash: SHA-1, length: 160, name: Hmac}, false, [verify, sign])", + "Success: generateKey({hash: SHA-1, length: 160, name: Hmac}, false, [verify])", + "Success: generateKey({hash: SHA-1, length: 160, name: Hmac}, false, [sign, verify, sign, verify])", + "Success: generateKey({hash: SHA-256, length: 256, name: Hmac}, false, [sign])", + "Success: generateKey({hash: SHA-256, length: 256, name: Hmac}, false, [verify, sign])", + "Success: generateKey({hash: SHA-256, length: 256, name: Hmac}, false, [verify])", + "Success: generateKey({hash: SHA-256, length: 256, name: Hmac}, false, [sign, verify, sign, verify])", + "Success: generateKey({hash: SHA-384, length: 384, name: Hmac}, false, [sign])", + "Success: generateKey({hash: SHA-384, length: 384, name: Hmac}, false, [verify, sign])", + "Success: generateKey({hash: SHA-384, length: 384, name: Hmac}, false, [verify])", + "Success: generateKey({hash: SHA-384, length: 384, name: Hmac}, false, [sign, verify, sign, verify])", + "Success: generateKey({hash: SHA-512, length: 512, name: Hmac}, false, [sign])", + "Success: generateKey({hash: SHA-512, length: 512, name: Hmac}, false, [verify, sign])", + "Success: generateKey({hash: SHA-512, length: 512, name: Hmac}, false, [verify])", + "Success: generateKey({hash: SHA-512, length: 512, name: Hmac}, false, [sign, verify, sign, verify])" ], + "successes_ECDH.https.any.html": false, "successes_ECDSA.https.any.html": [ + "Success: generateKey({name: ECDSA, namedCurve: P-256}, false, [sign])", + "Success: generateKey({name: ECDSA, namedCurve: P-256}, false, [verify, sign])", + "Success: generateKey({name: ECDSA, namedCurve: P-256}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({name: ECDSA, namedCurve: P-384}, false, [sign])", + "Success: generateKey({name: ECDSA, namedCurve: P-384}, false, [verify, sign])", + "Success: generateKey({name: ECDSA, namedCurve: P-384}, false, [sign, verify, sign, sign, verify])", "Success: generateKey({name: ECDSA, namedCurve: P-521}, false, [sign])", "Success: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign])", "Success: generateKey({name: ECDSA, namedCurve: P-521}, false, [verify, sign])", "Success: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign])", "Success: generateKey({name: ECDSA, namedCurve: P-521}, false, [sign, verify, sign, sign, verify])", "Success: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify])", + "Success: generateKey({name: ecdsa, namedCurve: P-256}, false, [sign])", + "Success: generateKey({name: ecdsa, namedCurve: P-256}, false, [verify, sign])", + "Success: generateKey({name: ecdsa, namedCurve: P-256}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({name: ecdsa, namedCurve: P-384}, false, [sign])", + "Success: generateKey({name: ecdsa, namedCurve: P-384}, false, [verify, sign])", + "Success: generateKey({name: ecdsa, namedCurve: P-384}, false, [sign, verify, sign, sign, verify])", "Success: generateKey({name: ecdsa, namedCurve: P-521}, false, [sign])", "Success: generateKey({name: ecdsa, namedCurve: P-521}, true, [sign])", "Success: generateKey({name: ecdsa, namedCurve: P-521}, false, [verify, sign])", "Success: generateKey({name: ecdsa, namedCurve: P-521}, true, [verify, sign])", "Success: generateKey({name: ecdsa, namedCurve: P-521}, false, [sign, verify, sign, sign, verify])", "Success: generateKey({name: ecdsa, namedCurve: P-521}, true, [sign, verify, sign, sign, verify])", + "Success: generateKey({name: Ecdsa, namedCurve: P-256}, false, [sign])", + "Success: generateKey({name: Ecdsa, namedCurve: P-256}, false, [verify, sign])", + "Success: generateKey({name: Ecdsa, namedCurve: P-256}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({name: Ecdsa, namedCurve: P-384}, false, [sign])", + "Success: generateKey({name: Ecdsa, namedCurve: P-384}, false, [verify, sign])", + "Success: generateKey({name: Ecdsa, namedCurve: P-384}, false, [sign, verify, sign, sign, verify])", "Success: generateKey({name: Ecdsa, namedCurve: P-521}, false, [sign])", "Success: generateKey({name: Ecdsa, namedCurve: P-521}, true, [sign])", "Success: generateKey({name: Ecdsa, namedCurve: P-521}, false, [verify, sign])", @@ -1724,8 +1877,6 @@ "Success: generateKey({name: Ecdsa, namedCurve: P-521}, false, [sign, verify, sign, sign, verify])", "Success: generateKey({name: Ecdsa, namedCurve: P-521}, true, [sign, verify, sign, sign, verify])" ], - "successes_RSA-PSS.https.any.html": true, - "successes_RSASSA-PKCS1-v1_5.https.any.html": true, "successes_RSA-OAEP.https.any.html": false, "successes_RSA-OAEP.https.any.html?1-10": false, "successes_RSA-OAEP.https.any.html?101-110": false, @@ -1743,14 +1894,58 @@ "successes_RSA-OAEP.https.any.html?71-80": false, "successes_RSA-OAEP.https.any.html?81-90": false, "successes_RSA-OAEP.https.any.html?91-100": false, - "successes_RSA-PSS.https.any.html?1-10": true, - "successes_RSA-PSS.https.any.html?11-20": true, - "successes_RSA-PSS.https.any.html?21-30": true, - "successes_RSA-PSS.https.any.html?31-last": true, - "successes_RSASSA-PKCS1-v1_5.https.any.html?1-10": true, - "successes_RSASSA-PKCS1-v1_5.https.any.html?11-20": true, - "successes_RSASSA-PKCS1-v1_5.https.any.html?21-30": true, - "successes_RSASSA-PKCS1-v1_5.https.any.html?31-last": true + "successes_RSA-PSS.https.any.html?1-10": [ + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])", + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign])" + ], + "successes_RSA-PSS.https.any.html?11-20": [ + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])" + ], + "successes_RSA-PSS.https.any.html?21-30": [ + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign])", + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify])" + ], + "successes_RSA-PSS.https.any.html?31-last": [ + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])", + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign])", + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify])" + ], + "successes_RSASSA-PKCS1-v1_5.https.any.html?1-10": [ + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-V1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-V1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-V1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-V1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])", + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-V1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign])" + ], + "successes_RSASSA-PKCS1-v1_5.https.any.html?11-20": [ + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-V1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])" + ], + "successes_RSASSA-PKCS1-v1_5.https.any.html?21-30": [ + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign])", + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign])", + "Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify])" + ], + "successes_RSASSA-PKCS1-v1_5.https.any.html?31-last": [ + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])", + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign])", + "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify])" + ] }, "historical.any.html": [ "Non-secure context window does not have access to crypto.subtle", From fb0871e0b2bff0b9cc477867ee171e146982dd4b Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 25 Jun 2021 13:58:58 +0530 Subject: [PATCH 109/130] fix warnings --- extensions/crypto/lib.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index 371821a5920969..9200b8376bfea2 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -1,6 +1,5 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use deno_core::error::bad_resource_id; use deno_core::error::custom_error; use deno_core::error::not_supported; use deno_core::error::null_opbuf; @@ -11,12 +10,9 @@ use deno_core::op_async; use deno_core::op_sync; use deno_core::Extension; use deno_core::OpState; -use deno_core::Resource; use deno_core::ZeroCopyBuf; use serde::Deserialize; -use serde::Serialize; -use std::borrow::Cow; use std::cell::RefCell; use std::convert::TryInto; use std::rc::Rc; @@ -28,8 +24,6 @@ use rand::rngs::StdRng; use rand::thread_rng; use rand::Rng; use rand::SeedableRng; -use ring::agreement::Algorithm as RingAlgorithm; -use ring::agreement::EphemeralPrivateKey; use ring::digest; use ring::hmac::Algorithm as HmacAlgorithm; use ring::hmac::Key as HmacKey; @@ -40,9 +34,7 @@ use ring::signature::EcdsaSigningAlgorithm; use rsa::padding::PaddingScheme; use rsa::BigUint; use rsa::PrivateKeyEncoding; -use rsa::PublicKeyParts; use rsa::RSAPrivateKey; -use rsa::RSAPublicKey; use sha1::Sha1; use sha2::{Digest, Sha256, Sha384, Sha512}; use std::path::PathBuf; @@ -54,7 +46,6 @@ mod key; use crate::key::Algorithm; use crate::key::CryptoHash; use crate::key::CryptoNamedCurve; -use crate::key::KeyUsage; // Whitelist for RSA public exponents. lazy_static! { @@ -123,13 +114,12 @@ pub struct AlgorithmArg { } pub async fn op_crypto_generate_key( - state: Rc>, + _state: Rc>, args: AlgorithmArg, zero_copy: Option, ) -> Result { let algorithm = args.name; - let mut state = state.borrow_mut(); let key = match algorithm { Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss => { let exp = zero_copy.ok_or_else(|| { @@ -196,6 +186,7 @@ pub async fn op_crypto_generate_key( Ok(key.into()) } + #[derive(Deserialize)] #[serde(rename_all = "lowercase")] pub enum KeyFormat { @@ -206,6 +197,8 @@ pub enum KeyFormat { #[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, } @@ -221,7 +214,7 @@ pub struct SignArg { } pub async fn op_crypto_sign_key( - state: Rc>, + _state: Rc>, args: SignArg, zero_copy: Option, ) -> Result { From ae5bdb371e094363950cdb2cd108b69783191d5f Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 25 Jun 2021 14:07:53 +0530 Subject: [PATCH 110/130] fix dlint --- extensions/crypto/01_crypto.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index c5a91b2a1269a7..e1df854acf57a6 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -140,7 +140,7 @@ } function constructKey(algorithm, extractable, usages, type, handle) { - let key = webidl.createBranded(CryptoKey); + const key = webidl.createBranded(CryptoKey); key[_algorithm] = algorithm; key[_extractable] = extractable; key[_usages] = usages; @@ -155,7 +155,7 @@ return a.includes(b) ? [b] : []; } - let keys = []; + const keys = []; class SubtleCrypto { constructor() { From 9eacbfb2b83af3ee5cbab98df52a52c48bcf27be Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 25 Jun 2021 14:25:27 +0530 Subject: [PATCH 111/130] yikes..typo --- extensions/crypto/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index 9200b8376bfea2..f39c213f9ff782 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -191,7 +191,7 @@ pub async fn op_crypto_generate_key( #[serde(rename_all = "lowercase")] pub enum KeyFormat { Raw, - Pcks8, + Pkcs8, } #[derive(Deserialize)] From 1d4463d1378c525834db06d3d98abd90c7498eb7 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 25 Jun 2021 15:10:39 +0530 Subject: [PATCH 112/130] update expectations --- extensions/crypto/01_crypto.js | 4 ++-- tools/wpt/expectation.json | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index e1df854acf57a6..9aaff5e46e823e 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -203,13 +203,13 @@ webidl.assertBranded(this, SubtleCrypto); webidl.requiredArguments(arguments.length, 3); - algorithm = normalizeAlgorithm(algorithm, "sign"); - data = webidl.converters.BufferSource(data, { prefix, context: "Argument 3", }); + algorithm = normalizeAlgorithm(algorithm, "sign"); + const index = key[_handle]; const keyData = keys[index]; diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 2b68e84ac8fb28..13486bc3e4ceac 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -1953,7 +1953,6 @@ "Non-secure context window does not have access to SubtleCrypto" ], "idlharness.https.any.html": [ - "CryptoKey interface object length", "CryptoKey interface: attribute type", "CryptoKey interface: attribute extractable", "CryptoKey interface: attribute algorithm", From e6f386119eb0530fa34e9b068e4bfb68992f911f Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 25 Jun 2021 15:22:12 +0530 Subject: [PATCH 113/130] apply webidl suggestions --- extensions/crypto/00_webidl.js | 33 +------------------------------ extensions/crypto/01_crypto.js | 36 +++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/extensions/crypto/00_webidl.js b/extensions/crypto/00_webidl.js index cf626df4ea083a..e1c0bcff327b6b 100644 --- a/extensions/crypto/00_webidl.js +++ b/extensions/crypto/00_webidl.js @@ -29,31 +29,11 @@ "unwrapKey", ]); - const SupportedHashIdentifiers = [ - "SHA-1", - "SHA-256", - "SHA-384", - "SHA-512", - ]; - - function validateHash(hash) { - const _hash = SupportedHashIdentifiers - .find((key) => key.toLowerCase() == hash.toLowerCase()); - if (_hash == undefined) { - throw new DOMException( - "hash not supported", - "NotSupportedError", - ); - } - } - webidl.converters["HashAlgorithmIdentifier"] = (V, opts) => { if (typeof V == "object") { - validateHash(V.name); return webidl.converters["object"](V, opts); } - validateHash(V); return webidl.converters["DOMString"](V, opts); }; @@ -102,22 +82,11 @@ RsaHashedKeyGenDictionary, ); - const SupportedNamedCurves = ["P-256", "P-384", "P-512"]; const EcKeyGenDictionary = [ ...algorithmDictionary, { key: "namedCurve", - converter: (V, opts) => { - const namedCurve = SupportedNamedCurves - .find((key) => key.toLowerCase() == V.toLowerCase()); - if (namedCurve == undefined) { - throw new DOMException( - "namedCurve not supported", - "NotSupportedError", - ); - } - return webidl.converters["DOMString"](namedCurve, opts); - }, + converter: webidl.converters["DOMString"], required: true, }, ]; diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index 9aaff5e46e823e..e68014e858c82e 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -6,6 +6,14 @@ const webidl = window.__bootstrap.webidl; const { algDict } = window.__bootstrap.crypto; + const supportedNamedCurves = ["P-256", "P-384", "P-512"]; + const supportedHashIdentifiers = [ + "SHA-1", + "SHA-256", + "SHA-384", + "SHA-512", + ]; + const supportedAlgorithms = { "digest": { "SHA-1": {}, @@ -60,6 +68,19 @@ normalizedAlgorithm.name = algorithmName; + if (normalizeAlgorithm.namedCurve) { + const namedCurve = supportedNamedCurves + .find((key) => + key.toLowerCase() == normalizeAlgorithm.namedCurve.toLowerCase() + ); + if (namedCurve == undefined) { + throw new DOMException( + "namedCurve not supported", + "NotSupportedError", + ); + } + } + for (const member of algDict[desiredType]) { const idlValue = normalizedAlgorithm[member.key]; if (member.converters == webidl.converters["BufferSource"]) { @@ -80,6 +101,19 @@ } } + if (normalizeAlgorithm.hash) { + const hash = supportedHashIdentifiers + .find((key) => + key.toLowerCase() == normalizeAlgorithm.hash.toLowerCase() + ); + if (hash == undefined) { + throw new DOMException( + "hash not supported", + "NotSupportedError", + ); + } + } + return normalizedAlgorithm; } @@ -209,7 +243,7 @@ }); algorithm = normalizeAlgorithm(algorithm, "sign"); - + const index = key[_handle]; const keyData = keys[index]; From fb7940e8ddf7aab93d17e0ae4da316b9b77df2a6 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 25 Jun 2021 18:22:12 +0530 Subject: [PATCH 114/130] fixes --- extensions/crypto/00_webidl.js | 2 +- extensions/crypto/01_crypto.js | 45 ++++++++++++---------------------- tools/wpt/expectation.json | 35 +++++++------------------- 3 files changed, 26 insertions(+), 56 deletions(-) diff --git a/extensions/crypto/00_webidl.js b/extensions/crypto/00_webidl.js index e1c0bcff327b6b..4bed815b5ee51d 100644 --- a/extensions/crypto/00_webidl.js +++ b/extensions/crypto/00_webidl.js @@ -190,7 +190,7 @@ window.__bootstrap.crypto = { algDict: { - "RsaHashedKeyGenParams": RsaKeyGenDictionary, + "RsaHashedKeyGenParams": RsaHashedKeyGenDictionary, "EcKeyGenParams": EcKeyGenDictionary, "HmacKeyGenParams": HmacKeyGenDictionary, "RsaPssParams": RsaPssDictionary, diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index e68014e858c82e..b9feda0882989f 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -7,12 +7,6 @@ const { algDict } = window.__bootstrap.crypto; const supportedNamedCurves = ["P-256", "P-384", "P-512"]; - const supportedHashIdentifiers = [ - "SHA-1", - "SHA-256", - "SHA-384", - "SHA-512", - ]; const supportedAlgorithms = { "digest": { @@ -83,37 +77,24 @@ for (const member of algDict[desiredType]) { const idlValue = normalizedAlgorithm[member.key]; - if (member.converters == webidl.converters["BufferSource"]) { + if (member.converter == webidl.converters["BufferSource"]) { normalizedAlgorithm[member.key] = new Uint8Array( ArrayBuffer.isView(idlValue) ? idlValue.buffer : idlValue, ); } else if ( - member.converters == webidl.converters["HashAlgorithmIdentifier"] + member.converter == webidl.converters["HashAlgorithmIdentifier"] ) { normalizedAlgorithm[member.key] = normalizeAlgorithm( idlValue, "digest", ); } else if ( - member.converters == webidl.converters["AlgorithmIdentifier"] + member.converter == webidl.converters["AlgorithmIdentifier"] ) { normalizedAlgorithm[member.key] = normalizeAlgorithm(idlValue, op); } } - if (normalizeAlgorithm.hash) { - const hash = supportedHashIdentifiers - .find((key) => - key.toLowerCase() == normalizeAlgorithm.hash.toLowerCase() - ); - if (hash == undefined) { - throw new DOMException( - "hash not supported", - "NotSupportedError", - ); - } - } - return normalizedAlgorithm; } @@ -237,13 +218,13 @@ webidl.assertBranded(this, SubtleCrypto); webidl.requiredArguments(arguments.length, 3); + algorithm = normalizeAlgorithm(algorithm, "sign"); + data = webidl.converters.BufferSource(data, { prefix, context: "Argument 3", }); - algorithm = normalizeAlgorithm(algorithm, "sign"); - const index = key[_handle]; const keyData = keys[index]; @@ -273,7 +254,7 @@ const signature = await core.opAsync("op_crypto_sign_key", { key: keyData, algorithm: "ECDSA", - hash: algorithm.hash, + hash: algorithm.hash.name, namedCurve, }, data); @@ -360,7 +341,10 @@ // 3. const rawMaterial = await core.opAsync( "op_crypto_generate_key", - algorithm, + { + ...algorithm, + hash: algorithm.hash.name, + }, ); const index = keys.push({ type: "raw", data: rawMaterial }) - 1; @@ -368,7 +352,7 @@ const key = constructKey( { name: "HMAC", - hash: { name: algorithm.hash }, + hash: algorithm.hash, length: algorithm.length, }, extractable, @@ -429,7 +413,10 @@ // 2. const pkcsMaterial = await core.opAsync( "op_crypto_generate_key", - algorithm, + { + ...algorithm, + hash: algorithm.hash.name, + }, algorithm.publicExponent || new Uint8Array(), ); const index = keys.push({ type: "pkcs8", data: pkcsMaterial }) - 1; @@ -439,7 +426,7 @@ name: algorithm.name, modulusLength: algorithm.modulusLength, publicExponent: algorithm.publicExponent, - hash: { name: algorithm.hash }, + hash: algorithm.hash, }; const publicKey = constructKey( alg, diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 13486bc3e4ceac..140ba0db71101d 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -1541,30 +1541,6 @@ "Empty usages: generateKey({name: ECDH, namedCurve: P-521}, true, [])" ], "failures_ECDSA.https.any.html": [ - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [encrypt])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, encrypt])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign, encrypt])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify, encrypt])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [decrypt])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, decrypt])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign, decrypt])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify, decrypt])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [wrapKey])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, wrapKey])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign, wrapKey])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify, wrapKey])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [unwrapKey])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, unwrapKey])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign, unwrapKey])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify, unwrapKey])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [deriveKey])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, deriveKey])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign, deriveKey])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify, deriveKey])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [deriveBits])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, deriveBits])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [verify, sign, deriveBits])", - "Bad usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [sign, verify, sign, sign, verify, deriveBits])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [sign])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, true, [sign])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [verify, sign])", @@ -1573,10 +1549,17 @@ "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, true, [])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [sign, verify, sign, sign, verify])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, true, [sign, verify, sign, sign, verify])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, false, [sign])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, true, [sign])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, false, [verify, sign])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, true, [verify, sign])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, false, [])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, true, [])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, false, [sign, verify, sign, sign, verify])", + "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, true, [sign, verify, sign, sign, verify])", "Empty usages: generateKey({name: ECDSA, namedCurve: P-256}, false, [])", "Empty usages: generateKey({name: ECDSA, namedCurve: P-384}, false, [])", - "Empty usages: generateKey({name: ECDSA, namedCurve: P-521}, false, [])", - "Empty usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [])" + "Empty usages: generateKey({name: ECDSA, namedCurve: P-521}, false, [])" ], "failures_HMAC.https.any.html": [ "Empty usages: generateKey({hash: SHA-1, length: 160, name: HMAC}, false, [])", From 154ba412852142497d9e64a87c6bf8b03997e91f Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 25 Jun 2021 18:40:27 +0530 Subject: [PATCH 115/130] update --- tools/wpt/expectation.json | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 140ba0db71101d..709f544d396be2 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -1535,10 +1535,19 @@ "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [])", "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveKey])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveKey])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveBits, deriveKey])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveBits, deriveKey])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveBits])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveBits])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", + "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", "Empty usages: generateKey({name: ECDH, namedCurve: P-256}, false, [])", "Empty usages: generateKey({name: ECDH, namedCurve: P-384}, false, [])", - "Empty usages: generateKey({name: ECDH, namedCurve: P-521}, false, [])", - "Empty usages: generateKey({name: ECDH, namedCurve: P-521}, true, [])" + "Empty usages: generateKey({name: ECDH, namedCurve: P-521}, false, [])" ], "failures_ECDSA.https.any.html": [ "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [sign])", From 30d12e660fa847ebb89b7e90da1a0279fb130edf Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 25 Jun 2021 21:06:19 +0530 Subject: [PATCH 116/130] sign: normalise after converters --- extensions/crypto/01_crypto.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index b9feda0882989f..345faaaef81560 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -218,13 +218,13 @@ webidl.assertBranded(this, SubtleCrypto); webidl.requiredArguments(arguments.length, 3); - algorithm = normalizeAlgorithm(algorithm, "sign"); - data = webidl.converters.BufferSource(data, { prefix, context: "Argument 3", }); + algorithm = normalizeAlgorithm(algorithm, "sign"); + const index = key[_handle]; const keyData = keys[index]; From dcb2aff1986e4b9875b408bb9a985a61614185c9 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 26 Jun 2021 12:41:37 +0530 Subject: [PATCH 117/130] chore: move converters before algorithm steps --- extensions/crypto/00_webidl.js | 34 ++++------------------------------ extensions/crypto/01_crypto.js | 29 ++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/extensions/crypto/00_webidl.js b/extensions/crypto/00_webidl.js index 4bed815b5ee51d..c39dfecb866f2b 100644 --- a/extensions/crypto/00_webidl.js +++ b/extensions/crypto/00_webidl.js @@ -29,6 +29,10 @@ "unwrapKey", ]); + webidl.converters["sequence"] = webidl.createSequenceConverter( + webidl.converters["KeyUsage"], + ); + webidl.converters["HashAlgorithmIdentifier"] = (V, opts) => { if (typeof V == "object") { return webidl.converters["object"](V, opts); @@ -142,36 +146,6 @@ EcdsaDictionary, ); - const cryptoKeyDictionary = [ - { - key: "type", - converter: webidl.converters["KeyType"], - required: true, - }, - { - key: "extractable", - converter: webidl.converters["boolean"], - required: true, - }, - { - key: "algorithm", - converter: webidl.converters["DOMString"], - required: true, - }, - { - key: "usages", - converter: webidl.createSequenceConverter( - webidl.converters["KeyUsage"], - ), - required: true, - }, - ]; - - webidl.converters["CryptoKey"] = webidl.createDictionaryConverter( - "CryptoKey", - cryptoKeyDictionary, - ); - const cryptoKeyPairDictionary = [ { key: "publicKey", diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index 345faaaef81560..cf2bad8dd4a96a 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -154,6 +154,13 @@ } } + webidl.configurePrototype(CryptoKey); + + webidl.converters["CryptoKey"] = webidl.createInterfaceConverter( + "CryptoKey", + CryptoKey, + ); + function constructKey(algorithm, extractable, usages, type, handle) { const key = webidl.createBranded(CryptoKey); key[_algorithm] = algorithm; @@ -218,6 +225,16 @@ webidl.assertBranded(this, SubtleCrypto); webidl.requiredArguments(arguments.length, 3); + 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", @@ -305,13 +322,23 @@ webidl.assertBranded(this, SubtleCrypto); webidl.requiredArguments(arguments.length, 3); - algorithm = normalizeAlgorithm(algorithm, "generateKey"); + algorithm = webidl.converters.AlgorithmIdentifier(algorithm, { + prefix, + context: "Argument 1", + }); extractable = webidl.converters["boolean"](extractable, { prefix, context: "Argument 2", }); + keyUsages = webidl.converters["sequence"](keyUsages, { + prefix, + context: "Argument 3", + }); + + algorithm = normalizeAlgorithm(algorithm, "generateKey"); + // https://github.com/denoland/deno/pull/9614#issuecomment-866049433 if (!extractable) { throw new DOMException( From a8c2012a5758e3d1d718fa557cf86686f0c8fdeb Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 27 Jun 2021 17:05:12 +0530 Subject: [PATCH 118/130] cleanup --- extensions/crypto/README.md | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/extensions/crypto/README.md b/extensions/crypto/README.md index 26fa7106ddfb02..be07244584e75b 100644 --- a/extensions/crypto/README.md +++ b/extensions/crypto/README.md @@ -3,20 +3,3 @@ This crate implements the Web Cryptography API. Spec: https://www.w3.org/TR/WebCryptoAPI/ - -## Supported algorithms - -SubtleCrypto for Deno is in it's early stages; below is the supported algorithms -and functions. - -| Algorithm name | generateKey | sign | -| --------------------------------------------------------------------- | ------------------ | ------------------ | -| [RSASSA-PKCS1-v1_5](https://www.w3.org/TR/WebCryptoAPI/#rsassa-pkcs1) | :white_check_mark: | :white_check_mark: | -| [RSA-PSS](https://www.w3.org/TR/WebCryptoAPI/#rsa-pss) | :white_check_mark: | :white_check_mark: | -| [RSA-OAEP](https://www.w3.org/TR/WebCryptoAPI/#rsa-oaep) | :white_check_mark: | | -| [ECDSA](https://www.w3.org/TR/WebCryptoAPI/#ecdsa) | :white_check_mark: | :white_check_mark: | -| [ECDH](https://www.w3.org/TR/WebCryptoAPI/#ecdh) | :white_check_mark: | | -| [HMAC](https://www.w3.org/TR/WebCryptoAPI/#hmac) | :white_check_mark: | :white_check_mark: | - -All WebCrypto algorithms can be found -[here](https://www.w3.org/TR/WebCryptoAPI/#algorithm-overview). From e6b5dcff21f05affb9e634fc33d56b108b9d2384 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 29 Jun 2021 15:46:43 +0530 Subject: [PATCH 119/130] re run CI From a1727820e9ccc0ff353ece96e0671379bd8b1644 Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Thu, 1 Jul 2021 16:41:01 +0200 Subject: [PATCH 120/130] rework js glue code --- extensions/crypto/00_crypto.js | 653 +++++++++++++++++++++++++++++++++ extensions/crypto/00_webidl.js | 174 --------- extensions/crypto/01_crypto.js | 549 --------------------------- extensions/crypto/01_webidl.js | 161 ++++++++ extensions/crypto/lib.rs | 17 +- 5 files changed, 821 insertions(+), 733 deletions(-) create mode 100644 extensions/crypto/00_crypto.js delete mode 100644 extensions/crypto/00_webidl.js delete mode 100644 extensions/crypto/01_crypto.js create mode 100644 extensions/crypto/01_webidl.js diff --git a/extensions/crypto/00_crypto.js b/extensions/crypto/00_crypto.js new file mode 100644 index 00000000000000..1d71acdd4b7351 --- /dev/null +++ b/extensions/crypto/00_crypto.js @@ -0,0 +1,653 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +// @ts-check +/// +/// +/// + +"use strict"; + +((window) => { + const core = window.Deno.core; + const webidl = window.__bootstrap.webidl; + + const supportedNamedCurves = ["P-256", "P-384", "P-512"]; + + const simpleAlgorithmDictionaries = { + RsaHashedKeyGenParams: { hash: "HashAlgorithmIdentifier" }, + EcKeyGenParams: {}, + HmacKeyGenParams: { hash: "HashAlgorithmIdentifier" }, + RsaPssParams: {}, + EcdsaParams: { 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", + "RSA-OAEP": "RsaHashedKeyGenParams", + "ECDSA": "EcKeyGenParams", + "ECDH": "EcKeyGenParams", + "HMAC": "HmacKeyGenParams", + }, + "sign": { + "RSASSA-PKCS1-v1_5": null, + "RSA-PSS": "RsaPssParams", + "ECDSA": "EcdsaParams", + "HMAC": null, + }, + }; + + // 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 (key.toLowerCase() === algName.toLowerCase()) { + 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( + (ArrayBuffer.isView(idlValue) ? idlValue.buffer : idlValue).slice( + 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; + } + + // Should match op_crypto_subtle_digest() in extensions/crypto/lib.rs + function digestToId(name) { + switch (name) { + case "SHA-1": + return 0; + case "SHA-256": + return 1; + case "SHA-384": + return 2; + case "SHA-512": + return 3; + } + } + + 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 [Symbol.toStringTag]() { + return "CryptoKey"; + } + + [Symbol.for("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 + // TODO(littledivy): When the need arises, make `b` a list. + /** + * @param {string[]} a + * @param {string} b + * @returns + */ + function usageIntersection(a, b) { + return a.includes(b) ? [b] : []; + } + + // TODO(lucacasonato): this should be moved to rust + /** @type {WeakMap} */ + const KEY_STORE = new WeakMap(); + + class SubtleCrypto { + constructor() { + webidl.illegalConstructor(); + } + + /** + * @param {string} algorithm + * @param {BufferSource} data + * @returns {Promise} + */ + 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 (ArrayBuffer.isView(data)) { + data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + } else { + data = new Uint8Array(data); + } + data = data.slice(); + + algorithm = normalizeAlgorithm(algorithm, "digest"); + + const result = await core.opAsync( + "op_crypto_subtle_digest", + digestToId(algorithm.name), + data, + ); + + return result.buffer; + } + + /** + * @param {string} algorithm + * @param {CryptoKey} key + * @param {BufferSource} data + * @returns {Promise} + */ + 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 (ArrayBuffer.isView(data)) { + data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + } else { + data = new Uint8Array(data); + } + data = data.slice(); + + // 2. + const normalizedAlgorithm = normalizeAlgorithm(algorithm, "sign"); + + const handle = key[_handle]; + const keyData = KEY_STORE.get(handle); + + // 8. + if (normalizedAlgorithm.name !== key[_algorithm].name) { + throw new DOMException( + "Signing algorithm doesn't match key algorithm.", + "InvalidAccessError", + ); + } + + // 9. + if (!normalizeAlgorithm[_usages].includes("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 (!supportedNamedCurves.includes(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} algorithm + * @param {boolean} extractable + * @param {KeyUsage[]} keyUsages + * @returns {Promise} + */ + 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"](keyUsages, { + prefix, + context: "Argument 3", + }); + + // https://github.com/denoland/deno/pull/9614#issuecomment-866049433 + if (!extractable) { + throw new DOMException( + "Non-extractable keys are not supported", + "SecurityError", + ); + } + + const normalizedAlgorithm = normalizeAlgorithm(algorithm, "generateKey"); + + switch (normalizedAlgorithm.name) { + case "RSASSA-PKCS1-v1_5": + case "RSA-PSS": { + // 1. + if (keyUsages.find((u) => !["sign", "verify"].includes(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 = {}; + KEY_STORE.set(handle, { type: "pkcs8", data: keyData }); + + // 4-8. + const algorithm = { + name: normalizedAlgorithm.name, + modulusLength: normalizedAlgorithm.modulusLength, + publicExponent: normalizedAlgorithm.publicExponent, + hash: normalizedAlgorithm.hash, + }; + + // 9-13. + let publicKey = constructKey( + "public", + true, + usageIntersection(keyUsages, "verify"), + algorithm, + handle, + ); + + // 14-18. + let privateKey = constructKey( + "private", + extractable, + usageIntersection(keyUsages, "sign"), + algorithm, + handle, + ); + + // 19-22. + return { publicKey, privateKey }; + } + // TODO(lucacasonato): RSA-OAEP + case "ECDSA": { + // 1. + if (keyUsages.find((u) => !["sign", "verify"].includes(u)) !== undefined) { + throw new DOMException("Invalid key usages", "SyntaxError"); + } + + // 2-3. + const handle = {}; + if (supportedNamedCurves.includes(normalizedAlgorithm.namedCurve)) { + const keyData = await core.opAsync("op_crypto_generate_key", { + name: "ECDSA", + namedCurve: normalizedAlgorithm.namedCurve, + }); + KEY_STORE.set(handle, { type: "pkcs8", data: keyData }); + } else { + throw new DOMException("Curve not supported", "NotSupportedError"); + } + + // 4-6. + const algorithm = { + name: "ECDSA", + namedCurve: normalizedAlgorithm.namedCurve, + }; + + // 7-11. + let publicKey = constructKey( + "public", + true, + usageIntersection(keyUsages, "verify"), + algorithm, + handle, + ); + + // 12-16. + let privateKey = constructKey( + "private", + extractable, + usageIntersection(keyUsages, "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 ( + keyUsages.find((u) => !["sign", "verify"].includes(u)) !== undefined + ) { + throw new DOMException("Invalid key usages", "SyntaxError"); + } + + // 2. + if (normalizedAlgorithm.length === undefined) { + // We don't support custom key length + } else if (normalizedAlgorithm.length !== 0) { + throw new DOMException( + "Custom key lengths are not supported", + "NotSupportedError", + ); + } else { + throw new DOMException("Invalid length", "OperationError"); + } + + // 3-4. + const keyData = await core.opAsync("op_crypto_generate_key", { + name: "HMAC", + hash: normalizedAlgorithm.hash.name, + }); + const handle = {}; + KEY_STORE.set(handle, { type: "raw", data: keyData }); + + // 6-10. + const algorithm = { + name: "HMAC", + hash: { + name: normalizedAlgorithm.hash.name, + }, + length: keyData.byteLength, + }; + + // 5, 11-13. + const key = constructKey( + "secret", + extractable, + keyUsages, + 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 Int16Array || + arrayBufferView instanceof Uint16Array || + arrayBufferView instanceof Int32Array || + arrayBufferView instanceof Uint32Array || + arrayBufferView instanceof Uint8ClampedArray + ) + ) { + 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 [Symbol.toStringTag]() { + return "Crypto"; + } + + [Symbol.for("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/00_webidl.js b/extensions/crypto/00_webidl.js deleted file mode 100644 index c39dfecb866f2b..00000000000000 --- a/extensions/crypto/00_webidl.js +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -"use strict"; - -((window) => { - const webidl = window.__bootstrap.webidl; - webidl.converters["AlgorithmIdentifier"] = (V, opts) => { - // Union for (object or DOMString) - if (typeof 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["KeyUsage"] = webidl.createEnumConverter("KeyUsage", [ - "encrypt", - "decrypt", - "sign", - "verify", - "deriveKey", - "deriveBits", - "wrapKey", - "unwrapKey", - ]); - - webidl.converters["sequence"] = webidl.createSequenceConverter( - webidl.converters["KeyUsage"], - ); - - webidl.converters["HashAlgorithmIdentifier"] = (V, opts) => { - if (typeof V == "object") { - return webidl.converters["object"](V, opts); - } - - return webidl.converters["DOMString"](V, opts); - }; - - const algorithmDictionary = [ - { - key: "name", - converter: webidl.converters["DOMString"], - }, - ]; - - webidl.converters["Algorithm"] = webidl.createDictionaryConverter( - "Algorithm", - algorithmDictionary, - ); - - const RsaKeyGenDictionary = [ - ...algorithmDictionary, - { - key: "publicExponent", - converter: webidl.converters["BufferSource"], - required: true, - }, - { - key: "modulusLength", - converter: webidl.converters["unsigned long"], - required: true, - }, - ]; - - webidl.converters["RsaKeyGenParams"] = webidl.createDictionaryConverter( - "RsaKeyGenParams", - RsaKeyGenDictionary, - ); - - const RsaHashedKeyGenDictionary = [ - ...RsaKeyGenDictionary, - { - key: "hash", - converter: webidl.converters["HashAlgorithmIdentifier"], - required: true, - }, - ]; - - webidl.converters["RsaHashedKeyGenParams"] = webidl.createDictionaryConverter( - "RsaHashedKeyGenParams", - RsaHashedKeyGenDictionary, - ); - - const EcKeyGenDictionary = [ - ...algorithmDictionary, - { - key: "namedCurve", - converter: webidl.converters["DOMString"], - required: true, - }, - ]; - - webidl.converters["EcKeyGenParams"] = webidl.createDictionaryConverter( - "EcKeyGenParams", - EcKeyGenDictionary, - ); - - const HmacKeyGenDictionary = [ - ...algorithmDictionary, - { - key: "hash", - converter: webidl.converters["HashAlgorithmIdentifier"], - required: true, - }, - { - key: "length", - converter: webidl.converters["unsigned long"], - }, - ]; - - webidl.converters["HmacKeyGenParams"] = webidl.createDictionaryConverter( - "HmacKeyGenParams", - HmacKeyGenDictionary, - ); - - const RsaPssDictionary = [ - ...algorithmDictionary, - { - key: "saltLength", - converter: webidl.converters["unsigned long"], - required: true, - }, - ]; - - webidl.converters["RsaPssParams"] = webidl.createDictionaryConverter( - "RsaPssParams", - RsaPssDictionary, - ); - - const EcdsaDictionary = [ - ...algorithmDictionary, - { - key: "hash", - converter: webidl.converters["HashAlgorithmIdentifier"], - required: true, - }, - ]; - - webidl.converters["EcdsaParams"] = webidl.createDictionaryConverter( - "EcdsaParams", - EcdsaDictionary, - ); - - const cryptoKeyPairDictionary = [ - { - key: "publicKey", - converter: webidl.converters["CryptoKey"], - }, - { - key: "privateKey", - converter: webidl.converters["CryptoKey"], - }, - ]; - - webidl.converters["CryptoKeyPair"] = webidl.createDictionaryConverter( - "CryptoKeyPair", - cryptoKeyPairDictionary, - ); - - window.__bootstrap.crypto = { - algDict: { - "RsaHashedKeyGenParams": RsaHashedKeyGenDictionary, - "EcKeyGenParams": EcKeyGenDictionary, - "HmacKeyGenParams": HmacKeyGenDictionary, - "RsaPssParams": RsaPssDictionary, - "EcdsaParams": EcdsaDictionary, - }, - }; -})(this); diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js deleted file mode 100644 index cf2bad8dd4a96a..00000000000000 --- a/extensions/crypto/01_crypto.js +++ /dev/null @@ -1,549 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -"use strict"; - -((window) => { - const core = window.Deno.core; - const webidl = window.__bootstrap.webidl; - const { algDict } = window.__bootstrap.crypto; - - const supportedNamedCurves = ["P-256", "P-384", "P-512"]; - - const supportedAlgorithms = { - "digest": { - "SHA-1": {}, - "SHA-256": {}, - "SHA-384": {}, - "SHA-512": {}, - }, - "generateKey": { - "RSASSA-PKCS1-v1_5": "RsaHashedKeyGenParams", - "RSA-PSS": "RsaHashedKeyGenParams", - "RSA-OAEP": "RsaHashedKeyGenParams", - "ECDSA": "EcKeyGenParams", - "ECDH": "EcKeyGenParams", - "HMAC": "HmacKeyGenParams", - }, - "sign": { - "RSASSA-PKCS1-v1_5": {}, - "RSA-PSS": "RsaPssParams", - "ECDSA": "EcdsaParams", - "HMAC": {}, - }, - }; - - // See https://www.w3.org/TR/WebCryptoAPI/#dfn-normalize-an-algorithm - function normalizeAlgorithm(algorithm, op) { - if (typeof algorithm == "string") { - return normalizeAlgorithm({ name: algorithm }, op); - } - - const initialAlgorithm = webidl.converters["Algorithm"](algorithm, { - context: "Argument 1", - }); - - const registeredAlgorithms = supportedAlgorithms[op]; - const algorithmName = Object.keys(registeredAlgorithms) - .find((key) => key.toLowerCase() == initialAlgorithm.name.toLowerCase()); - - if (algorithmName === undefined) { - throw new DOMException( - "Unrecognized algorithm name", - "NotSupportedError", - ); - } - - const desiredType = registeredAlgorithms[algorithmName]; - - if (typeof desiredType !== "string") { - return { name: algorithmName }; - } - - const normalizedAlgorithm = webidl.converters[desiredType](algorithm, {}); - - normalizedAlgorithm.name = algorithmName; - - if (normalizeAlgorithm.namedCurve) { - const namedCurve = supportedNamedCurves - .find((key) => - key.toLowerCase() == normalizeAlgorithm.namedCurve.toLowerCase() - ); - if (namedCurve == undefined) { - throw new DOMException( - "namedCurve not supported", - "NotSupportedError", - ); - } - } - - for (const member of algDict[desiredType]) { - const idlValue = normalizedAlgorithm[member.key]; - if (member.converter == webidl.converters["BufferSource"]) { - normalizedAlgorithm[member.key] = new Uint8Array( - ArrayBuffer.isView(idlValue) ? idlValue.buffer : idlValue, - ); - } else if ( - member.converter == webidl.converters["HashAlgorithmIdentifier"] - ) { - normalizedAlgorithm[member.key] = normalizeAlgorithm( - idlValue, - "digest", - ); - } else if ( - member.converter == webidl.converters["AlgorithmIdentifier"] - ) { - normalizedAlgorithm[member.key] = normalizeAlgorithm(idlValue, op); - } - } - - return normalizedAlgorithm; - } - - // Should match op_crypto_subtle_digest() in extensions/crypto/lib.rs - function digestToId(name) { - switch (name) { - case "SHA-1": - return 0; - case "SHA-256": - return 1; - case "SHA-384": - return 2; - case "SHA-512": - return 3; - } - } - - const _handle = Symbol("[[handle]]"); - const _algorithm = Symbol("[[algorithm]]"); - const _extractable = Symbol("[[extractable]]"); - const _usages = Symbol("[[usages]]"); - const _type = Symbol("[[type]]"); - - class CryptoKey { - [_usages]; - [_algorithm]; - [_extractable]; - [_type]; - [_handle]; - - constructor() { - webidl.illegalConstructor(); - } - - get usages() { - return this[_usages]; - } - - get extractable() { - return this[_extractable]; - } - - get algorithm() { - return this[_algorithm]; - } - - get type() { - return this[_type]; - } - - get [Symbol.toStringTag]() { - return "CryptoKey"; - } - - [Symbol.for("Deno.customInspect")](inspect) { - return `${this.constructor.name} ${inspect({})}`; - } - } - - webidl.configurePrototype(CryptoKey); - - webidl.converters["CryptoKey"] = webidl.createInterfaceConverter( - "CryptoKey", - CryptoKey, - ); - - function constructKey(algorithm, extractable, usages, type, handle) { - const key = webidl.createBranded(CryptoKey); - key[_algorithm] = algorithm; - key[_extractable] = extractable; - key[_usages] = usages; - key[_type] = type; - key[_handle] = handle; - return key; - } - - // https://w3c.github.io/webcrypto/#concept-usage-intersection - // TODO(littledivy): When the need arises, make `b` a list. - function usageIntersection(a, b) { - return a.includes(b) ? [b] : []; - } - - const keys = []; - - class SubtleCrypto { - constructor() { - webidl.illegalConstructor(); - } - - async digest(algorithm, data) { - const prefix = "Failed to execute 'digest' on 'SubtleCrypto'"; - - webidl.assertBranded(this, SubtleCrypto); - webidl.requiredArguments(arguments.length, 2); - - algorithm = webidl.converters.AlgorithmIdentifier(algorithm, { - prefix, - context: "Argument 1", - }); - - data = webidl.converters.BufferSource(data, { - prefix, - context: "Argument 2", - }); - - if (ArrayBuffer.isView(data)) { - data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); - } else { - data = new Uint8Array(data); - } - - data = data.slice(); - - algorithm = normalizeAlgorithm(algorithm, "digest"); - - const result = await core.opAsync( - "op_crypto_subtle_digest", - digestToId(algorithm.name), - data, - ); - - return result.buffer; - } - - async sign(algorithm, key, data) { - const prefix = "Failed to execute 'sign' on 'SubtleCrypto'"; - - webidl.assertBranded(this, SubtleCrypto); - webidl.requiredArguments(arguments.length, 3); - - 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", - }); - - algorithm = normalizeAlgorithm(algorithm, "sign"); - - const index = key[_handle]; - const keyData = keys[index]; - - data = new Uint8Array(ArrayBuffer.isView(data) ? data.buffer : data); - - if (algorithm.name == "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; - } else if (algorithm.name == "ECDSA") { - // 1. - if (key[_type] !== "private") { - throw new DOMException( - "Key type not supported", - "InvalidAccessError", - ); - } - - const namedCurve = key[_algorithm].namedCurve; - // 2 to 6. - const signature = await core.opAsync("op_crypto_sign_key", { - key: keyData, - algorithm: "ECDSA", - hash: algorithm.hash.name, - namedCurve, - }, data); - - return signature; - } else if (algorithm.name == "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: algorithm.saltLength, - }, data); - - return signature; - } else if (algorithm.name == "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; - } - } - - async generateKey(algorithm, extractable, keyUsages) { - const prefix = "Failed to execute 'generateKey' on 'SubtleCrypto'"; - - webidl.assertBranded(this, SubtleCrypto); - webidl.requiredArguments(arguments.length, 3); - - algorithm = webidl.converters.AlgorithmIdentifier(algorithm, { - prefix, - context: "Argument 1", - }); - - extractable = webidl.converters["boolean"](extractable, { - prefix, - context: "Argument 2", - }); - - keyUsages = webidl.converters["sequence"](keyUsages, { - prefix, - context: "Argument 3", - }); - - algorithm = normalizeAlgorithm(algorithm, "generateKey"); - - // https://github.com/denoland/deno/pull/9614#issuecomment-866049433 - if (!extractable) { - throw new DOMException( - "Extractable keys are not supported", - "SecurityError", - ); - } - - if (keyUsages.length == 0) { - throw new SyntaxError("Usages must not be empty"); - } - - if (algorithm.name == "HMAC") { - // 1. - const illegal = keyUsages.find((usage) => - !["sign", "verify"].includes(usage) - ); - if (illegal) { - throw new SyntaxError("Invalid usage"); - } - - // 2. - if (algorithm.length == 0) { - throw new DOMException("Invalid key length", "OperationError"); - } - - // 3. - const rawMaterial = await core.opAsync( - "op_crypto_generate_key", - { - ...algorithm, - hash: algorithm.hash.name, - }, - ); - const index = keys.push({ type: "raw", data: rawMaterial }) - 1; - - // 11 to 13. - const key = constructKey( - { - name: "HMAC", - hash: algorithm.hash, - length: algorithm.length, - }, - extractable, - keyUsages, - "secret", - index, - ); - - // 14. - return key; - } else if (algorithm.name == "ECDSA") { - // 1. - const illegal = keyUsages.find((usage) => - !["sign", "verify"].includes(usage) - ); - if (illegal) { - throw new SyntaxError("Invalid usage"); - } - - // 3. - const pkcsMaterial = await core.opAsync( - "op_crypto_generate_key", - algorithm, - ); - const index = keys.push({ type: "pkcs8", data: pkcsMaterial }) - 1; - - const alg = { name: "ECDSA", namedCurve: algorithm.namedCurve }; - const publicKey = constructKey( - alg, - extractable, - usageIntersection(keyUsages, "verify"), - "public", - index, - ); - const privateKey = constructKey( - alg, - extractable, - usageIntersection(keyUsages, "sign"), - "private", - index, - ); - - return { - publicKey, - privateKey, - }; - } else if ( - algorithm.name == "RSA-PSS" || algorithm.name == "RSASSA-PKCS1-v1_5" - ) { - // 1. - const illegal = keyUsages.find((usage) => - !["sign", "verify"].includes(usage) - ); - if (illegal) { - throw new SyntaxError("Invalid usage"); - } - - // 2. - const pkcsMaterial = await core.opAsync( - "op_crypto_generate_key", - { - ...algorithm, - hash: algorithm.hash.name, - }, - algorithm.publicExponent || new Uint8Array(), - ); - const index = keys.push({ type: "pkcs8", data: pkcsMaterial }) - 1; - - // 4 to 8. - const alg = { - name: algorithm.name, - modulusLength: algorithm.modulusLength, - publicExponent: algorithm.publicExponent, - hash: algorithm.hash, - }; - const publicKey = constructKey( - alg, - extractable, - usageIntersection(keyUsages, "verify"), - "public", - index, - ); - const privateKey = constructKey( - alg, - extractable, - usageIntersection(keyUsages, "sign"), - "private", - index, - ); - - // 19 to 22. - return { - publicKey, - privateKey, - }; - } - } - } - - 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 Int16Array || - arrayBufferView instanceof Uint16Array || - arrayBufferView instanceof Int32Array || - arrayBufferView instanceof Uint32Array || - arrayBufferView instanceof Uint8ClampedArray - ) - ) { - 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 [Symbol.toStringTag]() { - return "Crypto"; - } - - [Symbol.for("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 new file mode 100644 index 00000000000000..30bf66c4b73073 --- /dev/null +++ b/extensions/crypto/01_webidl.js @@ -0,0 +1,161 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +// @ts-check +/// +/// + +"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.KeyUsage = webidl.createEnumConverter("KeyUsage", [ + "encrypt", + "decrypt", + "sign", + "verify", + "deriveKey", + "deriveBits", + "wrapKey", + "unwrapKey", + ]); + + webidl.converters["sequence"] = 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); + + webidl.converters.CryptoKey = webidl.createInterfaceConverter(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/lib.rs b/extensions/crypto/lib.rs index f39c213f9ff782..b8965b7cf178ed 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -57,8 +57,8 @@ pub fn init(maybe_seed: Option) -> Extension { Extension::builder() .js(include_js_files!( prefix "deno:extensions/crypto", - "00_webidl.js", - "01_crypto.js", + "00_crypto.js", + "01_webidl.js", )) .ops(vec![ ( @@ -107,27 +107,24 @@ pub fn op_crypto_get_random_values( pub struct AlgorithmArg { name: Algorithm, modulus_length: Option, - hash: Option, - #[allow(dead_code)] - length: Option, + public_exponent: Option, named_curve: Option, + hash: Option, } pub async fn op_crypto_generate_key( _state: Rc>, args: AlgorithmArg, - zero_copy: Option, + _: (), ) -> Result { let algorithm = args.name; let key = match algorithm { Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss => { - let exp = zero_copy.ok_or_else(|| { - type_error("Missing argument publicExponent".to_string()) - })?; + 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(&exp); + let exponent = BigUint::from_bytes_be(&public_exponent); if exponent != *PUB_EXPONENT_1 && exponent != *PUB_EXPONENT_2 { return Err(custom_error( "DOMExceptionOperationError", From 8911678919d678eb8af4ebb97d0131b5e072f5d4 Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Fri, 2 Jul 2021 18:33:05 +0200 Subject: [PATCH 121/130] wip --- extensions/crypto/00_crypto.js | 25 +++++++++-------- extensions/crypto/lib.rs | 18 +++++++++++-- tools/wpt/expectation.json | 49 +++++++++++++++++----------------- 3 files changed, 55 insertions(+), 37 deletions(-) diff --git a/extensions/crypto/00_crypto.js b/extensions/crypto/00_crypto.js index 1d71acdd4b7351..137a8de3896133 100644 --- a/extensions/crypto/00_crypto.js +++ b/extensions/crypto/00_crypto.js @@ -309,7 +309,7 @@ } // 9. - if (!normalizeAlgorithm[_usages].includes("sign")) { + if (!key[_usages].includes("sign")) { throw new DOMException( "Key does not support the 'sign' operation.", "InvalidAccessError", @@ -420,6 +420,8 @@ context: "Argument 3", }); + const normalizedAlgorithm = normalizeAlgorithm(algorithm, "generateKey"); + // https://github.com/denoland/deno/pull/9614#issuecomment-866049433 if (!extractable) { throw new DOMException( @@ -428,13 +430,13 @@ ); } - const normalizedAlgorithm = normalizeAlgorithm(algorithm, "generateKey"); - switch (normalizedAlgorithm.name) { case "RSASSA-PKCS1-v1_5": case "RSA-PSS": { // 1. - if (keyUsages.find((u) => !["sign", "verify"].includes(u)) !== undefined) { + if ( + keyUsages.find((u) => !["sign", "verify"].includes(u)) !== undefined + ) { throw new DOMException("Invalid key usages", "SyntaxError"); } @@ -482,7 +484,9 @@ // TODO(lucacasonato): RSA-OAEP case "ECDSA": { // 1. - if (keyUsages.find((u) => !["sign", "verify"].includes(u)) !== undefined) { + if ( + keyUsages.find((u) => !["sign", "verify"].includes(u)) !== undefined + ) { throw new DOMException("Invalid key usages", "SyntaxError"); } @@ -539,13 +543,11 @@ } // 2. + let length; if (normalizedAlgorithm.length === undefined) { - // We don't support custom key length + length = null; } else if (normalizedAlgorithm.length !== 0) { - throw new DOMException( - "Custom key lengths are not supported", - "NotSupportedError", - ); + length = normalizedAlgorithm.length; } else { throw new DOMException("Invalid length", "OperationError"); } @@ -554,6 +556,7 @@ const keyData = await core.opAsync("op_crypto_generate_key", { name: "HMAC", hash: normalizedAlgorithm.hash.name, + length, }); const handle = {}; KEY_STORE.set(handle, { type: "raw", data: keyData }); @@ -564,7 +567,7 @@ hash: { name: normalizedAlgorithm.hash.name, }, - length: keyData.byteLength, + length: keyData.byteLength * 8, }; // 5, 11-13. diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index b8965b7cf178ed..dfff315ec1807f 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -110,6 +110,7 @@ pub struct AlgorithmArg { public_exponent: Option, named_curve: Option, hash: Option, + length: Option, } pub async fn op_crypto_generate_key( @@ -171,9 +172,22 @@ pub async fn op_crypto_generate_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(type_error("hmac block length must be byte aligned")); + } + let length = length / 8; + if length > ring::digest::MAX_BLOCK_LEN { + return Err(type_error("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_OUTPUT_LEN]; - let key_bytes = &mut key_bytes[..hash.digest_algorithm().output_len]; + let mut key_bytes = [0; ring::digest::MAX_BLOCK_LEN]; + let key_bytes = &mut key_bytes[..length]; rng.fill(key_bytes)?; key_bytes.to_vec() diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index f34e4f174767a2..965ff44f1c9660 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -25,7 +25,8 @@ "aes_cbc.https.any.html": false, "aes_ctr.https.any.html": false, "aes_gcm.https.any.html": false, - "rsa.https.any.html": false + "rsa.https.any.html": false, + "rsa_oaep.https.any.html": false }, "generateKey": { "failures_AES-CBC.https.any.html": [ @@ -1546,8 +1547,11 @@ "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", "Empty usages: generateKey({name: ECDH, namedCurve: P-256}, false, [])", + "Empty usages: generateKey({name: ECDH, namedCurve: P-256}, true, [])", "Empty usages: generateKey({name: ECDH, namedCurve: P-384}, false, [])", - "Empty usages: generateKey({name: ECDH, namedCurve: P-521}, false, [])" + "Empty usages: generateKey({name: ECDH, namedCurve: P-384}, true, [])", + "Empty usages: generateKey({name: ECDH, namedCurve: P-521}, false, [])", + "Empty usages: generateKey({name: ECDH, namedCurve: P-521}, true, [])" ], "failures_ECDSA.https.any.html": [ "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [sign])", @@ -1559,22 +1563,25 @@ "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [sign, verify, sign, sign, verify])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, true, [sign, verify, sign, sign, verify])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, false, [sign])", - "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, true, [sign])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, false, [verify, sign])", - "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, true, [verify, sign])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, false, [])", - "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, true, [])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, false, [sign, verify, sign, sign, verify])", - "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, true, [sign, verify, sign, sign, verify])", "Empty usages: generateKey({name: ECDSA, namedCurve: P-256}, false, [])", + "Empty usages: generateKey({name: ECDSA, namedCurve: P-256}, true, [])", "Empty usages: generateKey({name: ECDSA, namedCurve: P-384}, false, [])", - "Empty usages: generateKey({name: ECDSA, namedCurve: P-521}, false, [])" + "Empty usages: generateKey({name: ECDSA, namedCurve: P-384}, true, [])", + "Empty usages: generateKey({name: ECDSA, namedCurve: P-521}, false, [])", + "Empty usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [])" ], "failures_HMAC.https.any.html": [ "Empty usages: generateKey({hash: SHA-1, length: 160, name: HMAC}, false, [])", + "Empty usages: generateKey({hash: SHA-1, length: 160, name: HMAC}, true, [])", "Empty usages: generateKey({hash: SHA-256, length: 256, name: HMAC}, false, [])", + "Empty usages: generateKey({hash: SHA-256, length: 256, name: HMAC}, true, [])", "Empty usages: generateKey({hash: SHA-384, length: 384, name: HMAC}, false, [])", - "Empty usages: generateKey({hash: SHA-512, length: 512, name: HMAC}, false, [])" + "Empty usages: generateKey({hash: SHA-384, length: 384, name: HMAC}, true, [])", + "Empty usages: generateKey({hash: SHA-512, length: 512, name: HMAC}, false, [])", + "Empty usages: generateKey({hash: SHA-512, length: 512, name: HMAC}, true, [])" ], "failures_RSA-OAEP.https.any.html": [ "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign])", @@ -1746,35 +1753,37 @@ "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey])", "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", - "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])" + "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])", + "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", + "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])" ], "failures_RSA-PSS.https.any.html": [ "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, false, [sign])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, false, [verify, sign])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, false, [])", - "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, true, [])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, false, [sign, verify, sign, sign, verify])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [verify, sign])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [])", - "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign, verify, sign, sign, verify])", "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", - "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])" + "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])", + "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", + "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])" ], "failures_RSASSA-PKCS1-v1_5.https.any.html": [ "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, false, [sign])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, false, [verify, sign])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, false, [])", - "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, true, [])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, false, [sign, verify, sign, sign, verify])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [verify, sign])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [])", - "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign, verify, sign, sign, verify])", "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", - "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])" + "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])", + "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", + "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])" ], "successes_AES-CBC.https.any.html": false, "successes_AES-CTR.https.any.html": false, @@ -1939,16 +1948,8 @@ "Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify])" ] }, - "historical.any.html": [ - "Non-secure context window does not have access to crypto.subtle", - "Non-secure context window does not have access to CryptoKey", - "Non-secure context window does not have access to SubtleCrypto" - ], + "historical.any.html": false, "idlharness.https.any.html": [ - "CryptoKey interface: attribute type", - "CryptoKey interface: attribute extractable", - "CryptoKey interface: attribute algorithm", - "CryptoKey interface: attribute usages", "SubtleCrypto interface: operation encrypt(AlgorithmIdentifier, CryptoKey, BufferSource)", "SubtleCrypto interface: operation decrypt(AlgorithmIdentifier, CryptoKey, BufferSource)", "SubtleCrypto interface: operation sign(AlgorithmIdentifier, CryptoKey, BufferSource)", From aa62b79291aa9c53f31b0b070deaf2bb54549bc2 Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Fri, 2 Jul 2021 19:13:00 +0200 Subject: [PATCH 122/130] fixes --- extensions/crypto/00_crypto.js | 302 +++++++++++++++++---------------- extensions/crypto/key.rs | 5 - extensions/crypto/lib.rs | 21 ++- tools/wpt/expectation.json | 40 +---- 4 files changed, 179 insertions(+), 189 deletions(-) diff --git a/extensions/crypto/00_crypto.js b/extensions/crypto/00_crypto.js index 137a8de3896133..f73e93be2ccf07 100644 --- a/extensions/crypto/00_crypto.js +++ b/extensions/crypto/00_crypto.js @@ -11,7 +11,8 @@ const core = window.Deno.core; const webidl = window.__bootstrap.webidl; - const supportedNamedCurves = ["P-256", "P-384", "P-512"]; + // P-521 is not yet supported. + const supportedNamedCurves = ["P-256", "P-384"]; const simpleAlgorithmDictionaries = { RsaHashedKeyGenParams: { hash: "HashAlgorithmIdentifier" }, @@ -31,9 +32,7 @@ "generateKey": { "RSASSA-PKCS1-v1_5": "RsaHashedKeyGenParams", "RSA-PSS": "RsaHashedKeyGenParams", - "RSA-OAEP": "RsaHashedKeyGenParams", "ECDSA": "EcKeyGenParams", - "ECDH": "EcKeyGenParams", "HMAC": "HmacKeyGenParams", }, "sign": { @@ -420,6 +419,8 @@ context: "Argument 3", }); + const usages = keyUsages; + const normalizedAlgorithm = normalizeAlgorithm(algorithm, "generateKey"); // https://github.com/denoland/deno/pull/9614#issuecomment-866049433 @@ -430,158 +431,175 @@ ); } - switch (normalizedAlgorithm.name) { - case "RSASSA-PKCS1-v1_5": - case "RSA-PSS": { - // 1. - if ( - keyUsages.find((u) => !["sign", "verify"].includes(u)) !== undefined - ) { - throw new DOMException("Invalid key usages", "SyntaxError"); - } + const result = await generateKey( + normalizedAlgorithm, + extractable, + usages, + ); - // 2. - const keyData = await core.opAsync( - "op_crypto_generate_key", - { - name: normalizedAlgorithm.name, - modulusLength: normalizedAlgorithm.modulusLength, - publicExponent: normalizedAlgorithm.publicExponent, - }, - ); - const handle = {}; - KEY_STORE.set(handle, { type: "pkcs8", data: keyData }); + 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; + } + } + + async function generateKey(normalizedAlgorithm, extractable, usages) { + switch (normalizedAlgorithm.name) { + case "RSASSA-PKCS1-v1_5": + case "RSA-PSS": { + // 1. + if (usages.find((u) => !["sign", "verify"].includes(u)) !== undefined) { + throw new DOMException("Invalid key usages", "SyntaxError"); + } - // 4-8. - const algorithm = { + // 2. + const keyData = await core.opAsync( + "op_crypto_generate_key", + { name: normalizedAlgorithm.name, modulusLength: normalizedAlgorithm.modulusLength, publicExponent: normalizedAlgorithm.publicExponent, - hash: normalizedAlgorithm.hash, - }; - - // 9-13. - let publicKey = constructKey( - "public", - true, - usageIntersection(keyUsages, "verify"), - algorithm, - handle, - ); - - // 14-18. - let privateKey = constructKey( - "private", - extractable, - usageIntersection(keyUsages, "sign"), - algorithm, - handle, - ); - - // 19-22. - return { publicKey, privateKey }; - } - // TODO(lucacasonato): RSA-OAEP - case "ECDSA": { - // 1. - if ( - keyUsages.find((u) => !["sign", "verify"].includes(u)) !== undefined - ) { - throw new DOMException("Invalid key usages", "SyntaxError"); - } + }, + ); + const handle = {}; + KEY_STORE.set(handle, { type: "pkcs8", data: keyData }); + + // 4-8. + const algorithm = { + name: normalizedAlgorithm.name, + modulusLength: normalizedAlgorithm.modulusLength, + publicExponent: normalizedAlgorithm.publicExponent, + hash: normalizedAlgorithm.hash, + }; + + // 9-13. + let publicKey = constructKey( + "public", + true, + usageIntersection(usages, "verify"), + algorithm, + handle, + ); - // 2-3. - const handle = {}; - if (supportedNamedCurves.includes(normalizedAlgorithm.namedCurve)) { - const keyData = await core.opAsync("op_crypto_generate_key", { - name: "ECDSA", - namedCurve: normalizedAlgorithm.namedCurve, - }); - KEY_STORE.set(handle, { type: "pkcs8", data: keyData }); - } else { - throw new DOMException("Curve not supported", "NotSupportedError"); - } + // 14-18. + let privateKey = constructKey( + "private", + extractable, + usageIntersection(usages, "sign"), + algorithm, + handle, + ); + + // 19-22. + return { publicKey, privateKey }; + } + // TODO(lucacasonato): RSA-OAEP + case "ECDSA": { + // 1. + if (usages.find((u) => !["sign", "verify"].includes(u)) !== undefined) { + throw new DOMException("Invalid key usages", "SyntaxError"); + } - // 4-6. - const algorithm = { + // 2-3. + const handle = {}; + if (supportedNamedCurves.includes(normalizedAlgorithm.namedCurve)) { + const keyData = await core.opAsync("op_crypto_generate_key", { name: "ECDSA", namedCurve: normalizedAlgorithm.namedCurve, - }; - - // 7-11. - let publicKey = constructKey( - "public", - true, - usageIntersection(keyUsages, "verify"), - algorithm, - handle, - ); - - // 12-16. - let privateKey = constructKey( - "private", - extractable, - usageIntersection(keyUsages, "sign"), - algorithm, - handle, - ); - - // 17-20. - return { publicKey, privateKey }; + }); + KEY_STORE.set(handle, { type: "pkcs8", data: keyData }); + } else { + throw new DOMException("Curve not supported", "NotSupportedError"); } - // TODO(lucacasonato): ECDH - // TODO(lucacasonato): AES-CTR - // TODO(lucacasonato): AES-CBC - // TODO(lucacasonato): AES-GCM - // TODO(lucacasonato): AES-KW - case "HMAC": { - // 1. - if ( - keyUsages.find((u) => !["sign", "verify"].includes(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"); - } + // 4-6. + const algorithm = { + name: "ECDSA", + namedCurve: normalizedAlgorithm.namedCurve, + }; + + // 7-11. + let publicKey = constructKey( + "public", + true, + usageIntersection(usages, "verify"), + algorithm, + handle, + ); - // 3-4. - const keyData = await core.opAsync("op_crypto_generate_key", { - name: "HMAC", - hash: normalizedAlgorithm.hash.name, - length, - }); - const handle = {}; - KEY_STORE.set(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, - keyUsages, - algorithm, - handle, - ); - - // 14. - return key; + // 12-16. + let 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 ( + usages.find((u) => !["sign", "verify"].includes(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 = {}; + KEY_STORE.set(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; } } } diff --git a/extensions/crypto/key.rs b/extensions/crypto/key.rs index 4adc55a4dabf47..c3d6899a638ea9 100644 --- a/extensions/crypto/key.rs +++ b/extensions/crypto/key.rs @@ -1,6 +1,5 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use deno_core::error::not_supported; use deno_core::error::AnyError; use ring::agreement::Algorithm as RingAlgorithm; use ring::hmac::Algorithm as HmacAlgorithm; @@ -35,8 +34,6 @@ pub enum CryptoNamedCurve { P256, #[serde(rename = "P-384")] P384, - #[serde(rename = "P-521")] - P521, } impl TryInto<&RingAlgorithm> for CryptoNamedCurve { @@ -46,7 +43,6 @@ impl TryInto<&RingAlgorithm> for CryptoNamedCurve { match self { CryptoNamedCurve::P256 => Ok(&ring::agreement::ECDH_P256), CryptoNamedCurve::P384 => Ok(&ring::agreement::ECDH_P384), - CryptoNamedCurve::P521 => Err(not_supported()), } } } @@ -62,7 +58,6 @@ impl TryInto<&EcdsaSigningAlgorithm> for CryptoNamedCurve { CryptoNamedCurve::P384 => { Ok(&ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING) } - CryptoNamedCurve::P521 => Err(not_supported()), } } } diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index dfff315ec1807f..3a757deb4d78c3 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -146,7 +146,7 @@ pub async fn op_crypto_generate_key( ) .await .unwrap() - .map_err(|e| type_error(e.to_string()))?; + .map_err(|e| custom_error("DOMExceptionOperationError", e.to_string()))?; private_key.to_pkcs8()? } @@ -165,7 +165,10 @@ pub async fn op_crypto_generate_key( }, ) .await - .unwrap()?; + .unwrap() + .map_err(|_| { + custom_error("DOMExceptionOperationError", "Key generation failed") + })?; private_key } @@ -174,11 +177,17 @@ pub async fn op_crypto_generate_key( let length = if let Some(length) = args.length { if (length % 8) != 0 { - return Err(type_error("hmac block length must be byte aligned")); + 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(type_error("hmac block length is too large")); + return Err(custom_error( + "DOMExceptionOperationError", + "hmac block length is too large", + )); } length } else { @@ -188,7 +197,9 @@ pub async fn op_crypto_generate_key( 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)?; + rng.fill(key_bytes).map_err(|_| { + custom_error("DOMExceptionOperationError", "Key generation failed") + })?; key_bytes.to_vec() } diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 4d1d24d54af306..80ff4c0f96e1bd 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -1526,26 +1526,6 @@ "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, unwrapKey])", "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, unwrapKey])", "Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveKey])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveKey])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveBits, deriveKey])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveBits, deriveKey])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveBits])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveBits])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveKey])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveKey])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveBits, deriveKey])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveBits, deriveKey])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveBits])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveBits])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", - "Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])", "Empty usages: generateKey({name: ECDH, namedCurve: P-256}, false, [])", "Empty usages: generateKey({name: ECDH, namedCurve: P-256}, true, [])", "Empty usages: generateKey({name: ECDH, namedCurve: P-384}, false, [])", @@ -1555,33 +1535,23 @@ ], "failures_ECDSA.https.any.html": [ "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [sign])", - "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, true, [sign])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [verify, sign])", - "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, true, [verify, sign])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [])", - "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, true, [])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, false, [sign, verify, sign, sign, verify])", - "Bad algorithm property: generateKey({name: ECDSA, namedCurve: P-512}, true, [sign, verify, sign, sign, verify])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, false, [sign])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, false, [verify, sign])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, false, [])", "Bad algorithm property: generateKey({name: ECDSA, namedCurve: Curve25519}, false, [sign, verify, sign, sign, verify])", "Empty usages: generateKey({name: ECDSA, namedCurve: P-256}, false, [])", - "Empty usages: generateKey({name: ECDSA, namedCurve: P-256}, true, [])", "Empty usages: generateKey({name: ECDSA, namedCurve: P-384}, false, [])", - "Empty usages: generateKey({name: ECDSA, namedCurve: P-384}, true, [])", "Empty usages: generateKey({name: ECDSA, namedCurve: P-521}, false, [])", "Empty usages: generateKey({name: ECDSA, namedCurve: P-521}, true, [])" ], "failures_HMAC.https.any.html": [ "Empty usages: generateKey({hash: SHA-1, length: 160, name: HMAC}, false, [])", - "Empty usages: generateKey({hash: SHA-1, length: 160, name: HMAC}, true, [])", "Empty usages: generateKey({hash: SHA-256, length: 256, name: HMAC}, false, [])", - "Empty usages: generateKey({hash: SHA-256, length: 256, name: HMAC}, true, [])", "Empty usages: generateKey({hash: SHA-384, length: 384, name: HMAC}, false, [])", - "Empty usages: generateKey({hash: SHA-384, length: 384, name: HMAC}, true, [])", - "Empty usages: generateKey({hash: SHA-512, length: 512, name: HMAC}, false, [])", - "Empty usages: generateKey({hash: SHA-512, length: 512, name: HMAC}, true, [])" + "Empty usages: generateKey({hash: SHA-512, length: 512, name: HMAC}, false, [])" ], "failures_RSA-OAEP.https.any.html": [ "Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign])", @@ -1767,9 +1737,7 @@ "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign, verify, sign, sign, verify])", "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", - "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])", - "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", - "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])" + "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])" ], "failures_RSASSA-PKCS1-v1_5.https.any.html": [ "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, false, [sign])", @@ -1781,9 +1749,7 @@ "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [])", "Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign, verify, sign, sign, verify])", "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", - "Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])", - "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])", - "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])" + "Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])" ], "successes_AES-CBC.https.any.html": false, "successes_AES-CTR.https.any.html": false, From 07ed948ab836b97dfc49204baf8ee3fd159a5cb5 Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Fri, 2 Jul 2021 19:13:52 +0200 Subject: [PATCH 123/130] lint --- extensions/crypto/00_crypto.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/crypto/00_crypto.js b/extensions/crypto/00_crypto.js index f73e93be2ccf07..892cbf108db1e5 100644 --- a/extensions/crypto/00_crypto.js +++ b/extensions/crypto/00_crypto.js @@ -482,7 +482,7 @@ }; // 9-13. - let publicKey = constructKey( + const publicKey = constructKey( "public", true, usageIntersection(usages, "verify"), @@ -491,7 +491,7 @@ ); // 14-18. - let privateKey = constructKey( + const privateKey = constructKey( "private", extractable, usageIntersection(usages, "sign"), @@ -528,7 +528,7 @@ }; // 7-11. - let publicKey = constructKey( + const publicKey = constructKey( "public", true, usageIntersection(usages, "verify"), @@ -537,7 +537,7 @@ ); // 12-16. - let privateKey = constructKey( + const privateKey = constructKey( "private", extractable, usageIntersection(usages, "sign"), From 81de36f056b5c2c6b47bdc0f4455080c5e6c5a5c Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Fri, 2 Jul 2021 19:20:32 +0200 Subject: [PATCH 124/130] add todo --- Cargo.lock | 10 +++++----- extensions/crypto/Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c08f6ffff92f6d..0e52f1e6c6170c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2183,9 +2183,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf" +checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512" dependencies = [ "autocfg 1.0.1", "num-integer", @@ -3086,12 +3086,12 @@ dependencies = [ [[package]] name = "simple_asn1" -version = "0.5.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8d597fce66eb0f19dd129b9956e4054cba21aeaf97d4116595027b670fac50" +checksum = "8eb4ea60fb301dc81dfc113df680571045d375ab7345d171c5dc7d7e13107a80" dependencies = [ "chrono", - "num-bigint 0.3.1", + "num-bigint 0.4.0", "num-traits", "thiserror", ] diff --git a/extensions/crypto/Cargo.toml b/extensions/crypto/Cargo.toml index 3efd33ce4d959d..582593e8026021 100644 --- a/extensions/crypto/Cargo.toml +++ b/extensions/crypto/Cargo.toml @@ -19,7 +19,7 @@ deno_web = { version = "0.41.1", path = "../web" } tokio = { version = "1.7.1", features = ["full"] } rand = "0.8.3" ring = { version = "0.16.20", features = ["std"] } -rsa = "0.4.0" +rsa = "0.4.0" # TODO: remove "pem" feature when next release is on crates.io sha-1 = "0.9.4" sha2 = "0.9.3" serde = { version = "1.0.123", features = ["derive"] } From 3ee33570704e6b73b84d9bc731118fafb52d6dec Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Sat, 3 Jul 2021 01:12:05 +0200 Subject: [PATCH 125/130] fix --- extensions/crypto/01_webidl.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extensions/crypto/01_webidl.js b/extensions/crypto/01_webidl.js index 30bf66c4b73073..d8a9f19cc11e2c 100644 --- a/extensions/crypto/01_webidl.js +++ b/extensions/crypto/01_webidl.js @@ -143,7 +143,10 @@ webidl.converters["EcdsaParams"] = webidl .createDictionaryConverter("EcdsaParams", dictEcdsaParams); - webidl.converters.CryptoKey = webidl.createInterfaceConverter(CryptoKey); + webidl.converters.CryptoKey = webidl.createInterfaceConverter( + "CryptoKey", + CryptoKey, + ); const dictCryptoKeyPair = [ { From b6cd4d2d3e4682f8fc0f5d5f2086b01f5b23150f Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 3 Jul 2021 15:19:48 +0530 Subject: [PATCH 126/130] chore: import convention --- extensions/crypto/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index 3a757deb4d78c3..0b5c049e4d3f02 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -36,7 +36,10 @@ use rsa::BigUint; use rsa::PrivateKeyEncoding; use rsa::RSAPrivateKey; use sha1::Sha1; -use sha2::{Digest, Sha256, Sha384, Sha512}; +use sha2::Digest; +use sha2::Sha256; +use sha2::Sha384; +use sha2::Sha512; use std::path::PathBuf; pub use rand; // Re-export rand From 9e578490ee7cb52a55cfafe684c4751a68728be7 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 4 Jul 2021 21:13:01 +0530 Subject: [PATCH 127/130] fmt --- extensions/crypto/00_crypto.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/crypto/00_crypto.js b/extensions/crypto/00_crypto.js index 2d3c56fc1d133a..a6c6c07225649b 100644 --- a/extensions/crypto/00_crypto.js +++ b/extensions/crypto/00_crypto.js @@ -11,7 +11,7 @@ const core = window.Deno.core; const webidl = window.__bootstrap.webidl; const { DOMException } = window.__bootstrap.domException; - + // P-521 is not yet supported. const supportedNamedCurves = ["P-256", "P-384"]; From 7c2e9dffcf52e9abbd4e4068799355c66e975c17 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 4 Jul 2021 21:40:50 +0530 Subject: [PATCH 128/130] bump sha-1 to 0.9.6 and sha2 to 0.9.5 --- Cargo.lock | 12 +++--------- extensions/crypto/Cargo.toml | 4 ++-- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ad976d3c6d8e8..f09e3e7d5ecef3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -415,12 +415,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpuid-bool" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" - [[package]] name = "crc" version = "1.8.1" @@ -3061,13 +3055,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" +checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" dependencies = [ "block-buffer", "cfg-if 1.0.0", - "cpuid-bool", + "cpufeatures", "digest", "opaque-debug", ] diff --git a/extensions/crypto/Cargo.toml b/extensions/crypto/Cargo.toml index 582593e8026021..e0c77495627455 100644 --- a/extensions/crypto/Cargo.toml +++ b/extensions/crypto/Cargo.toml @@ -20,8 +20,8 @@ tokio = { version = "1.7.1", features = ["full"] } rand = "0.8.3" ring = { version = "0.16.20", features = ["std"] } rsa = "0.4.0" # TODO: remove "pem" feature when next release is on crates.io -sha-1 = "0.9.4" -sha2 = "0.9.3" +sha-1 = "0.9.6" +sha2 = "0.9.5" serde = { version = "1.0.123", features = ["derive"] } uuid = { version = "0.8.2", features = ["v4"] } lazy_static = "1.4.0" From 4295c94c884b078385cdfb193100372209ef80da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 6 Jul 2021 11:57:46 +0200 Subject: [PATCH 129/130] use From<> instead of TryInto<> --- Cargo.lock | 4 ++-- extensions/crypto/key.rs | 26 ++++++++++---------------- extensions/crypto/lib.rs | 8 ++------ 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 93d4cb9fa643c3..951249e204ab4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2204,7 +2204,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.3", + "rand 0.8.4", "smallvec", "zeroize", ] @@ -2828,7 +2828,7 @@ dependencies = [ "num-iter", "num-traits", "pem", - "rand 0.8.3", + "rand 0.8.4", "simple_asn1", "subtle", "zeroize", diff --git a/extensions/crypto/key.rs b/extensions/crypto/key.rs index c3d6899a638ea9..d5801635e034dd 100644 --- a/extensions/crypto/key.rs +++ b/extensions/crypto/key.rs @@ -1,12 +1,10 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use deno_core::error::AnyError; use ring::agreement::Algorithm as RingAlgorithm; use ring::hmac::Algorithm as HmacAlgorithm; use ring::signature::EcdsaSigningAlgorithm; use serde::Deserialize; use serde::Serialize; -use std::convert::TryInto; #[derive(Serialize, Deserialize, Copy, Clone)] #[serde(rename_all = "camelCase")] @@ -36,27 +34,23 @@ pub enum CryptoNamedCurve { P384, } -impl TryInto<&RingAlgorithm> for CryptoNamedCurve { - type Error = AnyError; - - fn try_into(self) -> Result<&'static RingAlgorithm, Self::Error> { - match self { - CryptoNamedCurve::P256 => Ok(&ring::agreement::ECDH_P256), - CryptoNamedCurve::P384 => Ok(&ring::agreement::ECDH_P384), +impl From for &RingAlgorithm { + fn from(curve: CryptoNamedCurve) -> &'static RingAlgorithm { + match curve { + CryptoNamedCurve::P256 => &ring::agreement::ECDH_P256, + CryptoNamedCurve::P384 => &ring::agreement::ECDH_P384, } } } -impl TryInto<&EcdsaSigningAlgorithm> for CryptoNamedCurve { - type Error = AnyError; - - fn try_into(self) -> Result<&'static EcdsaSigningAlgorithm, Self::Error> { - match self { +impl From for &EcdsaSigningAlgorithm { + fn from(curve: CryptoNamedCurve) -> &'static EcdsaSigningAlgorithm { + match curve { CryptoNamedCurve::P256 => { - Ok(&ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING) + &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING } CryptoNamedCurve::P384 => { - Ok(&ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING) + &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING } } } diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index 2e38f992f10c03..ab1a7134f17447 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -154,15 +154,11 @@ pub async fn op_crypto_generate_key( private_key.to_pkcs8()? } Algorithm::Ecdsa => { - let curve: Result<&EcdsaSigningAlgorithm, AnyError> = - args.named_curve.ok_or_else(not_supported)?.try_into(); - if curve.is_err() { - return Err(not_supported()); - } + let curve: &EcdsaSigningAlgorithm = + args.named_curve.ok_or_else(not_supported)?.into(); let rng = RingRand::SystemRandom::new(); let private_key: Vec = tokio::task::spawn_blocking( move || -> Result, ring::error::Unspecified> { - let curve = curve.unwrap(); let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)?; Ok(pkcs8.as_ref().to_vec()) }, From 4a51630a8f2506360436a72a1dad6e8ee2f0759a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 6 Jul 2021 12:37:29 +0200 Subject: [PATCH 130/130] reset CI