From 2d1dfdc2a149f2389a4f4c2c64db833c450f7d4e Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 28 Apr 2024 11:02:24 -0700 Subject: [PATCH] Replace custom PKCS #8 parsing with `der` crate and others --- russh-keys/Cargo.toml | 8 +- russh-keys/src/format/mod.rs | 9 +- russh-keys/src/format/pkcs8.rs | 599 +++++++-------------------------- russh-keys/src/lib.rs | 30 +- 4 files changed, 148 insertions(+), 498 deletions(-) diff --git a/russh-keys/Cargo.toml b/russh-keys/Cargo.toml index 0e79a03e..98314d9a 100644 --- a/russh-keys/Cargo.toml +++ b/russh-keys/Cargo.toml @@ -40,9 +40,10 @@ block-padding = { version = "0.3", features = ["std"] } byteorder = "1.4" data-encoding = "2.3" digest = "0.10" +der = "0.7" dirs = "5.0" ecdsa = "0.16" -ed25519-dalek = { version= "2.0", features = ["rand_core"] } +ed25519-dalek = { version= "2.0", features = ["rand_core", "pkcs8"] } elliptic-curve = "0.13" futures = "0.3" hmac = "0.12" @@ -57,18 +58,21 @@ p384 = "0.13" p521 = "0.13" pbkdf2 = "0.11" pkcs1 = "0.7" +pkcs5 = "0.7" +pkcs8 = { version = "0.10", features = ["pkcs5", "encryption"] } rand = "0.8" rand_core = { version = "0.6.4", features = ["std"] } rsa = "0.9" russh-cryptovec = { version = "0.7.0", path = "../cryptovec" } +sec1 = { version = "0.7", features = ["pkcs8"] } serde = { version = "1.0", features = ["derive"] } sha1 = { version = "0.10", features = ["oid"] } sha2 = { version = "0.10", features = ["oid"] } +spki = "0.7" thiserror = "1.0" tokio = { version = "1.17.0", features = ["io-util", "rt-multi-thread", "time", "net"] } tokio-stream = { version = "0.1", features = ["net"] } typenum = "1.17" -yasna = { version = "0.5.0", features = ["bit-vec", "num-bigint"] } [features] vendored-openssl = ["openssl", "openssl/vendored"] diff --git a/russh-keys/src/format/mod.rs b/russh-keys/src/format/mod.rs index 7a321590..c4987c5f 100644 --- a/russh-keys/src/format/mod.rs +++ b/russh-keys/src/format/mod.rs @@ -80,15 +80,16 @@ pub fn decode_secret_key(secret: &str, password: Option<&str>) -> Result decode_openssh(&secret, password), Some(Format::Rsa) => decode_rsa(&secret), Some(Format::Pkcs5Encrypted(enc)) => decode_pkcs5(&secret, password, enc), - Some(Format::Pkcs8Encrypted) | Some(Format::Pkcs8) => { - self::pkcs8::decode_pkcs8(&secret, password.map(|x| x.as_bytes())) - } + Some(Format::Pkcs8Encrypted) | Some(Format::Pkcs8) => Ok(self::pkcs8::decode_pkcs8( + &secret, + password.map(|x| x.as_bytes()), + )?), None => Err(Error::CouldNotReadKey), } } pub fn encode_pkcs8_pem(key: &key::KeyPair, mut w: W) -> Result<(), Error> { - let x = self::pkcs8::encode_pkcs8(key); + let x = self::pkcs8::encode_pkcs8(key)?; w.write_all(b"-----BEGIN PRIVATE KEY-----\n")?; w.write_all(BASE64_MIME.encode(&x).as_bytes())?; w.write_all(b"\n-----END PRIVATE KEY-----\n")?; diff --git a/russh-keys/src/format/pkcs8.rs b/russh-keys/src/format/pkcs8.rs index 63f653fb..cef480fb 100644 --- a/russh-keys/src/format/pkcs8.rs +++ b/russh-keys/src/format/pkcs8.rs @@ -1,356 +1,132 @@ -use std::borrow::Cow; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; -use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit}; -use bit_vec::BitVec; -use block_padding::{NoPadding, Pkcs7}; -#[cfg(test)] -use rand_core::OsRng; -use yasna::BERReaderSeq; -use {std, yasna}; - -use super::Encryption; -use crate::key::SignatureHash; -use crate::{key, protocol, Error}; - -const PBES2: &[u64] = &[1, 2, 840, 113549, 1, 5, 13]; -const PBKDF2: &[u64] = &[1, 2, 840, 113549, 1, 5, 12]; -const HMAC_SHA256: &[u64] = &[1, 2, 840, 113549, 2, 9]; -const AES256CBC: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 1, 42]; -const ED25519: &[u64] = &[1, 3, 101, 112]; -const RSA: &[u64] = &[1, 2, 840, 113549, 1, 1, 1]; -const EC_PUBLIC_KEY: &[u64] = &[1, 2, 840, 10045, 2, 1]; -const SECP256R1: &[u64] = &[1, 2, 840, 10045, 3, 1, 7]; -const SECP384R1: &[u64] = &[1, 3, 132, 0, 34]; -const SECP521R1: &[u64] = &[1, 3, 132, 0, 35]; +use crate::{ec, key, key::SignatureHash, protocol, Error}; +use pkcs8::{EncodePrivateKey, PrivateKeyInfo, SecretDocument}; /// Decode a PKCS#8-encoded private key. pub fn decode_pkcs8(ciphertext: &[u8], password: Option<&[u8]>) -> Result { - let secret = if let Some(pass) = password { - Cow::Owned(yasna::parse_der(ciphertext, |reader| { - reader.read_sequence(|reader| { - // Encryption parameters - let parameters = reader.next().read_sequence(|reader| { - let oid = reader.next().read_oid()?; - if oid.components().as_slice() == PBES2 { - asn1_read_pbes2(reader) - } else { - Ok(Err(Error::UnknownAlgorithm(oid))) - } - })?; - // Ciphertext - let ciphertext = reader.next().read_bytes()?; - Ok(parameters.map(|p| p.decrypt(pass, &ciphertext))) - }) - })???) + let doc = SecretDocument::try_from(ciphertext)?; + let doc = if let Some(password) = password { + doc.decode_msg::()? + .decrypt(password)? } else { - Cow::Borrowed(ciphertext) + doc }; - yasna::parse_der(&secret, |reader| { - reader.read_sequence(|reader| { - let version = reader.next().read_u64()?; - if version == 0 { - Ok(read_key_v0(reader)) - } else if version == 1 { - Ok(read_key_v1(reader)) - } else { - Ok(Err(Error::CouldNotReadKey)) - } - }) - })? -} - -fn asn1_read_pbes2( - reader: &mut yasna::BERReaderSeq, -) -> Result, yasna::ASN1Error> { - reader.next().read_sequence(|reader| { - // PBES2 has two components. - // 1. Key generation algorithm - let keygen = reader.next().read_sequence(|reader| { - let oid = reader.next().read_oid()?; - if oid.components().as_slice() == PBKDF2 { - asn1_read_pbkdf2(reader) - } else { - Ok(Err(Error::UnknownAlgorithm(oid))) - } - })?; - // 2. Encryption algorithm. - let algorithm = reader.next().read_sequence(|reader| { - let oid = reader.next().read_oid()?; - if oid.components().as_slice() == AES256CBC { - asn1_read_aes256cbc(reader) - } else { - Ok(Err(Error::UnknownAlgorithm(oid))) - } - })?; - Ok(keygen.and_then(|keygen| algorithm.map(|algo| Algorithms::Pbes2(keygen, algo)))) - }) -} - -fn asn1_read_pbkdf2( - reader: &mut yasna::BERReaderSeq, -) -> Result, yasna::ASN1Error> { - reader.next().read_sequence(|reader| { - let salt = reader.next().read_bytes()?; - let rounds = reader.next().read_u64()?; - let digest = reader.next().read_sequence(|reader| { - let oid = reader.next().read_oid()?; - if oid.components().as_slice() == HMAC_SHA256 { - reader.next().read_null()?; - Ok(Ok(())) - } else { - Ok(Err(Error::UnknownAlgorithm(oid))) + key::KeyPair::try_from(doc.decode_msg::()?) +} + +impl<'a> TryFrom> for key::KeyPair { + type Error = Error; + + fn try_from(pki: PrivateKeyInfo<'a>) -> Result { + match pki.algorithm.oid { + ed25519_dalek::pkcs8::ALGORITHM_OID => Ok(key::KeyPair::Ed25519( + ed25519_dalek::pkcs8::KeypairBytes::try_from(pki)? + .secret_key + .into(), + )), + pkcs1::ALGORITHM_OID => { + let sk = &pkcs1::RsaPrivateKey::try_from(pki.private_key)?; + key::KeyPair::new_rsa_with_hash( + &sk.into(), + Some(&sk.into()), + SignatureHash::SHA2_256, + ) } - })?; - Ok(digest.map(|()| KeyDerivation::Pbkdf2 { salt, rounds })) - }) -} - -fn asn1_read_aes256cbc( - reader: &mut yasna::BERReaderSeq, -) -> Result, yasna::ASN1Error> { - let iv = reader.next().read_bytes()?; - let mut i = [0; 16]; - i.clone_from_slice(&iv); - Ok(Ok(Encryption::Aes256Cbc(i))) -} - -fn write_key_v1(writer: &mut yasna::DERWriterSeq, secret: &ed25519_dalek::SigningKey) { - let public = ed25519_dalek::VerifyingKey::from(secret); - writer.next().write_u32(1); - // write OID - writer.next().write_sequence(|writer| { - writer - .next() - .write_oid(&ObjectIdentifier::from_slice(ED25519)); - }); - let seed = yasna::construct_der(|writer| writer.write_bytes(secret.to_bytes().as_slice())); - writer.next().write_bytes(&seed); - writer - .next() - .write_tagged_implicit(yasna::Tag::context(1), |writer| { - writer.write_bitvec(&BitVec::from_bytes(public.as_bytes())) - }) + sec1::ALGORITHM_OID => Ok(key::KeyPair::EC { + key: pki.try_into()?, + }), + oid => Err(Error::UnknownAlgorithm(oid)), + } + } } -fn read_key_v1(reader: &mut BERReaderSeq) -> Result { - let oid = reader - .next() - .read_sequence(|reader| reader.next().read_oid())?; - if oid.components().as_slice() == ED25519 { - let key = parse_ed25519_private_key(&reader.next().read_bytes()?)?; - let _attributes = reader.read_optional(|reader| { - reader.read_tagged_implicit(yasna::Tag::context(0), |reader| reader.read_der()) - })?; - let _public_key = reader.read_optional(|reader| { - reader.read_tagged_implicit(yasna::Tag::context(1), |reader| reader.read_bitvec()) - })?; - Ok(key) - } else { - Err(Error::CouldNotReadKey) +impl<'a> From<&pkcs1::RsaPrivateKey<'a>> for protocol::RsaPrivateKey<'a> { + fn from(sk: &pkcs1::RsaPrivateKey<'a>) -> Self { + Self { + public_key: protocol::RsaPublicKey { + public_exponent: sk.public_exponent.as_bytes().into(), + modulus: sk.modulus.as_bytes().into(), + }, + private_exponent: sk.private_exponent.as_bytes().into(), + prime1: sk.prime1.as_bytes().into(), + prime2: sk.prime2.as_bytes().into(), + coefficient: sk.coefficient.as_bytes().into(), + comment: b"".as_slice().into(), + } } } -fn parse_ed25519_private_key(der: &[u8]) -> Result { - use ed25519_dalek::SigningKey; - let secret_bytes = yasna::parse_der(der, |reader| reader.read_bytes())?; - let secret_key = SigningKey::from( - <&[u8; ed25519_dalek::SECRET_KEY_LENGTH]>::try_from(secret_bytes.as_slice()) - .map_err(|_| Error::CouldNotReadKey)?, - ); - Ok(key::KeyPair::Ed25519(secret_key)) +impl<'a> From<&pkcs1::RsaPrivateKey<'a>> for key::RsaCrtExtra<'a> { + fn from(sk: &pkcs1::RsaPrivateKey<'a>) -> Self { + Self { + dp: sk.exponent1.as_bytes().into(), + dq: sk.exponent2.as_bytes().into(), + } + } } -fn write_key_v0_rsa(writer: &mut yasna::DERWriterSeq, key: &key::RsaPrivate) { - writer.next().write_u32(0); - // write OID - writer.next().write_sequence(|writer| { - writer.next().write_oid(&ObjectIdentifier::from_slice(RSA)); - writer.next().write_null() - }); - #[allow(clippy::unwrap_used)] // key is known to be private - let (sk, extra) = ( - protocol::RsaPrivateKey::try_from(key).unwrap(), - key::RsaCrtExtra::try_from(key).unwrap(), - ); - let bytes = yasna::construct_der(|writer| { - writer.write_sequence(|writer| { - writer.next().write_u32(0); - use num_bigint::BigUint; - writer - .next() - .write_biguint(&BigUint::from_bytes_be(&sk.public_key.modulus)); - writer - .next() - .write_biguint(&BigUint::from_bytes_be(&sk.public_key.public_exponent)); - writer - .next() - .write_biguint(&BigUint::from_bytes_be(&sk.private_exponent)); - writer - .next() - .write_biguint(&BigUint::from_bytes_be(&sk.prime1)); - writer - .next() - .write_biguint(&BigUint::from_bytes_be(&sk.prime2)); - writer - .next() - .write_biguint(&BigUint::from_bytes_be(&extra.dp)); - writer - .next() - .write_biguint(&BigUint::from_bytes_be(&extra.dq)); - writer - .next() - .write_biguint(&BigUint::from_bytes_be(&sk.coefficient)); - }) - }); - writer.next().write_bytes(&bytes); +// Note: It's infeasible to implement `EncodePrivateKey` because that is bound to `pkcs8::Result`. +impl TryFrom<&key::RsaPrivate> for SecretDocument { + type Error = Error; + + fn try_from(key: &key::RsaPrivate) -> Result { + use der::Encode; + use pkcs1::UintRef; + + let sk = protocol::RsaPrivateKey::try_from(key)?; + let extra = key::RsaCrtExtra::try_from(key)?; + + let rsa_private_key = pkcs1::RsaPrivateKey { + modulus: UintRef::new(&sk.public_key.modulus)?, + public_exponent: UintRef::new(&sk.public_key.public_exponent)?, + private_exponent: UintRef::new(&sk.private_exponent)?, + prime1: UintRef::new(&sk.prime1)?, + prime2: UintRef::new(&sk.prime2)?, + exponent1: UintRef::new(&extra.dp)?, + exponent2: UintRef::new(&extra.dq)?, + coefficient: UintRef::new(&sk.coefficient)?, + other_prime_infos: None, + }; + let pki = PrivateKeyInfo { + algorithm: spki::AlgorithmIdentifier { + oid: pkcs1::ALGORITHM_OID, + parameters: Some(der::asn1::Null.into()), + }, + private_key: &rsa_private_key.to_der()?, + public_key: None, + }; + Ok(Self::try_from(pki)?) + } } -fn write_key_v0_ec(writer: &mut yasna::DERWriterSeq, key: &crate::ec::PrivateKey) { - writer.next().write_u32(0); - writer.next().write_sequence(|writer| { - writer - .next() - .write_oid(&ObjectIdentifier::from_slice(EC_PUBLIC_KEY)); - writer - .next() - .write_oid(&ObjectIdentifier::from_slice(match key { - crate::ec::PrivateKey::P256(_) => SECP256R1, - crate::ec::PrivateKey::P384(_) => SECP384R1, - crate::ec::PrivateKey::P521(_) => SECP521R1, - })) - }); - let bytes = yasna::construct_der(|writer| { - #[allow(clippy::unwrap_used)] // key is known to be private - writer.write_sequence(|writer| { - writer.next().write_u32(1); - writer.next().write_bytes(&key.to_secret_bytes()); - writer - .next() - .write_tagged(yasna::Tag::context(1), |writer| { - writer.write_bitvec(&BitVec::from_bytes(&key.to_public_key().to_sec1_bytes())) - }); - }) - }); - writer.next().write_bytes(&bytes); -} +impl TryFrom> for ec::PrivateKey { + type Error = Error; -// Utility enum used for reading v0 key. -enum KeyType { - Unknown(ObjectIdentifier), - #[allow(clippy::upper_case_acronyms)] - ED25519, - #[allow(clippy::upper_case_acronyms)] - RSA, - EC(ObjectIdentifier), + fn try_from(pki: PrivateKeyInfo<'_>) -> Result { + use pkcs8::AssociatedOid; + match pki.algorithm.parameters_oid()? { + p256::NistP256::OID => Ok(ec::PrivateKey::P256(pki.try_into()?)), + p384::NistP384::OID => Ok(ec::PrivateKey::P384(pki.try_into()?)), + p521::NistP521::OID => Ok(ec::PrivateKey::P521(pki.try_into()?)), + oid => Err(Error::UnknownAlgorithm(oid)), + } + } } -fn read_key_v0(reader: &mut BERReaderSeq) -> Result { - let key_type = reader.next().read_sequence(|reader| { - let oid = reader.next().read_oid()?; - Ok(match oid.components().as_slice() { - ED25519 => KeyType::ED25519, - RSA => { - reader.next().read_null()?; - KeyType::RSA - } - EC_PUBLIC_KEY => KeyType::EC(reader.next().read_oid()?), - _ => KeyType::Unknown(oid), - }) - })?; - match key_type { - KeyType::Unknown(_) => Err(Error::CouldNotReadKey), - KeyType::ED25519 => parse_ed25519_private_key(&reader.next().read_bytes()?), - KeyType::RSA => { - let seq = &reader.next().read_bytes()?; - let (sk, extra) = yasna::parse_der(seq, |reader| { - reader.read_sequence(|reader| { - let version = reader.next().read_u32()?; - if version != 0 { - return Ok(Err(Error::CouldNotReadKey)); - } - let (n, e, d, p, q, dmp1, dmq1, iqmp) = ( - reader.next().read_biguint()?.to_bytes_be(), - reader.next().read_biguint()?.to_bytes_be(), - reader.next().read_biguint()?.to_bytes_be(), - reader.next().read_biguint()?.to_bytes_be(), - reader.next().read_biguint()?.to_bytes_be(), - reader.next().read_biguint()?.to_bytes_be(), - reader.next().read_biguint()?.to_bytes_be(), - reader.next().read_biguint()?.to_bytes_be(), - ); - Ok(Ok(( - protocol::RsaPrivateKey { - public_key: protocol::RsaPublicKey { - modulus: n.into(), - public_exponent: e.into(), - }, - private_exponent: d.into(), - prime1: p.into(), - prime2: q.into(), - coefficient: iqmp.into(), - comment: Cow::Borrowed(b""), - }, - key::RsaCrtExtra { - dp: dmp1.into(), - dq: dmq1.into(), - }, - ))) - }) - })??; - Ok(key::KeyPair::new_rsa_with_hash( - &sk, - Some(&extra), - SignatureHash::SHA2_256, - )?) - } - KeyType::EC(oid) => { - let private_key = reader.next().read_bytes()?; - let (version, secret_key, public_key) = yasna::parse_der(&private_key, |reader| { - reader.read_sequence(|reader| { - // Per RFC 5915, section 3: - // ECPrivateKey ::= SEQUENCE { - // version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), - // privateKey OCTET STRING, - // parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, - // publicKey [1] BIT STRING OPTIONAL - // } - let version = reader.next().read_u64()?; - let secret_key = reader.next().read_bytes()?; - let _named_curve = reader.read_optional(|reader| { - reader.read_tagged(yasna::Tag::context(0), |reader| reader.read_oid()) - })?; - let public_key = reader.read_optional(|reader| { - reader.read_tagged(yasna::Tag::context(1), |reader| reader.read_bitvec()) - })?; - Ok((version, secret_key, public_key)) - }) - })?; - if version != 1 { - return Err(Error::CouldNotReadKey); - } - let key = crate::ec::PrivateKey::new_from_secret_scalar( - match oid.components().as_slice() { - SECP256R1 => crate::KEYTYPE_ECDSA_SHA2_NISTP256, - SECP384R1 => crate::KEYTYPE_ECDSA_SHA2_NISTP384, - SECP521R1 => crate::KEYTYPE_ECDSA_SHA2_NISTP521, - _ => return Err(Error::CouldNotReadKey), - }, - &secret_key, - )?; - if let Some(public_key) = public_key { - if key.to_public_key().to_sec1_bytes() != public_key.to_bytes() { - return Err(Error::CouldNotReadKey); - } - } - Ok(key::KeyPair::EC { key }) +impl EncodePrivateKey for ec::PrivateKey { + fn to_pkcs8_der(&self) -> pkcs8::Result { + match self { + ec::PrivateKey::P256(key) => key.to_pkcs8_der(), + ec::PrivateKey::P384(key) => key.to_pkcs8_der(), + ec::PrivateKey::P521(key) => key.to_pkcs8_der(), } } } #[test] fn test_read_write_pkcs8() { - let secret = ed25519_dalek::SigningKey::generate(&mut OsRng {}); + let secret = ed25519_dalek::SigningKey::generate(&mut key::safe_rng()); assert_eq!( secret.verifying_key().as_bytes(), ed25519_dalek::VerifyingKey::from(&secret).as_bytes() @@ -366,171 +142,38 @@ fn test_read_write_pkcs8() { } } -use aes::*; -use yasna::models::ObjectIdentifier; - /// Encode a password-protected PKCS#8-encoded private key. pub fn encode_pkcs8_encrypted( pass: &[u8], rounds: u32, key: &key::KeyPair, ) -> Result, Error> { + let pvi_bytes = encode_pkcs8(key)?; + let pvi = PrivateKeyInfo::try_from(pvi_bytes.as_slice())?; + use rand::RngCore; let mut rng = rand::thread_rng(); let mut salt = [0; 64]; rng.fill_bytes(&mut salt); let mut iv = [0; 16]; rng.fill_bytes(&mut iv); - let mut dkey = [0; 32]; // AES256-CBC - pbkdf2::pbkdf2::>(pass, &salt, rounds, &mut dkey); - let mut plaintext = encode_pkcs8(key); - let padding_len = 32 - (plaintext.len() % 32); - plaintext.extend(std::iter::repeat(padding_len as u8).take(padding_len)); - - #[allow(clippy::unwrap_used)] // parameters are static - let c = cbc::Encryptor::::new_from_slices(&dkey, &iv).unwrap(); - let n = plaintext.len(); - let encrypted = c.encrypt_padded_mut::(&mut plaintext, n)?; - - Ok(yasna::construct_der(|writer| { - writer.write_sequence(|writer| { - // Encryption parameters - writer.next().write_sequence(|writer| { - writer - .next() - .write_oid(&ObjectIdentifier::from_slice(PBES2)); - asn1_write_pbes2(writer.next(), rounds as u64, &salt, &iv) - }); - // Ciphertext - writer.next().write_bytes(encrypted) - }) - })) + let doc = pvi.encrypt_with_params( + pkcs5::pbes2::Parameters::pbkdf2_sha256_aes256cbc(rounds, &salt, &iv) + .map_err(|_| Error::InvalidParameters)?, + pass, + )?; + Ok(doc.as_bytes().to_vec()) } /// Encode a Decode a PKCS#8-encoded private key. -pub fn encode_pkcs8(key: &key::KeyPair) -> Vec { - yasna::construct_der(|writer| { - writer.write_sequence(|writer| match *key { - key::KeyPair::Ed25519(ref pair) => write_key_v1(writer, pair), - key::KeyPair::RSA { ref key, .. } => write_key_v0_rsa(writer, key), - key::KeyPair::EC { ref key, .. } => write_key_v0_ec(writer, key), - }) - }) -} - -fn asn1_write_pbes2(writer: yasna::DERWriter, rounds: u64, salt: &[u8], iv: &[u8]) { - writer.write_sequence(|writer| { - // 1. Key generation algorithm - writer.next().write_sequence(|writer| { - writer - .next() - .write_oid(&ObjectIdentifier::from_slice(PBKDF2)); - asn1_write_pbkdf2(writer.next(), rounds, salt) - }); - // 2. Encryption algorithm. - writer.next().write_sequence(|writer| { - writer - .next() - .write_oid(&ObjectIdentifier::from_slice(AES256CBC)); - writer.next().write_bytes(iv) - }); - }) -} - -fn asn1_write_pbkdf2(writer: yasna::DERWriter, rounds: u64, salt: &[u8]) { - writer.write_sequence(|writer| { - writer.next().write_bytes(salt); - writer.next().write_u64(rounds); - writer.next().write_sequence(|writer| { - writer - .next() - .write_oid(&ObjectIdentifier::from_slice(HMAC_SHA256)); - writer.next().write_null() - }) - }) -} - -enum Algorithms { - Pbes2(KeyDerivation, Encryption), -} - -impl Algorithms { - fn decrypt(&self, password: &[u8], cipher: &[u8]) -> Result, Error> { - match *self { - Algorithms::Pbes2(ref der, ref enc) => { - let mut key = enc.key(); - der.derive(password, &mut key)?; - let out = enc.decrypt(&key, cipher)?; - Ok(out) - } - } - } -} - -impl KeyDerivation { - fn derive(&self, password: &[u8], key: &mut [u8]) -> Result<(), Error> { - match *self { - KeyDerivation::Pbkdf2 { ref salt, rounds } => { - pbkdf2::pbkdf2::>(password, salt, rounds as u32, key) - // pbkdf2_hmac(password, salt, rounds as usize, digest, key)? - } - } - Ok(()) - } -} - -#[derive(Debug)] -enum Key { - K128([u8; 16]), - K256([u8; 32]), -} - -impl std::ops::Deref for Key { - type Target = [u8]; - fn deref(&self) -> &[u8] { - match *self { - Key::K128(ref k) => k, - Key::K256(ref k) => k, - } +pub fn encode_pkcs8(key: &key::KeyPair) -> Result, Error> { + let v = match *key { + key::KeyPair::Ed25519(ref pair) => pair.to_pkcs8_der()?, + key::KeyPair::RSA { ref key, .. } => SecretDocument::try_from(key)?, + key::KeyPair::EC { ref key, .. } => key.to_pkcs8_der()?, } -} - -impl std::ops::DerefMut for Key { - fn deref_mut(&mut self) -> &mut [u8] { - match *self { - Key::K128(ref mut k) => k, - Key::K256(ref mut k) => k, - } - } -} - -impl Encryption { - fn key(&self) -> Key { - match *self { - Encryption::Aes128Cbc(_) => Key::K128([0; 16]), - Encryption::Aes256Cbc(_) => Key::K256([0; 32]), - } - } - - fn decrypt(&self, key: &[u8], ciphertext: &[u8]) -> Result, Error> { - match *self { - Encryption::Aes128Cbc(ref iv) => { - #[allow(clippy::unwrap_used)] // parameters are static - let c = cbc::Decryptor::::new_from_slices(key, iv).unwrap(); - let mut dec = ciphertext.to_vec(); - Ok(c.decrypt_padded_mut::(&mut dec)?.into()) - } - Encryption::Aes256Cbc(ref iv) => { - #[allow(clippy::unwrap_used)] // parameters are static - let c = cbc::Decryptor::::new_from_slices(key, iv).unwrap(); - let mut dec = ciphertext.to_vec(); - Ok(c.decrypt_padded_mut::(&mut dec)?.into()) - } - } - } -} - -enum KeyDerivation { - Pbkdf2 { salt: Vec, rounds: u64 }, + .as_bytes() + .to_vec(); + Ok(v) } diff --git a/russh-keys/src/lib.rs b/russh-keys/src/lib.rs index 97cbd53e..98cc4157 100644 --- a/russh-keys/src/lib.rs +++ b/russh-keys/src/lib.rs @@ -126,8 +126,8 @@ pub enum Error { #[error("The server key changed at line {}", line)] KeyChanged { line: usize }, /// The key uses an unsupported algorithm - #[error("Unknown key algorithm")] - UnknownAlgorithm(yasna::models::ObjectIdentifier), + #[error("Unknown key algorithm: {0}")] + UnknownAlgorithm(::pkcs8::ObjectIdentifier), /// Index out of bounds #[error("Index out of bounds")] IndexOutOfBounds, @@ -136,6 +136,8 @@ pub enum Error { UnknownSignatureType { sig_type: String }, #[error("Invalid signature")] InvalidSignature, + #[error("Invalid parameters")] + InvalidParameters, /// Agent protocol error #[error("Agent protocol error")] AgentProtocolError, @@ -151,9 +153,6 @@ pub enum Error { #[cfg(not(feature = "openssl"))] #[error("Rsa: {0}")] Rsa(#[from] rsa::Error), - #[cfg(not(feature = "openssl"))] - #[error("Pkcs1: {0}")] - Pkcs1(#[from] pkcs1::Error), #[error(transparent)] Pad(#[from] PadError), @@ -163,8 +162,17 @@ pub enum Error { #[error("Base64 decoding error: {0}")] Decode(#[from] data_encoding::DecodeError), - #[error("ASN1 decoding error: {0}")] - ASN1(yasna::ASN1Error), + #[error("Der: {0}")] + Der(#[from] der::Error), + #[error("Spki: {0}")] + Spki(#[from] spki::Error), + #[error("Pkcs1: {0}")] + Pkcs1(#[from] pkcs1::Error), + #[error("Pkcs8: {0}")] + Pkcs8(#[from] ::pkcs8::Error), + #[error("Sec1: {0}")] + Sec1(#[from] sec1::Error), + #[error("Environment variable `{0}` not found")] EnvVar(&'static str), #[error( @@ -174,12 +182,6 @@ pub enum Error { BadAuthSock, } -impl From for Error { - fn from(e: yasna::ASN1Error) -> Error { - Error::ASN1(e) - } -} - const KEYTYPE_ED25519: &[u8] = b"ssh-ed25519"; const KEYTYPE_RSA: &[u8] = b"ssh-rsa"; const KEYTYPE_ECDSA_SHA2_NISTP256: &[u8] = ECDSA_SHA2_NISTP256.as_bytes(); @@ -898,7 +900,7 @@ Ow== ) .unwrap(); let decoded_key = decode_secret_key(key, None).unwrap(); - let encoded_key_bytes = pkcs8::encode_pkcs8(&decoded_key); + let encoded_key_bytes = pkcs8::encode_pkcs8(&decoded_key).unwrap(); assert_eq!(original_key_bytes, encoded_key_bytes); }