diff options
author | Luca Casonato <hello@lcas.dev> | 2021-12-13 13:22:03 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-13 13:22:03 +0100 |
commit | 5afb2cca65f10b8d0baaff4989a102d24d629087 (patch) | |
tree | b390f1e3dccdff3bc9b58fd79473ba967ee62783 /ext/crypto/export_key.rs | |
parent | cd03de3c7b8a99aeee3953e69392c26d3667c41d (diff) |
refactor(ext/crypto): clean up exportKey rust code (#13052)
Diffstat (limited to 'ext/crypto/export_key.rs')
-rw-r--r-- | ext/crypto/export_key.rs | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/ext/crypto/export_key.rs b/ext/crypto/export_key.rs new file mode 100644 index 000000000..22a4b55ca --- /dev/null +++ b/ext/crypto/export_key.rs @@ -0,0 +1,113 @@ +use deno_core::error::AnyError; +use deno_core::OpState; +use deno_core::ZeroCopyBuf; +use serde::Deserialize; +use serde::Serialize; +use spki::der::asn1; +use spki::der::Encodable; + +use crate::shared::*; + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ExportKeyOptions { + format: ExportKeyFormat, + #[serde(flatten)] + algorithm: ExportKeyAlgorithm, +} + +#[derive(Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum ExportKeyFormat { + Pkcs8, + Spki, + Jwk, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase", tag = "algorithm")] +pub enum ExportKeyAlgorithm { + #[serde(rename = "RSASSA-PKCS1-v1_5")] + RsassaPkcs1v15 {}, + #[serde(rename = "RSA-PSS")] + RsaPss {}, + #[serde(rename = "RSA-OAEP")] + RsaOaep {}, +} + +#[derive(Serialize)] +#[serde(untagged)] +pub enum ExportKeyResult { + Pkcs8(ZeroCopyBuf), + Spki(ZeroCopyBuf), +} + +pub fn op_crypto_export_key( + _state: &mut OpState, + opts: ExportKeyOptions, + key_data: RawKeyData, +) -> Result<ExportKeyResult, AnyError> { + match opts.algorithm { + ExportKeyAlgorithm::RsassaPkcs1v15 {} + | ExportKeyAlgorithm::RsaPss {} + | ExportKeyAlgorithm::RsaOaep {} => export_key_rsa(opts.format, key_data), + } +} + +fn export_key_rsa( + format: ExportKeyFormat, + key_data: RawKeyData, +) -> Result<ExportKeyResult, deno_core::anyhow::Error> { + match format { + ExportKeyFormat::Spki => { + let subject_public_key = &key_data.as_rsa_public_key()?; + + // the SPKI structure + let key_info = spki::SubjectPublicKeyInfo { + algorithm: spki::AlgorithmIdentifier { + // rsaEncryption(1) + oid: spki::ObjectIdentifier::new("1.2.840.113549.1.1.1"), + // parameters field should not be ommited (None). + // It MUST have ASN.1 type NULL. + parameters: Some(asn1::Any::from(asn1::Null)), + }, + subject_public_key, + }; + + // Infallible because we know the public key is valid. + let spki_der = key_info.to_vec().unwrap(); + Ok(ExportKeyResult::Spki(spki_der.into())) + } + ExportKeyFormat::Pkcs8 => { + let private_key = key_data.as_rsa_private_key()?; + + // 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 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, + }; + + // Infallible because we know the private key is valid. + let pkcs8_der = pk_info.to_vec().unwrap(); + + Ok(ExportKeyResult::Pkcs8(pkcs8_der.into())) + } + _ => Err(unsupported_format()), + } +} |