diff --git a/.github/workflows/ssh-key.yml b/.github/workflows/ssh-key.yml index 358e97b5..565b9ad2 100644 --- a/.github/workflows/ssh-key.yml +++ b/.github/workflows/ssh-key.yml @@ -69,7 +69,7 @@ jobs: toolchain: ${{ matrix.rust }} target: ${{ matrix.target }} - uses: RustCrypto/actions/cargo-hack-install@master - - run: cargo hack build --target ${{ matrix.target }} --feature-powerset --exclude-features default,getrandom,std + - run: cargo hack build --target ${{ matrix.target }} --feature-powerset --exclude-features crypto,default,getrandom,std --release test: runs-on: ubuntu-latest @@ -84,9 +84,12 @@ jobs: with: toolchain: ${{ matrix.rust }} - uses: RustCrypto/actions/cargo-hack-install@master - - run: cargo hack test --feature-powerset --exclude-features aes-gcm,default,encryption,getrandom,std - - run: cargo test --features aes-gcm - - run: cargo test --features encryption - - run: cargo test --features getrandom - - run: cargo test --features std - - run: cargo test --all-features + - run: cargo hack test --feature-powerset --exclude-features aes-gcm,crypto,default,encryption,getrandom,std --release + - run: cargo test --release + - run: cargo test --release --features aes-gcm + - run: cargo test --release --features crypto + - run: cargo test --release --features encryption + - run: cargo test --release --features getrandom + - run: cargo test --release --features std + - run: cargo test --all-features # debug build + - run: cargo test --release --all-features diff --git a/Cargo.lock b/Cargo.lock index 117b392f..2c4a02bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -656,6 +656,7 @@ dependencies = [ "pkcs1", "pkcs8", "rand_core", + "sha2", "signature", "subtle", "zeroize", diff --git a/ssh-key/Cargo.toml b/ssh-key/Cargo.toml index de3db91f..ad3c6fa9 100644 --- a/ssh-key/Cargo.toml +++ b/ssh-key/Cargo.toml @@ -34,7 +34,7 @@ ed25519-dalek = { version = "=2.0.0-pre.0", optional = true, default-features = p256 = { version = "0.13", optional = true, default-features = false, features = ["ecdsa"] } p384 = { version = "0.13", optional = true, default-features = false, features = ["ecdsa"] } rand_core = { version = "0.6.4", optional = true, default-features = false } -rsa = { version = "=0.9.0-pre.0", optional = true, default-features = false } +rsa = { version = "=0.9.0-pre.0", optional = true, default-features = false, features = ["sha2"] } sec1 = { version = "0.7", optional = true, default-features = false, features = ["point"] } serde = { version = "1", optional = true } sha1 = { version = "0.10", optional = true, default-features = false } @@ -62,12 +62,15 @@ std = [ ] aes-gcm = ["dep:aes-gcm", "encryption"] +crypto = ["aes-gcm", "ed25519", "p256", "p384", "rsa"] # NOTE: `dsa` is obsolete/weak dsa = ["dep:bigint", "dep:dsa", "dep:sha1", "alloc", "signature/rand_core"] ecdsa = ["dep:sec1"] ed25519 = ["dep:ed25519-dalek", "rand_core"] encryption = [ "alloc", "dep:aes", "dep:bcrypt-pbkdf", "dep:ctr", "rand_core"] getrandom = ["rand_core/getrandom"] -rsa = ["dep:bigint", "dep:rsa", "alloc", "rand_core", "sha2/oid"] +p256 = ["dep:p256", "ecdsa"] +p384 = ["dep:p384", "ecdsa"] +rsa = ["dep:bigint", "dep:rsa", "alloc", "rand_core"] [package.metadata.docs.rs] all-features = true diff --git a/ssh-key/README.md b/ssh-key/README.md index 257548f6..73652927 100644 --- a/ssh-key/README.md +++ b/ssh-key/README.md @@ -61,7 +61,7 @@ respective SSH key algorithm. - [ ] [RFC4716] public keys - [ ] SEC1 -## Supported algorithms +### Supported Signature Algorithms | Name | Decode | Encode | Cert | Keygen | Sign | Verify | Feature | `no_std` | |--------------------------------------|--------|--------|------|--------|------|--------|-----------|----------| @@ -74,7 +74,13 @@ respective SSH key algorithm. | `sk‑ecdsa‑sha2‑nistp256@openssh.com` | ✅ | ✅ | ✅ | ⛔ | ⛔️ | ⛔️ | ⛔ | `alloc` | | `sk‑ssh‑ed25519@openssh.com` | ✅ | ✅ | ✅ | ⛔ | ⛔️ | ⛔️ | ⛔ | `alloc` | -Note: the "Feature" section lists the name of `ssh-key` crate features which can +By default *no algorithms are enabled* and you will get an +`Error::AlgorithmUnsupported` error if you try to use them. + +Enable the `crypto` feature or the "Feature" for specific algorithms in the +chart above (e.g. `p256`, `rsa`) in order to use cryptographic functionality. + +The "Feature" column lists the name of `ssh-key` crate features which can be enabled to provide full support for the "Keygen", "Sign", and "Verify" functionality for a particular SSH key algorithm. diff --git a/ssh-key/tests/certificate_builder.rs b/ssh-key/tests/certificate_builder.rs index 9f5b0533..af726fb5 100644 --- a/ssh-key/tests/certificate_builder.rs +++ b/ssh-key/tests/certificate_builder.rs @@ -1,18 +1,19 @@ //! Certificate builder tests. -#![cfg(all(feature = "alloc", any(feature = "ed25519", feature = "p256")))] +#![cfg(all( + feature = "alloc", + feature = "rand_core", + any(feature = "ed25519", feature = "p256") +))] use hex_literal::hex; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; -use ssh_key::{ - certificate::{self, CertType}, - Algorithm, PrivateKey, -}; +use ssh_key::{certificate, Algorithm, PrivateKey}; #[cfg(feature = "p256")] use ssh_key::EcdsaCurve; -#[cfg(feature = "rsa")] +#[cfg(all(feature = "ed25519", feature = "rsa"))] use std::str::FromStr; /// Example Unix timestamp when a certificate was issued (2020-09-13 12:26:40 UTC). @@ -24,36 +25,21 @@ const VALID_AT: u64 = 1650000000; /// Example Unix timestamp when a certificate expires (2023-11-14 22:13:20 UTC). const EXPIRES_AT: u64 = 1700000000; -/// Example serial number. -const SERIAL: u64 = 42; - -/// Example key ID. -const KEY_ID: &str = "example"; - -/// Example principal name. -const PRINCIPAL: &str = "nobody"; - -/// Critical extension 1. -const CRITICAL_EXTENSION_1: (&str, &str) = ("critical name 1", "critical data 2"); - -/// Critical extension 1. -const CRITICAL_EXTENSION_2: (&str, &str) = ("critical name 2", "critical data 2"); - -/// Non critical extension 1. -const EXTENSION_1: (&str, &str) = ("extension name 1", "extension data 1"); - -/// Non critical extension 2. -const EXTENSION_2: (&str, &str) = ("extension name 2", "extension data 2"); - -/// Example comment. -const COMMENT: &str = "user@example.com"; - /// Seed to use for PRNG. const PRNG_SEED: [u8; 32] = [42; 32]; #[cfg(feature = "ed25519")] #[test] fn ed25519_sign_and_verify() { + const SERIAL: u64 = 42; + const KEY_ID: &str = "example"; + const PRINCIPAL: &str = "nobody"; + const CRITICAL_EXTENSION_1: (&str, &str) = ("critical name 1", "critical data 2"); + const CRITICAL_EXTENSION_2: (&str, &str) = ("critical name 2", "critical data 2"); + const EXTENSION_1: (&str, &str) = ("extension name 1", "extension data 1"); + const EXTENSION_2: (&str, &str) = ("extension name 2", "extension data 2"); + const COMMENT: &str = "user@example.com"; + let mut rng = ChaCha8Rng::from_seed(PRNG_SEED); let ca_key = PrivateKey::random(&mut rng, Algorithm::Ed25519).unwrap(); @@ -89,7 +75,7 @@ fn ed25519_sign_and_verify() { assert_eq!(cert.nonce(), &hex!("321fdf7e0a2afe803308f394f54c6abe")); assert_eq!(cert.public_key(), subject_key.public_key().key_data()); assert_eq!(cert.serial(), SERIAL); - assert_eq!(cert.cert_type(), CertType::User); + assert_eq!(cert.cert_type(), certificate::CertType::User); assert_eq!(cert.key_id(), KEY_ID); assert_eq!(cert.valid_principals().len(), 1); assert_eq!(cert.valid_principals()[0], PRINCIPAL); @@ -140,7 +126,7 @@ fn ecdsa_nistp256_sign_and_verify() { assert!(cert.validate_at(VALID_AT, &[ca_fingerprint]).is_ok()); } -#[cfg(feature = "rsa")] +#[cfg(all(feature = "ed25519", feature = "rsa"))] #[test] fn rsa_sign_and_verify() { let ca_key = PrivateKey::from_str( diff --git a/ssh-key/tests/sshsig.rs b/ssh-key/tests/sshsig.rs index e2b918c3..8e3dde19 100644 --- a/ssh-key/tests/sshsig.rs +++ b/ssh-key/tests/sshsig.rs @@ -5,7 +5,12 @@ use hex_literal::hex; use ssh_key::{Algorithm, HashAlg, LineEnding, PublicKey, SshSig}; -#[cfg(any(feature = "dsa", feature = "ed25519", feature = "rsa"))] +#[cfg(any( + feature = "dsa", + feature = "ed25519", + feature = "p256", + feature = "rsa" +))] use ssh_key::PrivateKey; #[cfg(feature = "ed25519")]