diff --git a/.github/workflows/ssh-key.yml b/.github/workflows/ssh-key.yml index bc16e52c..79c8537e 100644 --- a/.github/workflows/ssh-key.yml +++ b/.github/workflows/ssh-key.yml @@ -91,5 +91,6 @@ jobs: - run: cargo test --release #- run: cargo test --release --features getrandom # TODO(tarcieri): fix `getrandom` feature - run: cargo test --release --features std + - run: cargo test --no-default-features --features ecdsa,rand_core,std # debug build without `sha2` - run: cargo test --all-features # debug build - run: cargo test --release --all-features diff --git a/ssh-key/Cargo.toml b/ssh-key/Cargo.toml index b35cf82b..6605293a 100644 --- a/ssh-key/Cargo.toml +++ b/ssh-key/Cargo.toml @@ -21,7 +21,6 @@ rust-version = "1.85" cipher = { package = "ssh-cipher", version = "0.3", features = ["encoding", "zeroize"] } ctutils = { version = "0.4", default-features = false } encoding = { package = "ssh-encoding", version = "0.3", features = ["base64", "digest", "pem", "ctutils", "zeroize"] } -sha2 = { version = "0.11", default-features = false } signature = { version = "3", default-features = false } zeroize = { version = "1.9", default-features = false } @@ -40,6 +39,7 @@ rsa = { version = "0.10.0-rc.18", optional = true, default-features = false, fea sec1 = { version = "0.8", optional = true, default-features = false, features = ["point"] } serde = { version = "1.0.16", optional = true } sha1 = { version = "0.11", optional = true, default-features = false, features = ["oid"] } +sha2 = { version = "0.11", optional = true, default-features = false } [dev-dependencies] hex-literal = "1" @@ -47,14 +47,14 @@ chacha20 = { version = "0.10", features = ["rng"] } getrandom = { version = "0.4", features = ["sys_rng"] } [features] -default = ["ecdsa", "rand_core", "std"] +default = ["ecdsa", "rand_core", "sha2", "std"] alloc = ["encoding/alloc", "signature/alloc", "zeroize/alloc", ] std = ["alloc"] crypto = ["ed25519", "p256", "p384", "p521", "rsa"] # NOTE: `dsa` is obsolete/weak dsa = ["dep:dsa", "dep:sha1", "alloc", "encoding/bigint", "signature/rand_core"] ecdsa = ["dep:sec1"] -ed25519 = ["dep:ed25519-dalek", "rand_core"] +ed25519 = ["dep:ed25519-dalek", "rand_core", "sha2"] encryption = [ "dep:bcrypt-pbkdf", "alloc", @@ -63,13 +63,14 @@ encryption = [ "rand_core" ] getrandom = ["cipher/getrandom", "rand_core"] -p256 = ["dep:p256", "ecdsa"] +p256 = ["dep:p256", "ecdsa", "sha2"] p384 = ["dep:p384", "ecdsa"] p521 = ["dep:p521", "ecdsa"] -ppk = ["dep:hex", "alloc", "cipher/aes", "dep:hmac", "dep:argon2", "dep:sha1"] +ppk = ["dep:hex", "alloc", "cipher/aes", "dep:hmac", "dep:argon2", "dep:sha1", "sha2"] rand_core = ["dep:rand_core", "cipher/rand_core"] -rsa = ["dep:rsa", "alloc", "encoding/bigint", "rand_core"] +rsa = ["dep:rsa", "alloc", "encoding/bigint", "rand_core", "sha2"] sha1 = ["dep:sha1"] +sha2 = ["dep:sha2"] tdes = ["cipher/tdes", "encryption"] [lints] diff --git a/ssh-key/README.md b/ssh-key/README.md index 821091f5..e3ea6d34 100644 --- a/ssh-key/README.md +++ b/ssh-key/README.md @@ -29,6 +29,14 @@ When the `ed25519`, `p256`, and/or `rsa` features of this crate are enabled, provides key generation and certificate signing/verification support for that respective SSH key algorithm. +Key fingerprints, certificate validation, and `sshsig` signing/verification of +messages compute SHA-2 hashes using the `sha2` crate, and are only available +when the `sha2` feature is enabled. It's on by default and implied by the +`ed25519`, `p256`, `ppk`, and `rsa` features. With it disabled, `sshsig` +signatures can still be created and verified from a digest computed by another +SHA-2 implementation, using the `*_prehash` methods, or the `*_digest` methods +with a type that implements `AssociatedHashAlg`. + ## Features - [x] Constant-time Base64 decoder/encoder using `base64ct`/`pem-rfc7468` crates diff --git a/ssh-key/src/algorithm.rs b/ssh-key/src/algorithm.rs index ed56c706..a8adf475 100644 --- a/ssh-key/src/algorithm.rs +++ b/ssh-key/src/algorithm.rs @@ -5,11 +5,16 @@ mod name; use crate::{Error, Result}; use core::{fmt, str}; -use encoding::{Label, LabelError}; -use sha2::{Digest, Sha256, Sha512}; +use encoding::{Label, LabelError, digest::Digest}; #[cfg(feature = "alloc")] -use alloc::{borrow::ToOwned, string::String, vec::Vec}; +use alloc::{borrow::ToOwned, string::String}; + +#[cfg(all(feature = "alloc", feature = "sha2"))] +use alloc::vec::Vec; + +#[cfg(feature = "sha2")] +use sha2::{Sha256, Sha512}; #[cfg(feature = "alloc")] pub use name::AlgorithmName; @@ -457,7 +462,7 @@ impl HashAlg { } /// Compute a digest of the given message using this hash function. - #[cfg(feature = "alloc")] + #[cfg(all(feature = "alloc", feature = "sha2"))] #[must_use] pub fn digest(self, msg: &[u8]) -> Vec { match self { @@ -499,10 +504,12 @@ pub trait AssociatedHashAlg: Digest { const HASH_ALG: HashAlg; } +#[cfg(feature = "sha2")] impl AssociatedHashAlg for Sha256 { const HASH_ALG: HashAlg = HashAlg::Sha256; } +#[cfg(feature = "sha2")] impl AssociatedHashAlg for Sha512 { const HASH_ALG: HashAlg = HashAlg::Sha512; } diff --git a/ssh-key/src/certificate.rs b/ssh-key/src/certificate.rs index 1a37ee57..fe1be5c4 100644 --- a/ssh-key/src/certificate.rs +++ b/ssh-key/src/certificate.rs @@ -9,7 +9,7 @@ mod unix_time; pub use self::{builder::Builder, cert_type::CertType, field::Field, options_map::OptionsMap}; use crate::{ - Algorithm, Comment, Error, Fingerprint, HashAlg, Result, Signature, + Algorithm, Comment, Error, Result, Signature, public::{KeyData, SshFormat}, }; use alloc::{ @@ -23,6 +23,9 @@ use signature::Verifier; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize, de, ser}; +#[cfg(feature = "sha2")] +use crate::{Fingerprint, HashAlg}; + #[cfg(feature = "std")] use { self::unix_time::UnixTime, @@ -396,7 +399,7 @@ impl Certificate { /// /// # Errors /// Returns [`Error::CertificateValidation`] if the certificate failed to validate - #[cfg(feature = "std")] + #[cfg(all(feature = "sha2", feature = "std"))] pub fn validate<'a, I>(&self, ca_fingerprints: I) -> Result<()> where I: IntoIterator, @@ -431,6 +434,7 @@ impl Certificate { /// /// # Errors /// Returns [`Error::CertificateValidation`] if the certificate failed to validate + #[cfg(feature = "sha2")] pub fn validate_at<'a, I>(&self, unix_timestamp: u64, ca_fingerprints: I) -> Result<()> where I: IntoIterator, diff --git a/ssh-key/src/certificate/builder.rs b/ssh-key/src/certificate/builder.rs index 84bb9e4a..41865565 100644 --- a/ssh-key/src/certificate/builder.rs +++ b/ssh-key/src/certificate/builder.rs @@ -332,12 +332,15 @@ impl Builder { cert.encode_tbs(&mut tbs_cert)?; cert.signature = signing_key.try_sign(&tbs_cert)?; - #[cfg(debug_assertions)] + #[cfg(all(debug_assertions, feature = "sha2"))] cert.validate_at( cert.valid_after, &[cert.signature_key.fingerprint(Default::default())], )?; + #[cfg(all(debug_assertions, not(feature = "sha2")))] + cert.verify_signature()?; + Ok(cert) } } diff --git a/ssh-key/src/certificate/unix_time.rs b/ssh-key/src/certificate/unix_time.rs index 636fe87a..f3f486d5 100644 --- a/ssh-key/src/certificate/unix_time.rs +++ b/ssh-key/src/certificate/unix_time.rs @@ -73,7 +73,7 @@ impl UnixTime { } /// Get the current time as a Unix timestamp. - #[cfg(feature = "std")] + #[cfg(all(feature = "sha2", feature = "std"))] pub(super) fn now() -> Result { SystemTime::now().try_into() } diff --git a/ssh-key/src/dot_ssh.rs b/ssh-key/src/dot_ssh.rs index bd3f9e3c..df1c86e9 100644 --- a/ssh-key/src/dot_ssh.rs +++ b/ssh-key/src/dot_ssh.rs @@ -1,6 +1,6 @@ //! `~/.ssh` support. -use crate::{Fingerprint, PrivateKey, PublicKey, Result}; +use crate::{PrivateKey, PublicKey, Result}; use core::fmt::{self, Debug}; use std::{ env, @@ -8,6 +8,9 @@ use std::{ path::{Path, PathBuf}, }; +#[cfg(feature = "sha2")] +use crate::Fingerprint; + #[cfg(doc)] use crate::Error; @@ -62,6 +65,7 @@ impl DotSsh { } /// Find a private key whose public key has the given key fingerprint. + #[cfg(feature = "sha2")] #[must_use] pub fn private_key_with_fingerprint(&self, fingerprint: Fingerprint) -> Option { self.private_keys() @@ -80,6 +84,7 @@ impl DotSsh { } /// Find a public key with the given key fingerprint. + #[cfg(feature = "sha2")] #[must_use] pub fn public_key_with_fingerprint(&self, fingerprint: Fingerprint) -> Option { self.public_keys() diff --git a/ssh-key/src/fingerprint.rs b/ssh-key/src/fingerprint.rs index 74d3faf0..97173eb2 100644 --- a/ssh-key/src/fingerprint.rs +++ b/ssh-key/src/fingerprint.rs @@ -3,23 +3,26 @@ mod randomart; use self::randomart::Randomart; -use crate::{Error, HashAlg, Result, public}; +use crate::{Error, HashAlg, Result}; use core::{ fmt::{self, Display}, str::{self, FromStr}, }; -use encoding::{ - DigestWriter, Encode, - base64::{Base64Unpadded, Encoding}, -}; -use sha2::{Digest, Sha256, Sha512}; +use encoding::base64::{Base64Unpadded, Encoding}; #[cfg(feature = "alloc")] use alloc::string::{String, ToString}; #[cfg(all(feature = "alloc", feature = "serde"))] use serde::{Deserialize, Serialize, de, ser}; +#[cfg(feature = "sha2")] +use { + crate::public, + encoding::{DigestWriter, Encode}, + sha2::{Digest, Sha256, Sha512}, +}; /// Fingerprint encoding error message. +#[cfg(feature = "sha2")] const FINGERPRINT_ERR_MSG: &str = "fingerprint encoding error"; /// SSH public key fingerprints. @@ -58,6 +61,7 @@ impl Fingerprint { /// Create a fingerprint of the given public key data using the provided /// hash algorithm. + #[cfg(feature = "sha2")] #[must_use] #[allow(clippy::missing_panics_doc, reason = "should not panic")] pub fn new(algorithm: HashAlg, public_key: &public::KeyData) -> Self { diff --git a/ssh-key/src/lib.rs b/ssh-key/src/lib.rs index 820e701b..ac4513c2 100644 --- a/ssh-key/src/lib.rs +++ b/ssh-key/src/lib.rs @@ -157,7 +157,6 @@ pub use crate::{ }; pub use cipher::{self, Cipher}; pub use encoding::{self, pem::LineEnding}; -pub use sha2; #[cfg(feature = "std")] pub use crate::dot_ssh::DotSsh; @@ -167,6 +166,8 @@ pub use cipher::cipher::common::getrandom; pub use rand_core; #[cfg(feature = "ecdsa")] pub use sec1; +#[cfg(feature = "sha2")] +pub use sha2; #[cfg(feature = "alloc")] pub use { crate::{ diff --git a/ssh-key/src/private.rs b/ssh-key/src/private.rs index a7bf4a2a..fe5f8c46 100644 --- a/ssh-key/src/private.rs +++ b/ssh-key/src/private.rs @@ -114,13 +114,13 @@ pub use self::{ #[cfg(feature = "alloc")] pub use crate::{ Comment, SshSig, + encoding::digest::Digest, private::{ dsa::{DsaKeypair, DsaPrivateKey}, opaque::{OpaqueKeypair, OpaqueKeypairBytes, OpaquePrivateKeyBytes}, rsa::{RsaKeypair, RsaPrivateKey}, sk::SkEd25519, }, - sha2::Digest, }; #[cfg(feature = "ecdsa")] @@ -129,7 +129,7 @@ pub use self::ecdsa::{EcdsaKeypair, EcdsaPrivateKey}; #[cfg(all(feature = "alloc", feature = "ecdsa"))] pub use self::sk::SkEcdsaSha2NistP256; -use crate::{Algorithm, Cipher, Error, Fingerprint, HashAlg, Kdf, PublicKey, Result, public}; +use crate::{Algorithm, Cipher, Error, Kdf, PublicKey, Result, public}; use cipher::Tag; use core::str; use ctutils::{Choice, CtEq}; @@ -151,6 +151,12 @@ use rand_core::TryCryptoRng; #[cfg(feature = "rand_core")] use rand_core::CryptoRng; +#[cfg(feature = "sha2")] +use crate::Fingerprint; + +#[cfg(any(feature = "alloc", feature = "sha2"))] +use crate::HashAlg; + #[cfg(feature = "std")] use std::{fs::File, path::Path}; @@ -354,7 +360,7 @@ impl PrivateKey { /// /// # Errors /// Propagates errors from [`SshSig::sign`]. - #[cfg(feature = "alloc")] + #[cfg(all(feature = "alloc", feature = "sha2"))] pub fn sign(&self, namespace: &str, hash_alg: HashAlg, msg: &[u8]) -> Result { SshSig::sign(self, namespace, hash_alg, msg) } @@ -569,6 +575,7 @@ impl PrivateKey { /// Compute key fingerprint. /// /// Use [`Default::default()`] to use the default hash function (SHA-256). + #[cfg(feature = "sha2")] #[must_use] pub fn fingerprint(&self, hash_alg: HashAlg) -> Fingerprint { self.public_key.fingerprint(hash_alg) diff --git a/ssh-key/src/public.rs b/ssh-key/src/public.rs index 9dd0b106..290c521d 100644 --- a/ssh-key/src/public.rs +++ b/ssh-key/src/public.rs @@ -29,7 +29,7 @@ pub use self::{ecdsa::EcdsaPublicKey, sk::SkEcdsaSha2NistP256}; pub(crate) use self::ssh_format::SshFormat; -use crate::{Algorithm, Error, Fingerprint, HashAlg, Result}; +use crate::{Algorithm, Error, Result}; use core::str::{self, FromStr}; use encoding::{Base64Reader, Decode, Reader}; @@ -41,13 +41,15 @@ use { string::{String, ToString}, vec::Vec, }, - encoding::Encode, - sha2::Digest, + encoding::{Encode, digest::Digest}, }; #[cfg(all(feature = "alloc", feature = "serde"))] use serde::{Deserialize, Serialize, de, ser}; +#[cfg(feature = "sha2")] +use crate::{Fingerprint, HashAlg}; + #[cfg(feature = "std")] use std::{fs::File, path::Path}; @@ -251,7 +253,7 @@ impl PublicKey { /// - Returns [`Error::PublicKey`] if this key does not match the one in the signature. /// - Returns [`Error::Namespace`] if the provided `namespace` does not match the signature. /// - Returns [`Error::Signature`] in the event signature verification failed. - #[cfg(feature = "alloc")] + #[cfg(all(feature = "alloc", feature = "sha2"))] pub fn verify(&self, namespace: &str, msg: &[u8], signature: &SshSig) -> Result<()> { self.verify_prehash( namespace, @@ -378,6 +380,7 @@ impl PublicKey { /// Compute key fingerprint. /// /// Use [`Default::default()`] to use the default hash function (SHA-256). + #[cfg(feature = "sha2")] #[must_use] pub fn fingerprint(&self, hash_alg: HashAlg) -> Fingerprint { self.key_data.fingerprint(hash_alg) diff --git a/ssh-key/src/public/key_data.rs b/ssh-key/src/public/key_data.rs index 5924ca98..7ed75437 100644 --- a/ssh-key/src/public/key_data.rs +++ b/ssh-key/src/public/key_data.rs @@ -1,7 +1,7 @@ //! Public key data. use super::{Ed25519PublicKey, SkEd25519}; -use crate::{Algorithm, Error, Fingerprint, HashAlg, Result}; +use crate::{Algorithm, Error, Result}; use encoding::{CheckedSum, Decode, Encode, Reader, Writer}; #[cfg(feature = "alloc")] @@ -14,6 +14,9 @@ use { #[cfg(feature = "ecdsa")] use super::{EcdsaPublicKey, SkEcdsaSha2NistP256}; +#[cfg(feature = "sha2")] +use crate::{Fingerprint, HashAlg}; + /// Public key data. #[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] #[non_exhaustive] @@ -112,6 +115,7 @@ impl KeyData { /// Compute key fingerprint. /// /// Use [`Default::default()`] to use the default hash function (SHA-256). + #[cfg(feature = "sha2")] #[must_use] pub fn fingerprint(&self, hash_alg: HashAlg) -> Fingerprint { Fingerprint::new(hash_alg, self) diff --git a/ssh-key/src/signature.rs b/ssh-key/src/signature.rs index db132c31..a2a8c44c 100644 --- a/ssh-key/src/signature.rs +++ b/ssh-key/src/signature.rs @@ -35,7 +35,7 @@ use sha1::Sha1; use sha2::Sha256; #[cfg(any(feature = "dsa", feature = "ed25519", feature = "p256"))] -use sha2::Digest; +use encoding::digest::Digest; const DSA_COMPONENT_SIZE: usize = 20; const DSA_SIGNATURE_SIZE: usize = DSA_COMPONENT_SIZE * 2; diff --git a/ssh-key/src/sshsig.rs b/ssh-key/src/sshsig.rs index 4cdf59b8..7f35f39a 100644 --- a/ssh-key/src/sshsig.rs +++ b/ssh-key/src/sshsig.rs @@ -5,9 +5,9 @@ use alloc::{string::String, string::ToString, vec::Vec}; use core::str::FromStr; use encoding::{ CheckedSum, Decode, DecodePem, Encode, EncodePem, Reader, Writer, + digest::Digest, pem::{LineEnding, PemLabel}, }; -use sha2::Digest; use signature::Verifier; #[cfg(doc)] @@ -117,6 +117,7 @@ impl SshSig { /// - Returns [`Error::Crypto`] in the event of an error occurring in the cryptographic /// implementation. /// - Returns [`Error::Namespace`] if the namespace is empty. + #[cfg(feature = "sha2")] pub fn sign( signing_key: &S, namespace: &str, @@ -195,6 +196,7 @@ impl SshSig { /// /// # Errors /// Returns [`Error::Namespace`] if the namespace is empty. + #[cfg(feature = "sha2")] pub fn signed_data(namespace: &str, hash_alg: HashAlg, msg: &[u8]) -> Result> { Self::signed_data_for_prehash(namespace, hash_alg, hash_alg.digest(msg).as_slice()) } diff --git a/ssh-key/tests/dot_ssh.rs b/ssh-key/tests/dot_ssh.rs index 9e517aab..128f47d4 100644 --- a/ssh-key/tests/dot_ssh.rs +++ b/ssh-key/tests/dot_ssh.rs @@ -2,8 +2,13 @@ #![cfg(feature = "std")] -use hex_literal::hex; -use ssh_key::{Algorithm, DotSsh, Fingerprint}; +use ssh_key::DotSsh; + +#[cfg(feature = "sha2")] +use { + hex_literal::hex, + ssh_key::{Algorithm, Fingerprint}, +}; /// Open `.ssh` using the `test/examples`. fn dot_ssh() -> DotSsh { @@ -23,6 +28,7 @@ fn private_keys() { assert_eq!(dot_ssh.private_keys().unwrap().count(), 22); } +#[cfg(feature = "sha2")] #[test] fn private_key_with_fingerprint() { let fingerprint = Fingerprint::Sha256(hex!( @@ -40,6 +46,7 @@ fn public_keys() { assert_eq!(dot_ssh.public_keys().unwrap().count(), 12); } +#[cfg(feature = "sha2")] #[test] fn public_key_with_fingerprint() { let fingerprint = Fingerprint::Sha256(hex!( diff --git a/ssh-key/tests/private_key.rs b/ssh-key/tests/private_key.rs index 30d33570..1c6d58db 100644 --- a/ssh-key/tests/private_key.rs +++ b/ssh-key/tests/private_key.rs @@ -9,7 +9,7 @@ use ssh_key::{Algorithm, Cipher, KdfAlg, PrivateKey}; use ssh_key::EcdsaCurve; #[cfg(feature = "alloc")] use ssh_key::LineEnding; -#[cfg(feature = "std")] +#[cfg(all(feature = "sha2", feature = "std"))] use { ssh_key::PublicKey, std::{io, path::PathBuf, process}, @@ -104,7 +104,7 @@ const OPENSSH_OVERPADDED_PUTTYGEN_EXAMPLE: &str = include_str!("examples/puttyge const OPENSSH_NON_UTF8_COMMENT_EXAMPLE: &str = include_str!("examples/non_utf8_comment"); /// Get a path into the `tests/scratch` directory. -#[cfg(feature = "std")] +#[cfg(all(feature = "sha2", feature = "std"))] #[must_use] pub fn scratch_path(filename: &str) -> PathBuf { PathBuf::from(&format!("tests/scratch/{}", filename)) @@ -664,10 +664,10 @@ fn encode_custom_algorithm_openssh() { /// Common behavior of all encoding tests #[cfg(feature = "alloc")] fn encoding_test(private_key: &str) { - #[cfg_attr(not(feature = "std"), allow(unused_variables))] + #[cfg_attr(not(all(feature = "sha2", feature = "std")), allow(unused_variables))] let key = round_trip_test(private_key); - #[cfg(feature = "std")] + #[cfg(all(feature = "sha2", feature = "std"))] if !matches!(key.algorithm(), Algorithm::Other(_)) { encoding_integration_test(key); } @@ -686,7 +686,7 @@ fn round_trip_test(private_key: &str) -> PrivateKey { } /// Parse PEM encoded using `PrivateKey::to_openssh` using the `ssh-keygen` utility. -#[cfg(feature = "std")] +#[cfg(all(feature = "sha2", feature = "std"))] fn encoding_integration_test(private_key: PrivateKey) { let fingerprint = private_key .fingerprint(Default::default()) diff --git a/ssh-key/tests/public_key.rs b/ssh-key/tests/public_key.rs index 3e777393..9b687eb1 100644 --- a/ssh-key/tests/public_key.rs +++ b/ssh-key/tests/public_key.rs @@ -11,7 +11,7 @@ use {sec1::consts::U32, ssh_key::public::SkEcdsaSha2NistP256}; #[cfg(feature = "ecdsa")] use ssh_key::EcdsaCurve; -#[cfg(feature = "std")] +#[cfg(all(feature = "sha2", feature = "std"))] use std::{fs, path::PathBuf}; /// DSA OpenSSH-formatted public key @@ -53,7 +53,7 @@ const OPENSSH_SK_ED25519_EXAMPLE: &str = include_str!("examples/id_sk_ed25519.pu const OPENSSH_OPAQUE_EXAMPLE: &str = include_str!("examples/id_opaque.pub"); /// Get a path into the `tests/scratch` directory. -#[cfg(feature = "std")] +#[cfg(all(feature = "sha2", feature = "std"))] #[must_use] pub fn scratch_path(filename: &str) -> PathBuf { PathBuf::from(&format!("tests/scratch/{}.pub", filename)) @@ -96,6 +96,7 @@ fn decode_dsa_openssh() { ); assert_eq!(b"user@example.com", key.comment().as_bytes()); + #[cfg(feature = "sha2")] assert_eq!( "SHA256:Nh0Me49Zh9fDw/VYUfq43IJmI1T+XrjiYONPND8GzaM", &key.fingerprint(Default::default()).to_string(), @@ -126,6 +127,7 @@ fn decode_ecdsa_p256_openssh() { #[cfg(feature = "alloc")] assert_eq!(b"user@example.com", key.comment().as_bytes()); + #[cfg(feature = "sha2")] assert_eq!( "SHA256:JQ6FV0rf7qqJHZqIj4zNH8eV0oB8KLKh9Pph3FTD98g", &key.fingerprint(Default::default()).to_string(), @@ -157,6 +159,7 @@ fn decode_ecdsa_p384_openssh() { #[cfg(feature = "alloc")] assert_eq!(b"user@example.com", key.comment().as_bytes()); + #[cfg(feature = "sha2")] assert_eq!( "SHA256:nkGE8oV7pHvOiPKHtQRs67WUPiVLRxbNu//gV/k4Vjw", &key.fingerprint(Default::default()).to_string(), @@ -189,6 +192,7 @@ fn decode_ecdsa_p521_openssh() { #[cfg(feature = "alloc")] assert_eq!(b"user@example.com", key.comment().as_bytes()); + #[cfg(feature = "sha2")] assert_eq!( "SHA256:l3AUUMK6Q2BbuiqvMx2fs97f8LUYq7sWCAx7q5m3S6M", &key.fingerprint(Default::default()).to_string(), @@ -208,6 +212,7 @@ fn decode_ed25519_openssh() { #[cfg(feature = "alloc")] assert_eq!(b"user@example.com", key.comment().as_bytes()); + #[cfg(feature = "sha2")] assert_eq!( "SHA256:UCUiLr7Pjs9wFFJMDByLgc3NrtdU344OgUM45wZPcIQ", &key.fingerprint(Default::default()).to_string(), @@ -238,6 +243,7 @@ fn decode_rsa_3072_openssh() { rsa_key.n().as_bytes(), ); assert_eq!(b"user@example.com", key.comment().as_bytes()); + #[cfg(feature = "sha2")] assert_eq!( "SHA256:Fmxts/GcV77PakFnf1Ueki5mpU4ZjUQWGRjZGAo3n/I", &key.fingerprint(Default::default()).to_string(), @@ -271,6 +277,7 @@ fn decode_rsa_4096_openssh() { rsa_key.n().as_bytes(), ); assert_eq!(b"user@example.com", key.comment().as_bytes()); + #[cfg(feature = "sha2")] assert_eq!( "SHA256:FKAyeywtQNZLl1YTzIzCV/ThadBlnWMaD7jHQYDseEY", &key.fingerprint(Default::default()).to_string(), @@ -297,6 +304,7 @@ fn decode_sk_ecdsa_p256_openssh() { #[cfg(feature = "alloc")] assert_eq!(b"user@example.com", key.comment().as_bytes()); + #[cfg(feature = "sha2")] assert_eq!( "SHA256:UINe2WXFh3SiqwLxsBv34fBO2ei+g7uOeJJXVEK95iE", &key.fingerprint(Default::default()).to_string(), @@ -338,6 +346,7 @@ fn decode_sk_ed25519_openssh() { #[cfg(feature = "alloc")] assert_eq!(b"user@example.com", key.comment().as_bytes()); + #[cfg(feature = "sha2")] assert_eq!( "SHA256:6WZVJ44bqhAWLVP4Ns0TDkoSQSsZo/h2K+mEvOaNFbw", &key.fingerprint(Default::default()).to_string(), @@ -376,6 +385,7 @@ fn decode_custom_algorithm_openssh() { assert_eq!(b"comment@example.com", key.comment().as_bytes()); + #[cfg(feature = "sha2")] assert_eq!( "SHA256:8GV7v5qOHG9invseKCx0NVwFocNL0MwdyRC9bfjTFGs", &key.fingerprint(Default::default()).to_string(), @@ -438,7 +448,7 @@ fn public_keys_are_hashable() { assert!(set.contains(&key)); } -#[cfg(feature = "std")] +#[cfg(all(feature = "sha2", feature = "std"))] #[test] fn write_openssh_file() { let example_key = OPENSSH_ED25519_EXAMPLE; diff --git a/ssh-key/tests/sshsig.rs b/ssh-key/tests/sshsig.rs index 2b0ae637..8d1db95c 100644 --- a/ssh-key/tests/sshsig.rs +++ b/ssh-key/tests/sshsig.rs @@ -11,13 +11,24 @@ use ssh_key::{Algorithm, HashAlg, LineEnding, PublicKey, SshSig}; feature = "p256", feature = "rsa" ))] -use {encoding::Decode, signature::Verifier, ssh_key::PrivateKey, ssh_key::Signature}; +use {encoding::Decode, signature::Verifier, ssh_key::Signature}; + +#[cfg(all( + feature = "sha2", + any( + feature = "dsa", + feature = "ed25519", + feature = "p256", + feature = "rsa" + ) +))] +use ssh_key::PrivateKey; #[cfg(feature = "ed25519")] use ssh_key::Error; /// DSA OpenSSH-formatted private key. -#[cfg(feature = "dsa")] +#[cfg(all(feature = "dsa", feature = "sha2"))] const DSA_PRIVATE_KEY: &str = include_str!("examples/id_dsa_1024"); /// DSA OpenSSH-formatted public key. @@ -172,7 +183,7 @@ fn encode_sk_ed25519() { } #[test] -#[cfg(feature = "dsa")] +#[cfg(all(feature = "dsa", feature = "sha2"))] fn sign_dsa() { let signing_key = PrivateKey::from_openssh(DSA_PRIVATE_KEY).unwrap(); let verifying_key = DSA_PUBLIC_KEY.parse::().unwrap();