diff --git a/russh-keys/Cargo.toml b/russh-keys/Cargo.toml index da7f15c7..bc03daee 100644 --- a/russh-keys/Cargo.toml +++ b/russh-keys/Cargo.toml @@ -49,8 +49,10 @@ inout = { version = "0.1", features = ["std"] } log = "0.4" md5 = "0.7" num-bigint = "0.4" +num-bigint-dig = { version = "0.8.2", default-features = false, package = "num-bigint-dig" } num-integer = "0.1" openssl = { version = "0.10", optional = true } +rsa = { version = "0.9.6", features = ["sha1", "sha2"]} p256 = "0.13" p384 = "0.13" p521 = "0.13" @@ -62,7 +64,14 @@ serde = { version = "1.0", features = ["derive"] } sha1 = "0.10" sha2 = "0.10" thiserror = "1.0" -tokio = { version = "1.17.0", features = ["io-util", "rt-multi-thread", "time", "net"] } +tokio = { version = "1.36.0", features = [ + "io-util", + "rt-multi-thread", + "time", + "net", + "macros", + "process" +] } tokio-stream = { version = "0.1", features = ["net"] } typenum = "1.17" yasna = { version = "0.5.0", features = ["bit-vec", "num-bigint"] } diff --git a/russh-keys/src/agent/client.rs b/russh-keys/src/agent/client.rs index 560c3f9b..01602e10 100644 --- a/russh-keys/src/agent/client.rs +++ b/russh-keys/src/agent/client.rs @@ -2,6 +2,8 @@ use std::convert::TryFrom; use byteorder::{BigEndian, ByteOrder}; use log::{debug, info}; +#[cfg(not(feature = "openssl"))] +use rsa::traits::{PrivateKeyParts, PublicKeyParts}; use russh_cryptovec::CryptoVec; use tokio; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; @@ -140,6 +142,32 @@ impl AgentClient { self.buf.extend_ssh_mpint(&key.q().unwrap().to_vec()); self.buf.extend_ssh_string(b""); } + #[cfg(not(feature = "openssl"))] + key::KeyPair::RSA { ref key, .. } => { + use num_bigint_dig::traits::ModInverse; + + self.buf.extend_ssh_string(b"ssh-rsa"); + self.buf.extend_ssh_mpint(&key.n().to_bytes_be()); + self.buf.extend_ssh_mpint(&key.e().to_bytes_be()); + self.buf.extend_ssh_mpint(&key.d().to_bytes_be()); + let primes = key.primes(); + if let Some(iqmp) = key.crt_coefficient() { + self.buf.extend_ssh_mpint(&iqmp.to_bytes_be()); + } else if let Some(iqmp) = &primes + .get(0) + .ok_or(Error::IndexOutOfBounds)? + .mod_inverse(primes.get(1).ok_or(Error::IndexOutOfBounds)?) + { + let (_, val) = &iqmp.to_bytes_be(); + self.buf.extend_ssh_mpint(val); + } + self.buf + .extend_ssh_mpint(&primes.get(0).ok_or(Error::IndexOutOfBounds)?.to_bytes_be()); + self.buf + .extend_ssh_mpint(&primes.get(1).ok_or(Error::IndexOutOfBounds)?.to_bytes_be()); + self.buf.extend_ssh_string(b""); + } + key::KeyPair::EC { ref key } => { self.buf.extend_ssh_string(key.algorithm().as_bytes()); self.buf.extend_ssh_string(key.ident().as_bytes()); @@ -282,6 +310,20 @@ impl AgentClient { hash: SignatureHash::SHA2_512, }) } + #[cfg(not(feature = "openssl"))] + b"ssh-rsa" => { + let e = r.read_mpint()?; + let n = r.read_mpint()?; + use rsa::{RsaPublicKey, BigUint}; + + let e = BigUint::from_bytes_be(&e); + let n = BigUint::from_bytes_be(&n); + + keys.push(PublicKey::RSA { + key: RsaPublicKey::new(n, e)?, + hash: SignatureHash::SHA2_512, + }) + } b"ssh-ed25519" => keys.push(PublicKey::Ed25519( ed25519_dalek::VerifyingKey::try_from(r.read_string()?)?, )), @@ -351,7 +393,6 @@ impl AgentClient { self.buf.extend_ssh_string(data); debug!("public = {:?}", public); let hash = match public { - #[cfg(feature = "openssl")] PublicKey::RSA { hash, .. } => match hash { SignatureHash::SHA2_256 => 2, SignatureHash::SHA2_512 => 4, @@ -534,14 +575,23 @@ impl AgentClient { fn key_blob(public: &key::PublicKey, buf: &mut CryptoVec) -> Result<(), Error> { match *public { - #[cfg(feature = "openssl")] PublicKey::RSA { ref key, .. } => { buf.extend(&[0, 0, 0, 0]); let len0 = buf.len(); buf.extend_ssh_string(b"ssh-rsa"); - let rsa = key.0.rsa()?; - buf.extend_ssh_mpint(&rsa.e().to_vec()); - buf.extend_ssh_mpint(&rsa.n().to_vec()); + #[cfg(feature = "openssl")] + { + let rsa = key.0.rsa()?; + buf.extend_ssh_mpint(&rsa.e().to_vec()); + buf.extend_ssh_mpint(&rsa.n().to_vec()); + } + #[cfg(not(feature = "openssl"))] + { + let rsa = key.clone(); + buf.extend_ssh_mpint(&rsa.e().to_bytes_be()); + buf.extend_ssh_mpint(&rsa.n().to_bytes_be()); + } + let len1 = buf.len(); #[allow(clippy::indexing_slicing)] // length is known BigEndian::write_u32(&mut buf[5..], (len1 - len0) as u32); diff --git a/russh-keys/src/agent/server.rs b/russh-keys/src/agent/server.rs index b8078539..a85d9635 100644 --- a/russh-keys/src/agent/server.rs +++ b/russh-keys/src/agent/server.rs @@ -15,8 +15,9 @@ use {std, tokio}; use super::{msg, Constraint}; use crate::encoding::{Encoding, Position, Reader}; -#[cfg(feature = "openssl")] use crate::key::SignatureHash; +#[cfg(not(feature = "openssl"))] +use rsa::{RsaPrivateKey, BigUint}; use crate::{key, Error}; #[derive(Clone)] @@ -321,6 +322,38 @@ impl { + let n = r.read_string()?; + let e = r.read_string()?; + + let n_buint = BigUint::from_bytes_be(n); + let e_buint = BigUint::from_bytes_be(e); + let d = BigUint::from_bytes_be(r.read_string()?); + let _ = r.read_string()?; + let p = BigUint::from_bytes_be(r.read_string()?); + let q = BigUint::from_bytes_be(r.read_string()?); + + let key = RsaPrivateKey::from_components(n_buint, e_buint, d, vec![p, q])?; + + let len0 = writebuf.len(); + writebuf.extend_ssh_string(b"ssh-rsa"); + writebuf.extend_ssh_mpint(e); + writebuf.extend_ssh_mpint(n); + + #[allow(clippy::indexing_slicing)] // length is known + let blob = writebuf[len0..].to_vec(); + writebuf.resize(len0); + writebuf.push(msg::SUCCESS); + + ( + blob, + key::KeyPair::RSA { + key: key, + hash: SignatureHash::SHA2_256, // Assuming SHA2_256 is compatible with your needs + }, + ) + } _ => return Ok(false), }; let mut w = self.keys.0.write().or(Err(Error::AgentFailure))?; diff --git a/russh-keys/src/format/mod.rs b/russh-keys/src/format/mod.rs index 1463a85d..c7e00869 100644 --- a/russh-keys/src/format/mod.rs +++ b/russh-keys/src/format/mod.rs @@ -1,21 +1,17 @@ use std::io::Write; -#[cfg(not(feature = "openssl"))] -use data_encoding::BASE64_MIME; -#[cfg(feature = "openssl")] use data_encoding::{BASE64_MIME, HEXLOWER_PERMISSIVE}; +#[cfg(not(feature = "openssl"))] +use rsa::{self, RsaPrivateKey, pkcs1::DecodeRsaPrivateKey}; #[cfg(feature = "openssl")] use openssl::rsa::Rsa; use super::is_base64_char; use crate::{key, Error}; +pub mod pkcs5; pub mod openssh; pub use self::openssh::*; - -#[cfg(feature = "openssl")] -pub mod pkcs5; -#[cfg(feature = "openssl")] pub use self::pkcs5::*; pub mod pkcs8; @@ -33,20 +29,29 @@ pub enum Encryption { #[derive(Clone, Debug)] enum Format { - #[cfg(feature = "openssl")] Rsa, Openssh, - #[cfg(feature = "openssl")] Pkcs5Encrypted(Encryption), Pkcs8Encrypted, Pkcs8, } +/// Parse the header line to determine the format of the secret key. +fn parse_header(line: &str) -> Option { + match line { + "-----BEGIN OPENSSH PRIVATE KEY-----" => Some(Format::Openssh), + "-----BEGIN RSA PRIVATE KEY-----" => Some(Format::Rsa), + "-----BEGIN ENCRYPTED PRIVATE KEY-----" => Some(Format::Pkcs8Encrypted), + "-----BEGIN PRIVATE KEY-----" => Some(Format::Pkcs8), + _ => None, + } +} + /// Decode a secret key, possibly deciphering it with the supplied /// password. pub fn decode_secret_key(secret: &str, password: Option<&str>) -> Result { let mut format = None; - let secret = { + let secret: String = { let mut started = false; let mut sec = String::new(); for l in secret.lines() { @@ -57,41 +62,18 @@ pub fn decode_secret_key(secret: &str, password: Option<&str>) -> Result = HEXLOWER_PERMISSIVE - .decode(l.split_at(AES_128_CBC.len()).1.as_bytes())?; - if iv_.len() != 16 { - return Err(Error::CouldNotReadKey); - } - let mut iv = [0; 16]; - iv.clone_from_slice(&iv_); - format = Some(Format::Pkcs5Encrypted(Encryption::Aes128Cbc(iv))) + let iv_: Vec = HEXLOWER_PERMISSIVE + .decode(l.split_at(AES_128_CBC.len()).1.as_bytes())?; + if iv_.len() != 16 { + return Err(Error::CouldNotReadKey); } + let mut iv = [0; 16]; + iv.clone_from_slice(&iv_); + format = Some(Format::Pkcs5Encrypted(Encryption::Aes128Cbc(iv))) } - } - if l == "-----BEGIN OPENSSH PRIVATE KEY-----" { - started = true; - format = Some(Format::Openssh); - } else if l == "-----BEGIN RSA PRIVATE KEY-----" { - #[cfg(not(feature = "openssl"))] - { - return Err(Error::UnsupportedKeyType { - key_type_string: "rsa".to_owned(), - key_type_raw: "rsa".as_bytes().to_vec(), - }); - } - #[cfg(feature = "openssl")] - { - started = true; - format = Some(Format::Rsa); - } - } else if l == "-----BEGIN ENCRYPTED PRIVATE KEY-----" { + } else { + format = parse_header(l); started = true; - format = Some(Format::Pkcs8Encrypted); - } else if l == "-----BEGIN PRIVATE KEY-----" { - started = true; - format = Some(Format::Pkcs8); } } sec @@ -100,9 +82,7 @@ pub fn decode_secret_key(secret: &str, password: Option<&str>) -> Result decode_openssh(&secret, password), - #[cfg(feature = "openssl")] Some(Format::Rsa) => decode_rsa(&secret), - #[cfg(feature = "openssl")] 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())) @@ -132,10 +112,12 @@ pub fn encode_pkcs8_pem_encrypted( Ok(()) } -#[cfg(feature = "openssl")] fn decode_rsa(secret: &[u8]) -> Result { Ok(key::KeyPair::RSA { + #[cfg(feature = "openssl")] key: Rsa::private_key_from_der(secret)?, + #[cfg(not(feature = "openssl"))] + key: RsaPrivateKey::from_pkcs1_der(secret).map_err(rsa::Error::from)?, hash: key::SignatureHash::SHA2_256, }) } diff --git a/russh-keys/src/format/openssh.rs b/russh-keys/src/format/openssh.rs index 21fbed3e..ab9d2a9c 100644 --- a/russh-keys/src/format/openssh.rs +++ b/russh-keys/src/format/openssh.rs @@ -6,7 +6,11 @@ use bcrypt_pbkdf; use ctr::Ctr64BE; #[cfg(feature = "openssl")] use openssl::bn::BigNum; - +#[cfg(not(feature = "openssl"))] +use { + rsa::BigUint, + rsa::RsaPrivateKey +}; use crate::encoding::Reader; use crate::{ec, key, Error, KEYTYPE_ED25519, KEYTYPE_RSA}; @@ -48,7 +52,7 @@ pub fn decode_openssh(secret: &[u8], password: Option<&str>) -> Result) -> Result, diff --git a/russh-keys/src/format/pkcs8.rs b/russh-keys/src/format/pkcs8.rs index 4a6bec8b..242d6b9c 100644 --- a/russh-keys/src/format/pkcs8.rs +++ b/russh-keys/src/format/pkcs8.rs @@ -4,26 +4,28 @@ use std::convert::TryFrom; use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit}; use bit_vec::BitVec; use block_padding::{NoPadding, Pkcs7}; -#[cfg(feature = "openssl")] -use openssl::pkey::Private; -#[cfg(feature = "openssl")] -use openssl::rsa::Rsa; #[cfg(test)] use rand_core::OsRng; +#[cfg(not(feature = "openssl"))] +use rsa::{ + traits::{PrivateKeyParts, PublicKeyParts}, + RsaPrivateKey, + BigUint +}; use yasna::BERReaderSeq; +#[cfg(feature = "openssl")] +use {openssl::pkey::Private, openssl::rsa::Rsa}; use {std, yasna}; use super::Encryption; -#[cfg(feature = "openssl")] -use crate::key::SignatureHash; use crate::{key, Error}; +use crate::key::SignatureHash; 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]; -#[cfg(feature = "openssl")] 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]; @@ -168,6 +170,63 @@ fn read_key_v1(reader: &mut BERReaderSeq) -> Result { } } +#[cfg(not(feature = "openssl"))] +fn write_key_v0_rsa(writer: &mut yasna::DERWriterSeq, key: &RsaPrivateKey) { + // Construct DER sequence + writer.next().write_u32(0); // Version + writer.next().write_sequence(|writer| { + writer.next().write_oid(&ObjectIdentifier::from_slice(RSA)); + writer.next().write_null(); + }); + + // Encode key data + let bytes = yasna::construct_der(|writer| { + let _ = writer.write_sequence(|writer| -> Result<(), Error> { + writer.next().write_u32(0); // Version + use num_bigint::BigUint; + + writer + .next() + .write_biguint(&BigUint::from_bytes_be(&key.n().to_bytes_be())); + writer + .next() + .write_biguint(&BigUint::from_bytes_be(&key.e().to_bytes_be())); + writer + .next() + .write_biguint(&BigUint::from_bytes_be(&key.d().to_bytes_be())); + + let primes = key.primes(); + + writer.next().write_biguint(&BigUint::from_bytes_be( + &primes.get(0).ok_or(Error::IndexOutOfBounds)?.to_bytes_be(), + )); + writer.next().write_biguint(&BigUint::from_bytes_be( + &primes.get(1).ok_or(Error::IndexOutOfBounds)?.to_bytes_be(), + )); + + let mut key = key.clone(); + key.precompute()?; // Compute dp/dq/crt_coefficient values + + if let (Some(dp), Some(dq), Some(iqmp)) = (key.dp(), key.dq(), key.crt_coefficient()) { + writer + .next() + .write_biguint(&BigUint::from_bytes_be(&dp.to_bytes_be())); + writer + .next() + .write_biguint(&BigUint::from_bytes_be(&dq.to_bytes_be())); + writer + .next() + .write_biguint(&BigUint::from_bytes_be(&iqmp.to_bytes_be())); + }; + Ok(()) + }); + }); + + // Write encoded bytes + writer.next().write_bytes(&bytes); +} + + #[cfg(feature = "openssl")] fn write_key_v0_rsa(writer: &mut yasna::DERWriterSeq, key: &Rsa) { writer.next().write_u32(0); @@ -210,6 +269,35 @@ fn write_key_v0_rsa(writer: &mut yasna::DERWriterSeq, key: &Rsa) { writer.next().write_bytes(&bytes); } +#[cfg(feature = "openssl")] +fn read_key(reader: &mut BERReaderSeq) -> Result, Error>{ + use openssl::bn::BigNum; + Ok(Rsa::from_private_components( + BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, + BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, + BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, + BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, + BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, + BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, + BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, + BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, + )?) +} + +#[allow(unused_must_use)] +#[cfg(not(feature = "openssl"))] +fn read_key(reader: &mut BERReaderSeq) -> Result { + let n = BigUint::from_bytes_be(&reader.next().read_biguint()?.to_bytes_be()); + let e = BigUint::from_bytes_be(&reader.next().read_biguint()?.to_bytes_be()); + let d = BigUint::from_bytes_be(&reader.next().read_biguint()?.to_bytes_be()); + let p = BigUint::from_bytes_be(&reader.next().read_biguint()?.to_bytes_be()); + let q = BigUint::from_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(RsaPrivateKey::from_components(n, e, d, vec![p, q])?) +} + fn write_key_v0_ec(writer: &mut yasna::DERWriterSeq, key: &crate::ec::PrivateKey) { writer.next().write_u32(0); writer.next().write_sequence(|writer| { @@ -242,8 +330,6 @@ fn write_key_v0_ec(writer: &mut yasna::DERWriterSeq, key: &crate::ec::PrivateKey // Utility enum used for reading v0 key. enum KeyType { Unknown(ObjectIdentifier), - #[cfg(feature = "openssl")] - #[allow(clippy::upper_case_acronyms)] RSA, EC(ObjectIdentifier), } @@ -252,7 +338,6 @@ 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() { - #[cfg(feature = "openssl")] RSA => { reader.next().read_null()?; KeyType::RSA @@ -263,29 +348,15 @@ fn read_key_v0(reader: &mut BERReaderSeq) -> Result { })?; match key_type { KeyType::Unknown(_) => Err(Error::CouldNotReadKey), - #[cfg(feature = "openssl")] KeyType::RSA => { let seq = &reader.next().read_bytes()?; - let rsa: Result, Error> = yasna::parse_der(seq, |reader| { + let rsa = yasna::parse_der(seq, |reader| { reader.read_sequence(|reader| { let version = reader.next().read_u32()?; if version != 0 { return Ok(Err(Error::CouldNotReadKey)); } - use openssl::bn::BigNum; - let mut read_key = || -> Result, Error> { - Ok(Rsa::from_private_components( - BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, - BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, - BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, - BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, - BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, - BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, - BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, - BigNum::from_slice(&reader.next().read_biguint()?.to_bytes_be())?, - )?) - }; - Ok(read_key()) + Ok(read_key(reader)) }) })?; Ok(key::KeyPair::RSA { @@ -351,7 +422,6 @@ fn test_read_write_pkcs8() { match key { key::KeyPair::Ed25519 { .. } => println!("Ed25519"), key::KeyPair::EC { .. } => println!("EC"), - #[cfg(feature = "openssl")] key::KeyPair::RSA { .. } => println!("RSA"), } } @@ -403,7 +473,6 @@ 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), - #[cfg(feature = "openssl")] key::KeyPair::RSA { ref key, .. } => write_key_v0_rsa(writer, key), key::KeyPair::EC { ref key, .. } => write_key_v0_ec(writer, key), }) diff --git a/russh-keys/src/key.rs b/russh-keys/src/key.rs index dcb578ee..ff83b7e9 100644 --- a/russh-keys/src/key.rs +++ b/russh-keys/src/key.rs @@ -15,11 +15,26 @@ use std::convert::TryFrom; use ed25519_dalek::{Signer, Verifier}; -#[cfg(feature = "openssl")] -use openssl::pkey::{Private, Public}; use rand_core::OsRng; use russh_cryptovec::CryptoVec; use serde::{Deserialize, Serialize}; +#[cfg(feature = "openssl")] +use { + openssl::pkey::{Private, Public}, + sha2::{Digest, Sha256}, +}; +#[cfg(not(feature = "openssl"))] +use { + rsa::{ + pkcs1v15::{Pkcs1v15Sign, SigningKey}, + sha2::Sha512, + sha2::{Digest, Sha256}, + signature::SignatureEncoding, + traits::PublicKeyParts, + BigUint, RsaPrivateKey, RsaPublicKey, + }, + sha1::Sha1, +}; use crate::ec; use crate::encoding::{Encoding, Reader}; @@ -125,6 +140,11 @@ pub enum PublicKey { key: OpenSSLPKey, hash: SignatureHash, }, + #[cfg(not(feature = "openssl"))] + RSA { + key: RsaPublicKey, + hash: SignatureHash, + }, #[doc(hidden)] EC { key: ec::PublicKey }, } @@ -132,7 +152,6 @@ pub enum PublicKey { impl PartialEq for PublicKey { fn eq(&self, other: &Self) -> bool { match (self, other) { - #[cfg(feature = "openssl")] (Self::RSA { key: a, .. }, Self::RSA { key: b, .. }) => a == b, (Self::Ed25519(a), Self::Ed25519(b)) => a == b, (Self::EC { key: a }, Self::EC { key: b }) => a == b, @@ -183,7 +202,7 @@ impl PublicKey { .map(PublicKey::Ed25519) .map_err(Error::from) } - b"ssh-rsa" | b"rsa-sha2-256" | b"rsa-sha2-512" if cfg!(feature = "openssl") => { + b"ssh-rsa" | b"rsa-sha2-256" | b"rsa-sha2-512" => { #[cfg(feature = "openssl")] { use log::debug; @@ -212,7 +231,31 @@ impl PublicKey { } #[cfg(not(feature = "openssl"))] { - unreachable!() + // Assuming that `pubkey` is a reader that provides access to the key components + let mut p = pubkey.reader(0); + + // Read the key algorithm + let key_algo = p.read_string()?; + if key_algo != b"ssh-rsa" + && key_algo != b"rsa-sha2-256" + && key_algo != b"rsa-sha2-512" + { + return Err(Error::CouldNotReadKey); + } + + // Read the key components + let key_e = p.read_string()?; + let key_n = p.read_string()?; + + // Convert byte slices to BigUints + let e = BigUint::from_bytes_be(key_e); + let n = BigUint::from_bytes_be(key_n); + + Ok(PublicKey::RSA { + key: RsaPublicKey::new(n, e)?, + hash: SignatureHash::from_rsa_hostkey_algo(algo) + .unwrap_or(SignatureHash::SHA1), + }) } } crate::KEYTYPE_ECDSA_SHA2_NISTP256 @@ -242,7 +285,6 @@ impl PublicKey { pub fn name(&self) -> &'static str { match *self { PublicKey::Ed25519(_) => ED25519.0, - #[cfg(feature = "openssl")] PublicKey::RSA { ref hash, .. } => hash.name().0, PublicKey::EC { ref key } => key.algorithm(), } @@ -258,7 +300,6 @@ impl PublicKey { let sig = ed25519_dalek::Signature::from_bytes(&sig); public.verify(buffer, &sig).is_ok() } - #[cfg(feature = "openssl")] PublicKey::RSA { ref key, ref hash } => { use openssl::sign::*; @@ -269,6 +310,16 @@ impl PublicKey { }; verify().unwrap_or(false) } + #[cfg(not(feature = "openssl"))] + PublicKey::RSA { ref key, ref hash } => { + let pss = match hash { + SignatureHash::SHA1 => Pkcs1v15Sign::new::(), + SignatureHash::SHA2_256 => Pkcs1v15Sign::new::(), + SignatureHash::SHA2_512 => Pkcs1v15Sign::new::(), + }; + key.verify(pss, buffer, sig).is_ok() + } + PublicKey::EC { ref key, .. } => ec_verify(key, buffer, sig).is_ok(), } } @@ -277,13 +328,11 @@ impl PublicKey { pub fn fingerprint(&self) -> String { use super::PublicKeyBase64; let key = self.public_key_bytes(); - use sha2::{Digest, Sha256}; let mut hasher = Sha256::new(); hasher.update(&key[..]); data_encoding::BASE64_NOPAD.encode(&hasher.finalize()) } - #[cfg(feature = "openssl")] pub fn set_algorithm(&mut self, algorithm: &[u8]) { if let PublicKey::RSA { ref mut hash, .. } = self { if algorithm == b"rsa-sha2-512" { @@ -295,9 +344,6 @@ impl PublicKey { } } } - - #[cfg(not(feature = "openssl"))] - pub fn set_algorithm(&mut self, _: &[u8]) {} } impl Verify for PublicKey { @@ -318,6 +364,11 @@ pub enum KeyPair { key: openssl::rsa::Rsa, hash: SignatureHash, }, + #[cfg(not(feature = "openssl"))] + RSA { + key: RsaPrivateKey, + hash: SignatureHash, + }, EC { key: ec::PrivateKey, }, @@ -330,7 +381,6 @@ impl Clone for KeyPair { Self::Ed25519(kp) => { Self::Ed25519(ed25519_dalek::SigningKey::from_bytes(&kp.to_bytes())) } - #[cfg(feature = "openssl")] Self::RSA { key, hash } => Self::RSA { key: key.clone(), hash: *hash, @@ -348,7 +398,6 @@ impl std::fmt::Debug for KeyPair { "Ed25519 {{ public: {:?}, secret: (hidden) }}", key.verifying_key().as_bytes() ), - #[cfg(feature = "openssl")] KeyPair::RSA { .. } => write!(f, "RSA {{ (hidden) }}"), KeyPair::EC { .. } => write!(f, "EC {{ (hidden) }}"), } @@ -376,6 +425,14 @@ impl KeyPair { hash: *hash, } } + #[cfg(not(feature = "openssl"))] + KeyPair::RSA { ref key, ref hash } => { + let cloned_key = RsaPublicKey::new(key.n().clone(), key.e().clone())?; + PublicKey::RSA { + key: cloned_key, + hash: *hash, + } + } KeyPair::EC { ref key } => PublicKey::EC { key: key.to_public_key(), }, @@ -386,7 +443,6 @@ impl KeyPair { pub fn name(&self) -> &'static str { match *self { KeyPair::Ed25519(_) => ED25519.0, - #[cfg(feature = "openssl")] KeyPair::RSA { ref hash, .. } => hash.name().0, KeyPair::EC { ref key } => key.algorithm(), } @@ -402,9 +458,11 @@ impl KeyPair { Some(KeyPair::Ed25519(keypair)) } - #[cfg(feature = "openssl")] pub fn generate_rsa(bits: usize, hash: SignatureHash) -> Option { + #[cfg(feature = "openssl")] let key = openssl::rsa::Rsa::generate(bits as u32).ok()?; + #[cfg(not(feature = "openssl"))] + let key = RsaPrivateKey::new(&mut OsRng, bits).ok()?; Some(KeyPair::RSA { key, hash }) } @@ -415,7 +473,6 @@ impl KeyPair { KeyPair::Ed25519(ref secret) => Ok(Signature::Ed25519(SignatureBytes( secret.sign(to_sign).to_bytes(), ))), - #[cfg(feature = "openssl")] KeyPair::RSA { ref key, ref hash } => Ok(Signature::RSA { bytes: rsa_signature(hash, key, to_sign)?, hash: *hash, @@ -444,7 +501,6 @@ impl KeyPair { buffer.extend_ssh_string(ED25519.0.as_bytes()); buffer.extend_ssh_string(signature.to_bytes().as_slice()); } - #[cfg(feature = "openssl")] KeyPair::RSA { ref key, ref hash } => { // https://tools.ietf.org/html/draft-rsa-dsa-sha2-256-02#section-2.2 let signature = rsa_signature(hash, key, to_sign.as_ref())?; @@ -476,7 +532,6 @@ impl KeyPair { buffer.extend_ssh_string(ED25519.0.as_bytes()); buffer.extend_ssh_string(signature.to_bytes().as_slice()); } - #[cfg(feature = "openssl")] KeyPair::RSA { ref key, ref hash } => { // https://tools.ietf.org/html/draft-rsa-dsa-sha2-256-02#section-2.2 let signature = rsa_signature(hash, key, buffer)?; @@ -497,11 +552,9 @@ impl KeyPair { } /// Create a copy of an RSA key with a specified hash algorithm. - #[cfg(feature = "openssl")] pub fn with_signature_hash(&self, hash: SignatureHash) -> Option { match self { KeyPair::Ed25519(_) => None, - #[cfg(feature = "openssl")] KeyPair::RSA { key, .. } => Some(KeyPair::RSA { key: key.clone(), hash, @@ -535,6 +588,23 @@ fn rsa_signature( Ok(signer.sign_to_vec()?) } +#[cfg(not(feature = "openssl"))] +fn rsa_signature(hash: &SignatureHash, key: &RsaPrivateKey, b: &[u8]) -> Result, Error> { + let private_key = key.clone(); + + let signing_key = match hash { + SignatureHash::SHA2_256 => { + SigningKey::::new(private_key).sign(b) + } + SignatureHash::SHA2_512 => { + SigningKey::::new(private_key).sign(b) + } + SignatureHash::SHA1 => SigningKey::::new(private_key).sign(b), + }; + + Ok(signing_key.to_vec()) +} + fn ec_signature(key: &ec::PrivateKey, b: &[u8]) -> Result, Error> { let (r, s) = key.try_sign(b)?; let mut buf = Vec::new(); @@ -549,10 +619,7 @@ fn ec_verify(key: &ec::PublicKey, b: &[u8], sig: &[u8]) -> Result<(), Error> { } /// Parse a public key from a byte slice. -pub fn parse_public_key( - p: &[u8], - #[cfg(feature = "openssl")] prefer_hash: Option, -) -> Result { +pub fn parse_public_key(p: &[u8], refer_hash: Option) -> Result { let mut pos = p.reader(0); let t = pos.read_string()?; if t == b"ssh-ed25519" { @@ -577,7 +644,21 @@ pub fn parse_public_key( BigNum::from_slice(n)?, BigNum::from_slice(e)?, )?)?), - hash: prefer_hash.unwrap_or(SignatureHash::SHA2_256), + hash: refer_hash.unwrap_or(SignatureHash::SHA2_256), + }); + } + #[cfg(not(feature = "openssl"))] + { + let e = pos.read_string()?; + let n = pos.read_string()?; + + // Convert byte slices to BigUints + let e = BigUint::from_bytes_be(e); + let n = BigUint::from_bytes_be(n); + + return Ok(PublicKey::RSA { + key: RsaPublicKey::new(n, e)?, + hash: refer_hash.unwrap_or(SignatureHash::SHA2_256), }); } } diff --git a/russh-keys/src/lib.rs b/russh-keys/src/lib.rs index 14bfab6c..c17abb5e 100644 --- a/russh-keys/src/lib.rs +++ b/russh-keys/src/lib.rs @@ -74,6 +74,8 @@ use byteorder::{BigEndian, WriteBytesExt}; use data_encoding::BASE64_MIME; use hmac::{Hmac, Mac}; use log::debug; +#[cfg(not(feature = "openssl"))] +pub use rsa::traits::PublicKeyParts; use sha1::Sha1; use thiserror::Error; @@ -140,6 +142,10 @@ pub enum Error { #[error(transparent)] Openssl(#[from] openssl::error::ErrorStack), + #[cfg(not(feature = "openssl"))] + #[error(transparent)] + RSA(#[from] rsa::errors::Error), + #[error(transparent)] Pad(#[from] PadError), @@ -202,11 +208,7 @@ pub fn load_public_key>(path: P) -> Result /// ``` pub fn parse_public_key_base64(key: &str) -> Result { let base = BASE64_MIME.decode(key.as_bytes())?; - key::parse_public_key( - &base, - #[cfg(feature = "openssl")] - None, - ) + key::parse_public_key(&base, None) } pub trait PublicKeyBase64 { @@ -234,17 +236,25 @@ impl PublicKeyBase64 for key::PublicKey { .unwrap(); s.extend_from_slice(publickey.as_bytes()); } - #[cfg(feature = "openssl")] key::PublicKey::RSA { ref key, .. } => { use encoding::Encoding; let name = b"ssh-rsa"; #[allow(clippy::unwrap_used)] // Vec<>.write_all can't fail s.write_u32::(name.len() as u32).unwrap(); s.extend_from_slice(name); - #[allow(clippy::unwrap_used)] // TODO check - s.extend_ssh_mpint(&key.0.rsa().unwrap().e().to_vec()); - #[allow(clippy::unwrap_used)] // TODO check - s.extend_ssh_mpint(&key.0.rsa().unwrap().n().to_vec()); + #[cfg(feature = "openssl")] + { + #[allow(clippy::unwrap_used)] // TODO check + s.extend_ssh_mpint(&key.0.rsa().unwrap().e().to_vec()); + #[allow(clippy::unwrap_used)] // TODO check + s.extend_ssh_mpint(&key.0.rsa().unwrap().n().to_vec()); + } + #[cfg(not(feature = "openssl"))] + { + let kk = key.clone(); + s.extend_ssh_mpint(&(kk.e().to_bytes_be())); + s.extend_ssh_mpint(&(kk.n().to_bytes_be())); + } } key::PublicKey::EC { ref key } => { write_ec_public_key(&mut s, key); @@ -268,11 +278,18 @@ impl PublicKeyBase64 for key::KeyPair { s.write_u32::(public.len() as u32).unwrap(); s.extend_from_slice(public.as_slice()); } - #[cfg(feature = "openssl")] key::KeyPair::RSA { ref key, .. } => { use encoding::Encoding; - s.extend_ssh_mpint(&key.e().to_vec()); - s.extend_ssh_mpint(&key.n().to_vec()); + #[cfg(feature = "openssl")] + { + s.extend_ssh_mpint(&key.e().to_vec()); + s.extend_ssh_mpint(&key.n().to_vec()); + } + #[cfg(not(feature = "openssl"))] + { + s.extend_ssh_mpint(&key.e().to_bytes_be()); + s.extend_ssh_mpint(&key.n().to_bytes_be()); + } } key::KeyPair::EC { ref key } => { write_ec_public_key(&mut s, &key.to_public_key()); @@ -485,7 +502,7 @@ mod test { use std::fs::File; use std::io::Write; - #[cfg(all(unix, feature = "openssl"))] + #[cfg(unix)] use futures::Future; use super::*; @@ -509,7 +526,6 @@ dP3jryYgvsCIBAA5jMWSjrmnOTXhidqcOy4xYCrAttzSnZ/cUadfBenL+DQq6neffw7j8r sJWR7W+cGvJ/vLsw== -----END OPENSSH PRIVATE KEY-----"; - #[cfg(feature = "openssl")] const RSA_KEY: &str = "-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn NhAAAAAwEAAQAAAQEAuSvQ9m76zhRB4m0BUKPf17lwccj7KQ1Qtse63AOqP/VYItqEH8un @@ -551,7 +567,6 @@ QR+u0AypRPmzHnOPAAAAEXJvb3RAMTQwOTExNTQ5NDBkAQ== } #[test] - #[cfg(feature = "openssl")] fn test_decode_rsa_secret_key() { env_logger::try_init().unwrap_or(()); decode_secret_key(RSA_KEY, None).unwrap(); @@ -625,7 +640,6 @@ Ve0k2ddxoEsSE15H4lgNHM2iuYKzIqZJOReHRCTff6QGgMYPDqDfFfL1Hc1Ntql0pwAAAA } #[test] - #[cfg(feature = "openssl")] fn test_fingerprint() { let key = parse_public_key_base64( "AAAAC3NzaC1lZDI1NTE5AAAAILagOJFgwaMNhBWQINinKOXmqS4Gh5NgxgriXwdOoINJ", @@ -727,7 +741,6 @@ Ve0k2ddxoEsSE15H4lgNHM2iuYKzIqZJOReHRCTff6QGgMYPDqDfFfL1Hc1Ntql0pwAAAA } #[test] - #[cfg(feature = "openssl")] fn test_srhb() { env_logger::try_init().unwrap_or(()); let key = "AAAAB3NzaC1yc2EAAAADAQABAAACAQC0Xtz3tSNgbUQAXem4d+d6hMx7S8Nwm/DOO2AWyWCru+n/+jQ7wz2b5+3oG2+7GbWZNGj8HCc6wJSA3jUsgv1N6PImIWclD14qvoqY3Dea1J0CJgXnnM1xKzBz9C6pDHGvdtySg+yzEO41Xt4u7HFn4Zx5SGuI2NBsF5mtMLZXSi33jCIWVIkrJVd7sZaY8jiqeVZBB/UvkLPWewGVuSXZHT84pNw4+S0Rh6P6zdNutK+JbeuO+5Bav4h9iw4t2sdRkEiWg/AdMoSKmo97Gigq2mKdW12ivnXxz3VfxrCgYJj9WwaUUWSfnAju5SiNly0cTEAN4dJ7yB0mfLKope1kRhPsNaOuUmMUqlu/hBDM/luOCzNjyVJ+0LLB7SV5vOiV7xkVd4KbEGKou8eeCR3yjFazUe/D1pjYPssPL8cJhTSuMc+/UC9zD8yeEZhB9V+vW4NMUR+lh5+XeOzenl65lWYd/nBZXLBbpUMf1AOfbz65xluwCxr2D2lj46iApSIpvE63i3LzFkbGl9GdUiuZJLMFJzOWdhGGc97cB5OVyf8umZLqMHjaImxHEHrnPh1MOVpv87HYJtSBEsN4/omINCMZrk++CRYAIRKRpPKFWV7NQHcvw3m7XLR3KaTYe+0/MINIZwGdou9fLUU3zSd521vDjA/weasH0CyDHq7sZw=="; @@ -736,7 +749,6 @@ Ve0k2ddxoEsSE15H4lgNHM2iuYKzIqZJOReHRCTff6QGgMYPDqDfFfL1Hc1Ntql0pwAAAA } #[test] - #[cfg(feature = "openssl")] fn test_nikao() { env_logger::try_init().unwrap_or(()); let key = "-----BEGIN RSA PRIVATE KEY----- @@ -771,7 +783,6 @@ QaChXiDsryJZwsRnruvMRX9nedtqHrgnIsJLTXjppIhGhq5Kg4RQfOU= } #[test] - #[cfg(feature = "openssl")] fn test_decode_pkcs8_rsa_secret_key() { // Generated using: ssh-keygen -t rsa -b 1024 -m pkcs8 -f $file let key = "-----BEGIN PRIVATE KEY----- @@ -971,7 +982,6 @@ ZgmnWhuwhyxErC5UkMHiEvTOZllxBvefs7XeJqL11pqQIHY4Gb5OQGiCNHiRRjg0egAAAA ecdsa_sign_verify(key, public); } - #[cfg(feature = "openssl")] pub const PKCS8_RSA: &str = "-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAwBGetHjW+3bDQpVktdemnk7JXgu1NBWUM+ysifYLDBvJ9ttX GNZSyQKA4v/dNr0FhAJ8I9BuOTjYCy1YfKylhl5D/DiSSXFPsQzERMmGgAlYvU2U @@ -1002,7 +1012,6 @@ xV/JrzLAwPoKk3bkqys3bUmgo6DxVC/6RmMwPQ0rmpw78kOgEej90g== "; #[test] - #[cfg(feature = "openssl")] fn test_loewenheim() -> Result<(), Error> { env_logger::try_init().unwrap_or(()); let key = "-----BEGIN RSA PRIVATE KEY----- @@ -1045,7 +1054,6 @@ KJaj7gc0n6gmKY6r0/Ddufy1JZ6eihBCSJ64RARBXeg2rZpyT+xxhMEZLK5meOeR } #[test] - #[cfg(feature = "openssl")] fn test_o01eg() { env_logger::try_init().unwrap_or(()); @@ -1083,14 +1091,12 @@ br8gXU8KyiY9sZVbmplRPF+ar462zcI2kt0a18mr0vbrdqp2eMjb37QDbVBJ+rPE decode_secret_key(key, Some("12345")).unwrap(); } #[test] - #[cfg(feature = "openssl")] fn test_pkcs8() { env_logger::try_init().unwrap_or(()); println!("test"); decode_secret_key(PKCS8_RSA, Some("blabla")).unwrap(); } - #[cfg(feature = "openssl")] const PKCS8_ENCRYPTED: &str = "-----BEGIN ENCRYPTED PRIVATE KEY----- MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQITo1O0b8YrS0CAggA MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBBtLH4T1KOfo1GGr7salhR8BIIE @@ -1123,7 +1129,6 @@ Cog3JMeTrb3LiPHgN6gU2P30MRp6L1j1J/MtlOAr5rux -----END ENCRYPTED PRIVATE KEY-----"; #[test] - #[cfg(feature = "openssl")] fn test_gpg() { env_logger::try_init().unwrap_or(()); let algo = [115, 115, 104, 45, 114, 115, 97]; @@ -1156,7 +1161,6 @@ Cog3JMeTrb3LiPHgN6gU2P30MRp6L1j1J/MtlOAr5rux } #[test] - #[cfg(feature = "openssl")] fn test_pkcs8_encrypted() { env_logger::try_init().unwrap_or(()); println!("test"); @@ -1199,7 +1203,6 @@ Cog3JMeTrb3LiPHgN6gU2P30MRp6L1j1J/MtlOAr5rux assert!(public.verify_detached(a, sig)); } key::KeyPair::EC { .. } => {} - #[cfg(feature = "openssl")] _ => {} } @@ -1232,7 +1235,6 @@ Cog3JMeTrb3LiPHgN6gU2P30MRp6L1j1J/MtlOAr5rux #[test] #[cfg(unix)] - #[cfg(feature = "openssl")] fn test_agent() { env_logger::try_init().unwrap_or(()); let dir = tempdir::TempDir::new("russh").unwrap(); diff --git a/russh/src/client/encrypted.rs b/russh/src/client/encrypted.rs index 187ef1a1..dfd2e2e4 100644 --- a/russh/src/client/encrypted.rs +++ b/russh/src/client/encrypted.rs @@ -673,7 +673,8 @@ impl Session { Ok(key) => { let key2 = <&[u8]>::clone(&key); #[cfg(not(feature = "openssl"))] - let key = parse_public_key(key).map_err(crate::Error::from); + let key = + parse_public_key(key, None).map_err(crate::Error::from); #[cfg(feature = "openssl")] let key = parse_public_key(key, None).map_err(crate::Error::from); diff --git a/russh/src/client/mod.rs b/russh/src/client/mod.rs index b2111d1a..1d2e7de5 100644 --- a/russh/src/client/mod.rs +++ b/russh/src/client/mod.rs @@ -47,9 +47,7 @@ use futures::Future; use log::{debug, error, info, trace}; use russh_cryptovec::CryptoVec; use russh_keys::encoding::Reader; -#[cfg(feature = "openssl")] -use russh_keys::key::SignatureHash; -use russh_keys::key::{self, parse_public_key, PublicKey}; +use russh_keys::key::{self, parse_public_key, PublicKey, SignatureHash}; use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, ReadHalf, WriteHalf}; use tokio::net::{TcpStream, ToSocketAddrs}; use tokio::pin; @@ -1212,7 +1210,6 @@ impl KexDhDone { let pubkey = reader.read_string().map_err(crate::Error::from)?; // server public key. let pubkey = parse_public_key( pubkey, - #[cfg(feature = "openssl")] SignatureHash::from_rsa_hostkey_algo(self.names.key.0.as_bytes()), ) .map_err(crate::Error::from)?; diff --git a/russh/src/key.rs b/russh/src/key.rs index 3b8b51d8..2135490d 100644 --- a/russh/src/key.rs +++ b/russh/src/key.rs @@ -30,12 +30,25 @@ impl PubKey for PublicKey { buffer.extend_ssh_string(ED25519.0.as_bytes()); buffer.extend_ssh_string(public.as_bytes()); } - #[cfg(feature = "openssl")] + #[allow(unused_assignments)] PublicKey::RSA { ref key, .. } => { + let mut e = Vec::new(); + let mut n = Vec::new(); + + #[cfg(feature = "openssl")] #[allow(clippy::unwrap_used)] // type known - let rsa = key.0.rsa().unwrap(); - let e = rsa.e().to_vec(); - let n = rsa.n().to_vec(); + { + let rsa = key.0.rsa().unwrap(); + e = rsa.e().to_vec(); + n = rsa.n().to_vec(); + } + #[cfg(not(feature = "openssl"))] + { + use russh_keys::PublicKeyParts; + let rsa = key.clone(); + e = rsa.e().to_bytes_be(); + n = rsa.n().to_bytes_be(); + } buffer.push_u32_be((4 + SSH_RSA.0.len() + mpint_len(&n) + mpint_len(&e)) as u32); buffer.extend_ssh_string(SSH_RSA.0.as_bytes()); buffer.extend_ssh_mpint(&e); @@ -57,10 +70,22 @@ impl PubKey for KeyPair { buffer.extend_ssh_string(ED25519.0.as_bytes()); buffer.extend_ssh_string(public.as_slice()); } - #[cfg(feature = "openssl")] + #[allow(unused_assignments)] KeyPair::RSA { ref key, .. } => { - let e = key.e().to_vec(); - let n = key.n().to_vec(); + let mut e = Vec::new(); + let mut n = Vec::new(); + #[cfg(feature = "openssl")] + { + e = key.e().to_vec(); + n = key.n().to_vec(); + } + + #[cfg(not(feature = "openssl"))] + { + use russh_keys::PublicKeyParts; + e = key.e().to_bytes_be(); + n = key.n().to_bytes_be(); + } buffer.push_u32_be((4 + SSH_RSA.0.len() + mpint_len(&n) + mpint_len(&e)) as u32); buffer.extend_ssh_string(SSH_RSA.0.as_bytes()); buffer.extend_ssh_mpint(&e); diff --git a/russh/src/negotiation.rs b/russh/src/negotiation.rs index e2af10e7..d0601ac7 100644 --- a/russh/src/negotiation.rs +++ b/russh/src/negotiation.rs @@ -102,9 +102,7 @@ impl Preferred { key::ED25519, key::ECDSA_SHA2_NISTP256, key::ECDSA_SHA2_NISTP521, - #[cfg(feature = "openssl")] key::RSA_SHA2_256, - #[cfg(feature = "openssl")] key::RSA_SHA2_512, ], cipher: CIPHER_ORDER, @@ -139,15 +137,12 @@ impl Named for () { } } -use russh_keys::key::ED25519; -#[cfg(feature = "openssl")] -use russh_keys::key::SSH_RSA; +use russh_keys::key::{ED25519, SSH_RSA}; impl Named for PublicKey { fn name(&self) -> &'static str { match self { PublicKey::Ed25519(_) => ED25519.0, - #[cfg(feature = "openssl")] PublicKey::RSA { .. } => SSH_RSA.0, PublicKey::EC { ref key } => key.algorithm(), } @@ -158,7 +153,6 @@ impl Named for KeyPair { fn name(&self) -> &'static str { match self { KeyPair::Ed25519 { .. } => ED25519.0, - #[cfg(feature = "openssl")] KeyPair::RSA { ref hash, .. } => hash.name().0, KeyPair::EC { ref key } => key.algorithm(), }