From c517d256083afd4dbc5ea68f9652dfbefb9ff488 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 30 Aug 2021 16:41:49 +0000 Subject: [PATCH 1/9] feat(ext/crypto): export RSA as pkcs#8 --- ext/crypto/00_crypto.js | 38 +++++++++++++++++++--- ext/crypto/lib.rs | 72 +++++++++++++++++++++++++++++++++++------ 2 files changed, 96 insertions(+), 14 deletions(-) diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js index ab6347d41bc0b7..5e978a120db990 100644 --- a/ext/crypto/00_crypto.js +++ b/ext/crypto/00_crypto.js @@ -944,7 +944,6 @@ * @param {CryptoKey} key * @returns {Promise} */ - // deno-lint-ignore require-await async exportKey(format, key) { webidl.assertBranded(this, SubtleCrypto); const prefix = "Failed to execute 'exportKey' on 'SubtleCrypto'"; @@ -1020,8 +1019,35 @@ // TODO(@littledivy): Redundant break but deno_lint complains without it break; } - // TODO(@littledivy): RSASSA-PKCS1-v1_5 - // TODO(@littledivy): RSA-PSS + case "RSASSA-PKCS1-v1_5": + case "RSA-PSS": { + switch (format) { + case "pkcs8": { + // 1. + if (key[_type] !== "private") { + throw new DOMException( + "Key is not a private key", + "InvalidAccessError", + ); + } + + // 2. + const data = await core.opAsync( + "op_crypto_export_key", + { + key: innerKey.data, + format: "pkcs8", + algorithm: key[_algorithm].name, + }, + ); + + // 3. + return data.buffer; + } + default: + throw new DOMException("Not implemented", "NotSupportedError"); + } + } // TODO(@littledivy): ECDSA default: throw new DOMException("Not implemented", "NotSupportedError"); @@ -1263,7 +1289,8 @@ ); const handle = {}; WeakMapPrototypeSet(KEY_STORE, handle, { - type: "pkcs8", + // PKCS#1 for RSA + type: "raw", data: keyData, }); @@ -1323,7 +1350,8 @@ ); const handle = {}; WeakMapPrototypeSet(KEY_STORE, handle, { - type: "pkcs8", + // PKCS#1 for RSA + type: "raw", data: keyData, }); diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index b68bd788746101..f68b72f19e724f 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -34,8 +34,8 @@ use ring::rand::SecureRandom; use ring::signature::EcdsaKeyPair; use ring::signature::EcdsaSigningAlgorithm; use rsa::padding::PaddingScheme; -use rsa::pkcs8::FromPrivateKey; -use rsa::pkcs8::ToPrivateKey; +use rsa::pkcs1::FromRsaPrivateKey; +use rsa::pkcs1::ToRsaPrivateKey; use rsa::BigUint; use rsa::PublicKey; use rsa::RsaPrivateKey; @@ -77,6 +77,7 @@ pub fn init(maybe_seed: Option) -> Extension { ("op_crypto_sign_key", op_async(op_crypto_sign_key)), ("op_crypto_verify_key", op_async(op_crypto_verify_key)), ("op_crypto_derive_bits", op_async(op_crypto_derive_bits)), + ("op_crypto_export_key", op_async(op_crypto_export_key)), ("op_crypto_encrypt_key", op_async(op_crypto_encrypt_key)), ("op_crypto_decrypt_key", op_async(op_crypto_decrypt_key)), ("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)), @@ -160,7 +161,7 @@ pub async fn op_crypto_generate_key( .unwrap() .map_err(|e| custom_error("DOMExceptionOperationError", e.to_string()))?; - private_key.to_pkcs8_der()?.as_ref().to_vec() + private_key.to_pkcs1_der()?.as_ref().to_vec() } Algorithm::Ecdsa => { let curve: &EcdsaSigningAlgorithm = @@ -254,7 +255,7 @@ pub async fn op_crypto_sign_key( let signature = match algorithm { Algorithm::RsassaPkcs1v15 => { - let private_key = RsaPrivateKey::from_pkcs8_der(&*args.key.data)?; + let private_key = RsaPrivateKey::from_pkcs1_der(&*args.key.data)?; let (padding, hashed) = match args .hash .ok_or_else(|| type_error("Missing argument hash".to_string()))? @@ -304,7 +305,7 @@ pub async fn op_crypto_sign_key( private_key.sign(padding, &hashed)? } Algorithm::RsaPss => { - let private_key = RsaPrivateKey::from_pkcs8_der(&*args.key.data)?; + let private_key = RsaPrivateKey::from_pkcs1_der(&*args.key.data)?; let salt_len = args .salt_length @@ -409,7 +410,7 @@ pub async fn op_crypto_verify_key( let verification = match algorithm { Algorithm::RsassaPkcs1v15 => { let public_key: RsaPublicKey = - RsaPrivateKey::from_pkcs8_der(&*args.key.data)?.to_public_key(); + RsaPrivateKey::from_pkcs1_der(&*args.key.data)?.to_public_key(); let (padding, hashed) = match args .hash .ok_or_else(|| type_error("Missing argument hash".to_string()))? @@ -466,7 +467,7 @@ pub async fn op_crypto_verify_key( .ok_or_else(|| type_error("Missing argument saltLength".to_string()))? as usize; let public_key: RsaPublicKey = - RsaPrivateKey::from_pkcs8_der(&*args.key.data)?.to_public_key(); + RsaPrivateKey::from_pkcs1_der(&*args.key.data)?.to_public_key(); let rng = OsRng; let (padding, hashed) = match args @@ -522,6 +523,59 @@ pub async fn op_crypto_verify_key( Ok(verification) } +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ExportKeyArg { + key: KeyData, + algorithm: Algorithm, + format: KeyFormat, +} + +pub async fn op_crypto_export_key( + _state: Rc>, + args: ExportKeyArg, + _zero_copy: Option, +) -> Result { + let algorithm = args.algorithm; + match algorithm { + Algorithm::RsassaPkcs1v15 => { + match args.format { + KeyFormat::Pkcs8 => { + // private_key is a PKCS#1 DER-encoded private key + + let private_key = &args.key.data; + + // the PKCS#8 v1 structure + // PrivateKeyInfo ::= SEQUENCE { + // version Version, + // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + // privateKey PrivateKey, + // attributes [0] IMPLICIT Attributes OPTIONAL } + + // version is 0 when publickey is None + + let pk_info = rsa::pkcs8::PrivateKeyInfo { + attributes: None, + public_key: None, + algorithm: rsa::pkcs8::AlgorithmIdentifier { + // rsaEncryption(1) + oid: rsa::pkcs8::ObjectIdentifier::new("1.2.840.113549.1.1.1"), + parameters: None, + }, + private_key, + }; + + Ok(pk_info.to_der().as_ref().to_vec().into()) + } + // TODO(@littledivy): spki + // TODO(@littledivy): jwk + _ => unreachable!(), + } + } + _ => Err(type_error("Unsupported algorithm".to_string())), + } +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct DeriveKeyArg { @@ -586,7 +640,7 @@ pub async fn op_crypto_encrypt_key( match algorithm { Algorithm::RsaOaep => { let public_key: RsaPublicKey = - RsaPrivateKey::from_pkcs8_der(&*args.key.data)?.to_public_key(); + RsaPrivateKey::from_pkcs1_der(&*args.key.data)?.to_public_key(); let label = args.label.map(|l| String::from_utf8_lossy(&*l).to_string()); let mut rng = OsRng; let padding = match args @@ -649,7 +703,7 @@ pub async fn op_crypto_decrypt_key( match algorithm { Algorithm::RsaOaep => { let private_key: RsaPrivateKey = - RsaPrivateKey::from_pkcs8_der(&*args.key.data)?; + RsaPrivateKey::from_pkcs1_der(&*args.key.data)?; let label = args.label.map(|l| String::from_utf8_lossy(&*l).to_string()); let padding = match args .hash From 6ff55954b37d1e877faf5b564e73df487aec511b Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 31 Aug 2021 08:45:11 +0000 Subject: [PATCH 2/9] rsa-pss --- Cargo.lock | 22 ++++++++++++ ext/crypto/Cargo.toml | 1 + ext/crypto/lib.rs | 83 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index f3189660b86e9b..a5f80ba6b2b4f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,6 +104,27 @@ dependencies = [ "libloading", ] +[[package]] +name = "asn1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c13a3c9cd71e1799fc16511efe36d0281b60bce3b32b4b211156a7b1925bfd" +dependencies = [ + "asn1_derive", + "chrono", +] + +[[package]] +name = "asn1_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62fc4b7f90b9540f1719f333e3ed85100ea072035d690000d7c01252ecdff096" +dependencies = [ + "proc-macro2 1.0.27", + "quote 1.0.9", + "syn 1.0.65", +] + [[package]] name = "ast_node" version = "0.7.3" @@ -697,6 +718,7 @@ dependencies = [ name = "deno_crypto" version = "0.30.0" dependencies = [ + "asn1", "deno_core", "deno_web", "lazy_static", diff --git a/ext/crypto/Cargo.toml b/ext/crypto/Cargo.toml index 349fb0265c55a3..a6166b78529235 100644 --- a/ext/crypto/Cargo.toml +++ b/ext/crypto/Cargo.toml @@ -26,3 +26,4 @@ sha-1 = "0.9.7" sha2 = "0.9.5" tokio = { version = "1.8.1", features = ["full"] } uuid = { version = "0.8.2", features = ["v4"] } +asn1 = "0.6.1" \ No newline at end of file diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index f68b72f19e724f..3eb3aa80173dd1 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -529,6 +529,8 @@ pub struct ExportKeyArg { key: KeyData, algorithm: Algorithm, format: KeyFormat, + // RSA-PSS + hash: Option, } pub async fn op_crypto_export_key( @@ -572,6 +574,87 @@ pub async fn op_crypto_export_key( _ => unreachable!(), } } + Algorithm::RsaPss => { + match args.format { + KeyFormat::Pkcs8 => { + let hash = args + .hash + .ok_or_else(|| type_error("Missing argument hash".to_string()))?; + + // private_key is a PKCS#1 DER-encoded private key + let private_key = &args.key.data; + + let (oid, salt_length) = { + let (oid_str, salt_length) = match hash { + // id-sha1 + CryptoHash::Sha1 => ("1.3.14.3.2.26", 20), + // id-sha256 + CryptoHash::Sha256 => ("2.16.840.1.101.3.4.2.1", 32), + // id-sha384 + CryptoHash::Sha384 => ("2.16.840.1.101.3.4.2.2", 48), + // id-sha512 + CryptoHash::Sha512 => ("2.16.840.1.101.3.4.2.3", 64), + }; + + (asn1::ObjectIdentifier::from_string(oid_str), salt_length) + }; + + let parameters = asn1::write(|w| { + w.write_element(&asn1::SequenceWriter::new(&|w| { + // hashAlgorithm + w.write_element(&asn1::Explicit::<_, 0>::new( + asn1::SequenceWriter::new(&|w| { + w.write_element(&oid); + }), + )); + + // maskGenAlgorithm + w.write_element(&asn1::Explicit::<_, 1>::new( + asn1::SequenceWriter::new(&|w| { + // id-mgf1 + let id_mgf1 = + asn1::ObjectIdentifier::from_string("1.2.840.113549.1.1.8"); + w.write_element(&id_mgf1); + w.write_element(&asn1::SequenceWriter::new(&|w| { + w.write_element(&oid); + w.write_element(&()); + })); + }), + )); + + // saltLength + w.write_element(&asn1::Explicit::<_, 2>::new(salt_length)); + })); + }); + + // version is 0 when publickey is None + + let pk_info = rsa::pkcs8::PrivateKeyInfo { + attributes: None, + public_key: None, + algorithm: rsa::pkcs8::AlgorithmIdentifier { + // id-RSASSA-PSS + oid: rsa::pkcs8::ObjectIdentifier::new("1.2.840.113549.1.1.10"), + parameters: Some( + rsa::pkcs8::der::asn1::Any::new( + rsa::pkcs8::der::Tag::Sequence, + ¶meters, + ) + .map_err(|e| { + custom_error("DOMExceptionOperationError", e.to_string()) + })?, + ), + }, + private_key, + }; + + Ok(pk_info.to_der().as_ref().to_vec().into()) + } + // TODO(@littledivy): spki + // TODO(@littledivy): jwk + _ => unreachable!(), + } + } _ => Err(type_error("Unsupported algorithm".to_string())), } } From 6d3dc115b7e33bcbd4a29d753f77b9f4660b5ee6 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 31 Aug 2021 09:56:51 +0000 Subject: [PATCH 3/9] hash --- ext/crypto/00_crypto.js | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js index 5e978a120db990..62f1fc30dde263 100644 --- a/ext/crypto/00_crypto.js +++ b/ext/crypto/00_crypto.js @@ -1019,7 +1019,34 @@ // TODO(@littledivy): Redundant break but deno_lint complains without it break; } - case "RSASSA-PKCS1-v1_5": + case "RSASSA-PKCS1-v1_5": { + switch (format) { + case "pkcs8": { + // 1. + if (key[_type] !== "private") { + throw new DOMException( + "Key is not a private key", + "InvalidAccessError", + ); + } + + // 2. + const data = await core.opAsync( + "op_crypto_export_key", + { + key: innerKey, + format: "pkcs8", + algorithm: "RSASSA-PKCS1-v1_5", + }, + ); + + // 3. + return data.buffer; + } + default: + throw new DOMException("Not implemented", "NotSupportedError"); + } + } case "RSA-PSS": { switch (format) { case "pkcs8": { @@ -1035,9 +1062,10 @@ const data = await core.opAsync( "op_crypto_export_key", { - key: innerKey.data, + key: innerKey, format: "pkcs8", - algorithm: key[_algorithm].name, + algorithm: "RSA-PSS", + hash: key[_algorithm].hash.name, }, ); @@ -1048,6 +1076,7 @@ throw new DOMException("Not implemented", "NotSupportedError"); } } + // TODO(@littledivy): RSA-OAEP // TODO(@littledivy): ECDSA default: throw new DOMException("Not implemented", "NotSupportedError"); From cffdfafb188597ad0ae459ef1ab57c938b24a321 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 31 Aug 2021 15:34:36 +0000 Subject: [PATCH 4/9] use rsaEncryption OID --- ext/crypto/lib.rs | 62 ++++++----------------------------------------- 1 file changed, 8 insertions(+), 54 deletions(-) diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index 3eb3aa80173dd1..b3fdbdb368a6ae 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -577,73 +577,27 @@ pub async fn op_crypto_export_key( Algorithm::RsaPss => { match args.format { KeyFormat::Pkcs8 => { - let hash = args + // Intentionally unused but required. Not encoded into PKCS#8 (see below). + let _hash = args .hash .ok_or_else(|| type_error("Missing argument hash".to_string()))?; // private_key is a PKCS#1 DER-encoded private key let private_key = &args.key.data; - let (oid, salt_length) = { - let (oid_str, salt_length) = match hash { - // id-sha1 - CryptoHash::Sha1 => ("1.3.14.3.2.26", 20), - // id-sha256 - CryptoHash::Sha256 => ("2.16.840.1.101.3.4.2.1", 32), - // id-sha384 - CryptoHash::Sha384 => ("2.16.840.1.101.3.4.2.2", 48), - // id-sha512 - CryptoHash::Sha512 => ("2.16.840.1.101.3.4.2.3", 64), - }; - - (asn1::ObjectIdentifier::from_string(oid_str), salt_length) - }; - - let parameters = asn1::write(|w| { - w.write_element(&asn1::SequenceWriter::new(&|w| { - // hashAlgorithm - w.write_element(&asn1::Explicit::<_, 0>::new( - asn1::SequenceWriter::new(&|w| { - w.write_element(&oid); - }), - )); - - // maskGenAlgorithm - w.write_element(&asn1::Explicit::<_, 1>::new( - asn1::SequenceWriter::new(&|w| { - // id-mgf1 - let id_mgf1 = - asn1::ObjectIdentifier::from_string("1.2.840.113549.1.1.8"); - w.write_element(&id_mgf1); - w.write_element(&asn1::SequenceWriter::new(&|w| { - w.write_element(&oid); - w.write_element(&()); - })); - }), - )); - - // saltLength - w.write_element(&asn1::Explicit::<_, 2>::new(salt_length)); - })); - }); - // version is 0 when publickey is None let pk_info = rsa::pkcs8::PrivateKeyInfo { attributes: None, public_key: None, algorithm: rsa::pkcs8::AlgorithmIdentifier { - // id-RSASSA-PSS + // Spec wants the OID to be id-RSASSA-PSS (1.2.840.113549.1.1.10) but ring and RSA do not support it. + // Instead, we use rsaEncryption (1.2.840.113549.1.1.1) as specified in RFC 3447. + // Node, Chromium and Firefox also use rsaEncryption (1.2.840.113549.1.1.1) and do not support id-RSASSA-PSS. + + // parameters are set to NULL opposed to what spec wants (see above) oid: rsa::pkcs8::ObjectIdentifier::new("1.2.840.113549.1.1.10"), - parameters: Some( - rsa::pkcs8::der::asn1::Any::new( - rsa::pkcs8::der::Tag::Sequence, - ¶meters, - ) - .map_err(|e| { - custom_error("DOMExceptionOperationError", e.to_string()) - })?, - ), + parameters: None, }, private_key, }; From aeb079d694bd3f14b054a0dd902205b0299c4293 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 31 Aug 2021 15:46:50 +0000 Subject: [PATCH 5/9] fix OID --- ext/crypto/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index b3fdbdb368a6ae..c98362fac6040b 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -596,7 +596,7 @@ pub async fn op_crypto_export_key( // Node, Chromium and Firefox also use rsaEncryption (1.2.840.113549.1.1.1) and do not support id-RSASSA-PSS. // parameters are set to NULL opposed to what spec wants (see above) - oid: rsa::pkcs8::ObjectIdentifier::new("1.2.840.113549.1.1.10"), + oid: rsa::pkcs8::ObjectIdentifier::new("1.2.840.113549.1.1.1"), parameters: None, }, private_key, From e20601678f34f2ae81b715d75c63a2a1d7ca05bf Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 31 Aug 2021 16:14:40 +0000 Subject: [PATCH 6/9] fix: parameters encoding should be NULL --- ext/crypto/lib.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index c98362fac6040b..cc67dfcf35783e 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -36,6 +36,7 @@ use ring::signature::EcdsaSigningAlgorithm; use rsa::padding::PaddingScheme; use rsa::pkcs1::FromRsaPrivateKey; use rsa::pkcs1::ToRsaPrivateKey; +use rsa::pkcs8::der::asn1; use rsa::BigUint; use rsa::PublicKey; use rsa::RsaPrivateKey; @@ -562,7 +563,9 @@ pub async fn op_crypto_export_key( algorithm: rsa::pkcs8::AlgorithmIdentifier { // rsaEncryption(1) oid: rsa::pkcs8::ObjectIdentifier::new("1.2.840.113549.1.1.1"), - parameters: None, + // parameters field should not be ommited (None). + // It MUST have ASN.1 type NULL as per defined in RFC 3279 Section 2.3.1 + parameters: Some(asn1::Any::from(asn1::Null)), }, private_key, }; @@ -597,7 +600,9 @@ pub async fn op_crypto_export_key( // parameters are set to NULL opposed to what spec wants (see above) oid: rsa::pkcs8::ObjectIdentifier::new("1.2.840.113549.1.1.1"), - parameters: None, + // parameters field should not be ommited (None). + // It MUST have ASN.1 type NULL as per defined in RFC 3279 Section 2.3.1 + parameters: Some(asn1::Any::from(asn1::Null)), }, private_key, }; From a7fb1f4d2938334e04548c85b2f02f9fac5c10f6 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 1 Sep 2021 04:58:49 +0000 Subject: [PATCH 7/9] RSA_OAEP --- ext/crypto/00_crypto.js | 30 +++++++++++++++++++++++++++++- ext/crypto/lib.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js index 62f1fc30dde263..8f2530411bed34 100644 --- a/ext/crypto/00_crypto.js +++ b/ext/crypto/00_crypto.js @@ -1076,7 +1076,35 @@ throw new DOMException("Not implemented", "NotSupportedError"); } } - // TODO(@littledivy): RSA-OAEP + case "RSA-OAEP": { + switch (format) { + case "pkcs8": { + // 1. + if (key[_type] !== "private") { + throw new DOMException( + "Key is not a private key", + "InvalidAccessError", + ); + } + + // 2. + const data = await core.opAsync( + "op_crypto_export_key", + { + key: innerKey, + format: "pkcs8", + algorithm: "RSA-PSS", + hash: key[_algorithm].hash.name, + }, + ); + + // 3. + return data.buffer; + } + default: + throw new DOMException("Not implemented", "NotSupportedError"); + } + } // TODO(@littledivy): ECDSA default: throw new DOMException("Not implemented", "NotSupportedError"); diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index cc67dfcf35783e..64361d5279a220 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -614,6 +614,43 @@ pub async fn op_crypto_export_key( _ => unreachable!(), } } + Algorithm::RsaOaep => { + match args.format { + KeyFormat::Pkcs8 => { + // Intentionally unused but required. Not encoded into PKCS#8 (see below). + let _hash = args + .hash + .ok_or_else(|| type_error("Missing argument hash".to_string()))?; + + // private_key is a PKCS#1 DER-encoded private key + let private_key = &args.key.data; + + // version is 0 when publickey is None + + let pk_info = rsa::pkcs8::PrivateKeyInfo { + attributes: None, + public_key: None, + algorithm: rsa::pkcs8::AlgorithmIdentifier { + // Spec wants the OID to be id-RSAES-OAEP (1.2.840.113549.1.1.10) but ring and RSA crate do not support it. + // Instead, we use rsaEncryption (1.2.840.113549.1.1.1) as specified in RFC 3447. + // Chromium and Firefox also use rsaEncryption (1.2.840.113549.1.1.1) and do not support id-RSAES-OAEP. + + // parameters are set to NULL opposed to what spec wants (see above) + oid: rsa::pkcs8::ObjectIdentifier::new("1.2.840.113549.1.1.1"), + // parameters field should not be ommited (None). + // It MUST have ASN.1 type NULL as per defined in RFC 3279 Section 2.3.1 + parameters: Some(asn1::Any::from(asn1::Null)), + }, + private_key, + }; + + Ok(pk_info.to_der().as_ref().to_vec().into()) + } + // TODO(@littledivy): spki + // TODO(@littledivy): jwk + _ => unreachable!(), + } + } _ => Err(type_error("Unsupported algorithm".to_string())), } } From 68dc6be4db9818d96c45a354d9a8f371331cc276 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 1 Sep 2021 06:49:11 +0000 Subject: [PATCH 8/9] test --- cli/tests/unit/webcrypto_test.ts | 44 ++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts index 475efde6c0a854..5f062f7eb2d591 100644 --- a/cli/tests/unit/webcrypto_test.ts +++ b/cli/tests/unit/webcrypto_test.ts @@ -306,3 +306,47 @@ unitTest(async function subtleCryptoHmacImportExport() { const exportedKey2 = await crypto.subtle.exportKey("jwk", key2); assertEquals(exportedKey2, jwk); }); + +// deno-fmt-ignore +const asn1AlgorithmIdentifier = new Uint8Array([ + 0x02, 0x01, 0x00, // INTEGER + 0x30, 0x0d, // SEQUENCE (2 elements) + 0x06, 0x09, // OBJECT IDENTIFIER + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, // 1.2.840.113549.1.1.1 (rsaEncryption) + 0x05, 0x00, // NULL +]); + +unitTest(async function rsaExportPkcs8() { + for (const algorithm of ["RSASSA-PKCS1-v1_5", "RSA-PSS", "RSA-OAEP"]) { + const keyPair = await crypto.subtle.generateKey( + { + name: algorithm, + modulusLength: 2048, + publicExponent: new Uint8Array([1, 0, 1]), + hash: "SHA-256", + }, + true, + algorithm !== "RSA-OAEP" ? ["sign", "verify"] : ["encrypt", "decrypt"], + ); + + assert(keyPair.privateKey); + assert(keyPair.publicKey); + assertEquals(keyPair.privateKey.extractable, true); + + const exportedKey = await crypto.subtle.exportKey( + "pkcs8", + keyPair.privateKey, + ); + + assert(exportedKey); + assert(exportedKey instanceof ArrayBuffer); + + const pkcs8 = new Uint8Array(exportedKey); + assert(pkcs8.length > 0); + + assertEquals( + pkcs8.slice(4, asn1AlgorithmIdentifier.byteLength + 4), + asn1AlgorithmIdentifier, + ); + } +}); From c89903409bbb342da6fe30e3309659640c81972c Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 1 Sep 2021 06:56:44 +0000 Subject: [PATCH 9/9] fmt --- Cargo.lock | 22 ---------------------- ext/crypto/Cargo.toml | 1 - 2 files changed, 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a5f80ba6b2b4f3..f3189660b86e9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,27 +104,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "asn1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c13a3c9cd71e1799fc16511efe36d0281b60bce3b32b4b211156a7b1925bfd" -dependencies = [ - "asn1_derive", - "chrono", -] - -[[package]] -name = "asn1_derive" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62fc4b7f90b9540f1719f333e3ed85100ea072035d690000d7c01252ecdff096" -dependencies = [ - "proc-macro2 1.0.27", - "quote 1.0.9", - "syn 1.0.65", -] - [[package]] name = "ast_node" version = "0.7.3" @@ -718,7 +697,6 @@ dependencies = [ name = "deno_crypto" version = "0.30.0" dependencies = [ - "asn1", "deno_core", "deno_web", "lazy_static", diff --git a/ext/crypto/Cargo.toml b/ext/crypto/Cargo.toml index a6166b78529235..349fb0265c55a3 100644 --- a/ext/crypto/Cargo.toml +++ b/ext/crypto/Cargo.toml @@ -26,4 +26,3 @@ sha-1 = "0.9.7" sha2 = "0.9.5" tokio = { version = "1.8.1", features = ["full"] } uuid = { version = "0.8.2", features = ["v4"] } -asn1 = "0.6.1" \ No newline at end of file