From aacd268dee9afb1bd0f7f8829c8110116a9a722c Mon Sep 17 00:00:00 2001 From: Adam Michalik Date: Wed, 1 Oct 2025 20:57:08 -0400 Subject: [PATCH 1/3] kex/sign --- Cargo.toml | 16 ++++++++------- src/kx.rs | 20 +++++++++---------- src/lib.rs | 26 +++++++++++++++++++++++-- src/sign.rs | 47 +++++++++++++++++++++++++++++++++++++-------- src/sign/ecdsa.rs | 2 ++ src/verify.rs | 42 +++++++++++++++++++++++++++++++++++++--- src/verify/ecdsa.rs | 4 ++++ 7 files changed, 126 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 01ab6b0..1c53450 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,21 +25,21 @@ crypto-common = { version = "0.1.6", default-features = false } der = { version = "0.7.9", default-features = false } digest = { version = "0.10.7", default-features = false } ecdsa = { version = "0.16.8", default-features = false, features = ["alloc"] } -ed25519-dalek = { version = "2", default-features = false, features = ["pkcs8"] } +ed25519-dalek = { version = "2", default-features = false, features = ["pkcs8"], optional = true } hmac = { version = "0.12.1", default-features = false } -p256 = { version = "0.13.2", default-features = false, features = ["pem", "ecdsa", "ecdh"] } -p384 = { version = "0.13.0", default-features = false, features = ["pem", "ecdsa", "ecdh"] } +p256 = { version = "0.13.2", default-features = false, features = ["pem", "ecdsa", "ecdh"], optional = true } +p384 = { version = "0.13.0", default-features = false, features = ["pem", "ecdsa", "ecdh"], optional = true } paste = { version = "1.0.15", default-features = false } pkcs8 = { version = "0.10.2", default-features = false, features = ["pem", "pkcs5"] } pki-types = { package = "rustls-pki-types", version = "1.0.1", default-features = false } rand_core = { version = "0.6.4", default-features = false, features = ["getrandom"] } -rsa = { version = "0.9.2", default-features = false, features = ["sha2"] } +rsa = { version = "0.9.2", default-features = false, features = ["sha2"], optional = true } rustls = { version = "0.23.12", default-features = false } sec1 = { version = "0.7.3", default-features = false, features = ["pkcs8", "pem"] } sha2 = { version = "0.10.7", default-features = false } signature = { version = "2.1.0", default-features = false } webpki = { package = "rustls-webpki", version = "0.102.0", default-features = false } -x25519-dalek = { version = "2", default-features = false } +x25519-dalek = { version = "2", default-features = false, optional = true } [dev-dependencies] getrandom = { version = "0.2", features = ["custom"] } # workaround to build on no_std targets @@ -53,7 +53,9 @@ tls12 = ["rustls/tls12"] # zeroize is another typical that can be turned off # TODO: go through all of these that what gets exposed re: std error type -std = ["alloc", "webpki/std", "pki-types/std", "rustls/std", "ed25519-dalek/std"] +std = ["alloc", "webpki/std", "pki-types/std", "rustls/std"] # TODO: go through all of these to ensure to_vec etc. impls are exposed -alloc = ["webpki/alloc", "pki-types/alloc", "aead/alloc", "ed25519-dalek/alloc"] +alloc = ["webpki/alloc", "pki-types/alloc", "aead/alloc"] zeroize = ["ed25519-dalek/zeroize", "x25519-dalek/zeroize"] +x25519 = ["dep:x25519-dalek"] +ed25519 = ["dep:ed25519-dalek", "ed25519-dalek/alloc", "ed25519-dalek/std", "alloc"] diff --git a/src/kx.rs b/src/kx.rs index 66341f2..ee7cb09 100644 --- a/src/kx.rs +++ b/src/kx.rs @@ -1,13 +1,8 @@ -#[cfg(feature = "alloc")] -use alloc::boxed::Box; - -use crypto::{SharedSecret, SupportedKxGroup}; -use paste::paste; -use rustls::crypto; - +#[cfg(feature = "x25519")] #[derive(Debug)] pub struct X25519; +#[cfg(feature = "x25519")] impl crypto::SupportedKxGroup for X25519 { fn name(&self) -> rustls::NamedGroup { rustls::NamedGroup::X25519 @@ -20,13 +15,15 @@ impl crypto::SupportedKxGroup for X25519 { } } +#[cfg(feature = "x25519")] pub struct X25519KeyExchange { priv_key: x25519_dalek::EphemeralSecret, pub_key: x25519_dalek::PublicKey, } +#[cfg(feature = "x25519")] impl crypto::ActiveKeyExchange for X25519KeyExchange { - fn complete(self: Box, peer: &[u8]) -> Result { + fn complete(self: Box, peer: &[u8]) -> Result { let peer_array: [u8; 32] = peer .try_into() .map_err(|_| rustls::Error::from(rustls::PeerMisbehaved::InvalidKeyShare))?; @@ -48,7 +45,7 @@ impl crypto::ActiveKeyExchange for X25519KeyExchange { macro_rules! impl_kx { ($name:ident, $kx_name:ty, $secret:ty, $public_key:ty) => { - paste! { + paste::paste! { #[derive(Debug)] #[allow(non_camel_case_types)] @@ -79,7 +76,7 @@ macro_rules! impl_kx { fn complete( self: Box<[<$name KeyExchange>]>, peer: &[u8], - ) -> Result { + ) -> Result { let their_pub = $public_key::from_sec1_bytes(peer) .map_err(|_| rustls::Error::from(rustls::PeerMisbehaved::InvalidKeyShare))?; Ok(self @@ -102,7 +99,8 @@ macro_rules! impl_kx { }; } +#[cfg(feature = "p256")] impl_kx! {SecP256R1, rustls::NamedGroup::secp256r1, p256::ecdh::EphemeralSecret, p256::PublicKey} +#[cfg(feature = "p384")] impl_kx! {SecP384R1, rustls::NamedGroup::secp384r1, p384::ecdh::EphemeralSecret, p384::PublicKey} -pub const ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = &[&X25519, &SecP256R1, &SecP384R1]; diff --git a/src/lib.rs b/src/lib.rs index 1b108b8..016047b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,7 +44,7 @@ use alloc::sync::Arc; use rustls::crypto::{ CipherSuiteCommon, CryptoProvider, GetRandomFailed, KeyProvider, SecureRandom, }; -use rustls::{CipherSuite, SupportedCipherSuite, Tls13CipherSuite}; +use rustls::{crypto, CipherSuite, SupportedCipherSuite, Tls13CipherSuite}; #[cfg(feature = "tls12")] use rustls::SignatureScheme; @@ -55,7 +55,7 @@ pub struct Provider; pub fn provider() -> CryptoProvider { CryptoProvider { cipher_suites: ALL_CIPHER_SUITES.to_vec(), - kx_groups: kx::ALL_KX_GROUPS.to_vec(), + kx_groups: ALL_KX_GROUPS.to_vec(), signature_verification_algorithms: verify::ALGORITHMS, secure_random: &Provider, key_provider: &Provider, @@ -261,9 +261,31 @@ static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = misc::const_concat_slices!( TLS13_SUITES, ); +#[cfg(feature = "p256")] +pub use verify::ecdsa::{ECDSA_P256_SHA256, ECDSA_P256_SHA384}; +#[cfg(feature = "p384")] +pub use verify::ecdsa::{ECDSA_P384_SHA256, ECDSA_P384_SHA384}; + +#[cfg(feature = "ed25519")] +pub use verify::eddsa::ED25519; + +#[cfg(feature = "rsa")] +pub use verify::rsa::{RSA_PKCS1_SHA256, RSA_PKCS1_SHA384, RSA_PKCS1_SHA512, RSA_PSS_SHA256, RSA_PSS_SHA384, RSA_PSS_SHA512}; + +const ALL_KX_GROUPS: &[&dyn crypto::SupportedKxGroup] = &[ + #[cfg(feature = "x25519")] + &X25519, + #[cfg(feature = "p256")] + &SecP256R1, + #[cfg(feature = "p384")] + &SecP384R1 +]; + mod aead; mod hash; mod hmac; + +#[cfg(any(feature = "x25519", feature = "p256", feature = "p384"))] mod kx; mod misc; pub mod quic; diff --git a/src/sign.rs b/src/sign.rs index e6109f5..b28533d 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -2,8 +2,13 @@ use alloc::{sync::Arc, vec::Vec}; use core::marker::PhantomData; -use self::ecdsa::{EcdsaSigningKeyP256, EcdsaSigningKeyP384}; +#[cfg(feature = "p256")] +use self::ecdsa::EcdsaSigningKeyP256; +#[cfg(feature = "p384")] +use self::ecdsa::EcdsaSigningKeyP384; +#[cfg(feature = "ed25519")] use self::eddsa::Ed25519SigningKey; +#[cfg(feature = "rsa")] use self::rsa::RsaSigningKey; use pki_types::PrivateKeyDer; @@ -72,24 +77,47 @@ where /// # Errors /// /// Returns an error if the key couldn't be decoded. +#[allow(unused_variables, reason = "the argument is unused if all features are disabled")] pub fn any_supported_type(der: &PrivateKeyDer<'_>) -> Result, rustls::Error> { - RsaSigningKey::try_from(der) - .map(|x| Arc::new(x) as _) - .or_else(|_| any_ecdsa_type(der)) - .or_else(|_| any_eddsa_type(der)) + #[cfg(feature = "rsa")] + if let Ok(key) = RsaSigningKey::try_from(der) { + return Ok(Arc::new(key)); + } + + #[cfg(any(feature = "p256", feature = "p384"))] + if let Ok(key) = any_ecdsa_type(der) { + return Ok(key); + } + + #[cfg(feature = "ed25519")] + if let Ok(key) = any_eddsa_type(der) { + return Ok(key); + } + + Err(rustls::Error::General("unsupported private key format".into())) } +#[cfg(any(feature = "p256", feature = "p384"))] /// Extract any supported ECDSA key from the given DER input. /// /// # Errors /// /// Returns an error if the key couldn't be decoded. pub fn any_ecdsa_type(der: &PrivateKeyDer<'_>) -> Result, rustls::Error> { - let p256 = |_| EcdsaSigningKeyP256::try_from(der).map(|x| Arc::new(x) as _); - let p384 = |_| EcdsaSigningKeyP384::try_from(der).map(|x| Arc::new(x) as _); - p256(()).or_else(p384) + #[cfg(feature = "p256")] + if let Ok(key) = EcdsaSigningKeyP256::try_from(der) { + return Ok(Arc::new(key)); + } + + #[cfg(feature = "p384")] + if let Ok(key) = EcdsaSigningKeyP384::try_from(der) { + return Ok(Arc::new(key)); + } + + Err(rustls::Error::General("unsupported private key format".into())) } +#[cfg(feature = "ed25519")] /// Extract any supported EDDSA key from the given DER input. /// /// # Errors @@ -100,6 +128,9 @@ pub fn any_eddsa_type(der: &PrivateKeyDer<'_>) -> Result, ru Ed25519SigningKey::try_from(der).map(|x| Arc::new(x) as _) } +#[cfg(any(feature = "p256", feature = "p384"))] pub mod ecdsa; +#[cfg(feature = "ed25519")] pub mod eddsa; +#[cfg(feature = "rsa")] pub mod rsa; diff --git a/src/sign/ecdsa.rs b/src/sign/ecdsa.rs index 3f4a2bc..b1e21d0 100644 --- a/src/sign/ecdsa.rs +++ b/src/sign/ecdsa.rs @@ -62,5 +62,7 @@ macro_rules! impl_ecdsa { }; } +#[cfg(feature = "p256")] impl_ecdsa! {P256, SignatureScheme::ECDSA_NISTP256_SHA256, p256::ecdsa::SigningKey, p256::ecdsa::DerSignature} +#[cfg(feature = "p384")] impl_ecdsa! {P384, SignatureScheme::ECDSA_NISTP384_SHA384, p384::ecdsa::SigningKey, p384::ecdsa::DerSignature} diff --git a/src/verify.rs b/src/verify.rs index 2043b64..92a0289 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -1,8 +1,13 @@ use rustls::crypto::WebPkiSupportedAlgorithms; use rustls::SignatureScheme; -use self::ecdsa::{ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P384_SHA256, ECDSA_P384_SHA384}; +#[cfg(feature = "p256")] +use self::ecdsa::{ECDSA_P256_SHA256, ECDSA_P256_SHA384}; +#[cfg(feature = "p384")] +use self::ecdsa::{ECDSA_P384_SHA256, ECDSA_P384_SHA384}; +#[cfg(feature = "ed25519")] use self::eddsa::ED25519; +#[cfg(feature = "rsa")] use self::rsa::{ RSA_PKCS1_SHA256, RSA_PKCS1_SHA384, RSA_PKCS1_SHA512, RSA_PSS_SHA256, RSA_PSS_SHA384, RSA_PSS_SHA512, @@ -10,37 +15,68 @@ use self::rsa::{ pub static ALGORITHMS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms { all: &[ + #[cfg(feature = "p256")] ECDSA_P256_SHA256, + #[cfg(feature = "p256")] ECDSA_P256_SHA384, + #[cfg(feature = "p384")] ECDSA_P384_SHA256, + #[cfg(feature = "p384")] ECDSA_P384_SHA384, + #[cfg(feature = "ed25519")] ED25519, + #[cfg(feature = "rsa")] RSA_PKCS1_SHA256, + #[cfg(feature = "rsa")] RSA_PKCS1_SHA384, + #[cfg(feature = "rsa")] RSA_PKCS1_SHA512, + #[cfg(feature = "rsa")] RSA_PSS_SHA256, + #[cfg(feature = "rsa")] RSA_PSS_SHA384, + #[cfg(feature = "rsa")] RSA_PSS_SHA512, ], mapping: &[ ( SignatureScheme::ECDSA_NISTP384_SHA384, - &[ECDSA_P384_SHA384, ECDSA_P256_SHA384], + &[ + #[cfg(feature = "p384")] + ECDSA_P384_SHA384, + #[cfg(feature = "p256")] + ECDSA_P256_SHA384 + ], ), ( SignatureScheme::ECDSA_NISTP256_SHA256, - &[ECDSA_P256_SHA256, ECDSA_P384_SHA256], + &[ + #[cfg(feature = "p256")] + ECDSA_P256_SHA256, + #[cfg(feature = "p384")] + ECDSA_P384_SHA256 + ], ), + #[cfg(feature = "ed25519")] (SignatureScheme::ED25519, &[ED25519]), + #[cfg(feature = "rsa")] (SignatureScheme::RSA_PKCS1_SHA256, &[RSA_PKCS1_SHA256]), + #[cfg(feature = "rsa")] (SignatureScheme::RSA_PKCS1_SHA384, &[RSA_PKCS1_SHA384]), + #[cfg(feature = "rsa")] (SignatureScheme::RSA_PKCS1_SHA512, &[RSA_PKCS1_SHA512]), + #[cfg(feature = "rsa")] (SignatureScheme::RSA_PSS_SHA256, &[RSA_PSS_SHA256]), + #[cfg(feature = "rsa")] (SignatureScheme::RSA_PSS_SHA384, &[RSA_PSS_SHA384]), + #[cfg(feature = "rsa")] (SignatureScheme::RSA_PSS_SHA512, &[RSA_PSS_SHA512]), ], }; +#[cfg(any(feature = "p256", feature = "p384"))] pub mod ecdsa; +#[cfg(feature = "ed25519")] pub mod eddsa; +#[cfg(feature = "rsa")] pub mod rsa; diff --git a/src/verify/ecdsa.rs b/src/verify/ecdsa.rs index 669f03d..69bdf3d 100644 --- a/src/verify/ecdsa.rs +++ b/src/verify/ecdsa.rs @@ -48,7 +48,11 @@ macro_rules! impl_generic_ecdsa_verifer { }; } +#[cfg(feature = "p256")] impl_generic_ecdsa_verifer! {ECDSA_P256_SHA256, alg_id::ECDSA_P256, alg_id::ECDSA_SHA256, p256::ecdsa::VerifyingKey, p256::ecdsa::DerSignature, sha2::Sha256} +#[cfg(feature = "p256")] impl_generic_ecdsa_verifer! {ECDSA_P256_SHA384, alg_id::ECDSA_P256, alg_id::ECDSA_SHA384, p256::ecdsa::VerifyingKey, p256::ecdsa::DerSignature, sha2::Sha384} +#[cfg(feature = "p384")] impl_generic_ecdsa_verifer! {ECDSA_P384_SHA256, alg_id::ECDSA_P384, alg_id::ECDSA_SHA256, p384::ecdsa::VerifyingKey, p384::ecdsa::DerSignature, sha2::Sha256} +#[cfg(feature = "p384")] impl_generic_ecdsa_verifer! {ECDSA_P384_SHA384, alg_id::ECDSA_P384, alg_id::ECDSA_SHA384, p384::ecdsa::VerifyingKey, p384::ecdsa::DerSignature, sha2::Sha384} From 56d5580010f0ad6cfd74f40c5e321249df4297ec Mon Sep 17 00:00:00 2001 From: Adam Michalik Date: Wed, 1 Oct 2025 21:56:58 -0400 Subject: [PATCH 2/3] . --- .gitignore | 1 + Cargo.toml | 20 +++++++---- src/aead.rs | 1 + src/aead/chacha20.rs | 5 +++ src/aead/gcm.rs | 6 ++-- src/kx.rs | 23 +++++++++--- src/lib.rs | 86 ++++++++++++++++++++------------------------ src/sign.rs | 6 ++-- src/verify.rs | 2 +- 9 files changed, 86 insertions(+), 64 deletions(-) diff --git a/.gitignore b/.gitignore index a326afe..3e9f0e3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ debug/ target/ **/*.rs.bk *.pdb +.idea/ \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 1c53450..63e624b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,12 +19,12 @@ resolver = "1" # Hack to enable the `custom` feature of `getrandom` # default features often have std breaking no_std and potentially other unwanted [dependencies] aead = { version = "0.5.2", default-features = false } -aes-gcm = { version = "0.10.3", default-features = false, features = ["aes", "alloc"] } -chacha20poly1305 = { version = "0.10.1", default-features = false } +aes-gcm = { version = "0.10.3", default-features = false, features = ["aes", "alloc"], optional = true } +chacha20poly1305 = { version = "0.10.1", default-features = false, optional = true } crypto-common = { version = "0.1.6", default-features = false } der = { version = "0.7.9", default-features = false } digest = { version = "0.10.7", default-features = false } -ecdsa = { version = "0.16.8", default-features = false, features = ["alloc"] } +ecdsa = { version = "0.16.8", default-features = false, features = ["alloc"], optional = true } ed25519-dalek = { version = "2", default-features = false, features = ["pkcs8"], optional = true } hmac = { version = "0.12.1", default-features = false } p256 = { version = "0.13.2", default-features = false, features = ["pem", "ecdsa", "ecdh"], optional = true } @@ -37,7 +37,7 @@ rsa = { version = "0.9.2", default-features = false, features = ["sha2"], option rustls = { version = "0.23.12", default-features = false } sec1 = { version = "0.7.3", default-features = false, features = ["pkcs8", "pem"] } sha2 = { version = "0.10.7", default-features = false } -signature = { version = "2.1.0", default-features = false } +signature = { version = "2.1.0", default-features = false, features = ["rand_core", "alloc"] } webpki = { package = "rustls-webpki", version = "0.102.0", default-features = false } x25519-dalek = { version = "2", default-features = false, optional = true } @@ -45,9 +45,9 @@ x25519-dalek = { version = "2", default-features = false, optional = true } getrandom = { version = "0.2", features = ["custom"] } # workaround to build on no_std targets [features] -default = ["std", "tls12", "zeroize"] +default = ["std", "tls12", "zeroize", "quic", "aes-gcm", "chacha20poly1305", "rsa", "p256", "p384", "ed25519", "x25519"] logging = ["rustls/logging"] -tls12 = ["rustls/tls12"] +tls12 = ["rustls/tls12", "ecdsa"] # Only enable feature in upstream if there is an overall effect e.g. aead/alloc in-place # zeroize is another typical that can be turned off @@ -56,6 +56,12 @@ tls12 = ["rustls/tls12"] std = ["alloc", "webpki/std", "pki-types/std", "rustls/std"] # TODO: go through all of these to ensure to_vec etc. impls are exposed alloc = ["webpki/alloc", "pki-types/alloc", "aead/alloc"] -zeroize = ["ed25519-dalek/zeroize", "x25519-dalek/zeroize"] +zeroize = ["ed25519-dalek?/zeroize", "x25519-dalek?/zeroize"] +quic = ["chacha20poly1305"] +aes-gcm = ["dep:aes-gcm"] +chacha20poly1305 = ["dep:chacha20poly1305"] +ecdsa = ["dep:ecdsa"] +p256 = ["dep:p256", "ecdsa"] +p384 = ["dep:p384", "ecdsa"] x25519 = ["dep:x25519-dalek"] ed25519 = ["dep:ed25519-dalek", "ed25519-dalek/alloc", "ed25519-dalek/std", "alloc"] diff --git a/src/aead.rs b/src/aead.rs index 6ff57b7..1b42417 100644 --- a/src/aead.rs +++ b/src/aead.rs @@ -1,6 +1,7 @@ use aead::Buffer; use rustls::crypto::cipher::{BorrowedPayload, PrefixedPayload}; +#[cfg(feature = "chacha20poly1305")] pub mod chacha20; pub mod gcm; diff --git a/src/aead/chacha20.rs b/src/aead/chacha20.rs index 995b79e..7096f7f 100644 --- a/src/aead/chacha20.rs +++ b/src/aead/chacha20.rs @@ -3,6 +3,7 @@ use alloc::boxed::Box; use super::{DecryptBufferAdapter, EncryptBufferAdapter}; +#[cfg(feature = "chacha20poly1305")] use chacha20poly1305::{AeadInPlace, KeyInit, KeySizeUser}; use rustls::crypto::cipher::{ self, AeadKey, InboundOpaqueMessage, InboundPlainMessage, Iv, MessageDecrypter, @@ -14,8 +15,12 @@ use rustls::{ConnectionTrafficSecrets, ContentType, ProtocolVersion}; #[cfg(feature = "tls12")] use rustls::crypto::cipher::{KeyBlockShape, Tls12AeadAlgorithm, NONCE_LEN}; + +#[cfg(feature = "chacha20poly1305")] pub struct Chacha20Poly1305; + +#[cfg(feature = "chacha20poly1305")] impl Tls13AeadAlgorithm for Chacha20Poly1305 { fn encrypter(&self, key: AeadKey, iv: Iv) -> Box { Box::new(Tls13Cipher( diff --git a/src/aead/gcm.rs b/src/aead/gcm.rs index 14be62b..4e94570 100644 --- a/src/aead/gcm.rs +++ b/src/aead/gcm.rs @@ -225,11 +225,13 @@ macro_rules! impl_gcm_tls12 { }; } +#[cfg(feature = "aes-gcm")] impl_gcm_tls13! {Aes128Gcm, aes_gcm::Aes128Gcm, 16} +#[cfg(feature = "aes-gcm")] impl_gcm_tls13! {Aes256Gcm, aes_gcm::Aes256Gcm, 16} -#[cfg(feature = "tls12")] +#[cfg(all(feature = "tls12", feature = "aes-gcm"))] impl_gcm_tls12! {Aes128Gcm, aes_gcm::Aes128Gcm, TLS12_GCM_EXPLICIT_NONCE_LEN, TLS12_GCM_OVERHEAD} -#[cfg(feature = "tls12")] +#[cfg(all(feature = "tls12", feature = "aes-gcm"))] impl_gcm_tls12! {Aes256Gcm, aes_gcm::Aes256Gcm, TLS12_GCM_EXPLICIT_NONCE_LEN, TLS12_GCM_OVERHEAD} diff --git a/src/kx.rs b/src/kx.rs index ee7cb09..ec7cb6c 100644 --- a/src/kx.rs +++ b/src/kx.rs @@ -1,9 +1,16 @@ +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +use crypto::{SharedSecret, SupportedKxGroup}; +use paste::paste; +use rustls::crypto; + #[cfg(feature = "x25519")] #[derive(Debug)] pub struct X25519; #[cfg(feature = "x25519")] -impl crypto::SupportedKxGroup for X25519 { +impl SupportedKxGroup for X25519 { fn name(&self) -> rustls::NamedGroup { rustls::NamedGroup::X25519 } @@ -23,7 +30,7 @@ pub struct X25519KeyExchange { #[cfg(feature = "x25519")] impl crypto::ActiveKeyExchange for X25519KeyExchange { - fn complete(self: Box, peer: &[u8]) -> Result { + fn complete(self: Box, peer: &[u8]) -> Result { let peer_array: [u8; 32] = peer .try_into() .map_err(|_| rustls::Error::from(rustls::PeerMisbehaved::InvalidKeyShare))?; @@ -45,7 +52,7 @@ impl crypto::ActiveKeyExchange for X25519KeyExchange { macro_rules! impl_kx { ($name:ident, $kx_name:ty, $secret:ty, $public_key:ty) => { - paste::paste! { + paste! { #[derive(Debug)] #[allow(non_camel_case_types)] @@ -76,7 +83,7 @@ macro_rules! impl_kx { fn complete( self: Box<[<$name KeyExchange>]>, peer: &[u8], - ) -> Result { + ) -> Result { let their_pub = $public_key::from_sec1_bytes(peer) .map_err(|_| rustls::Error::from(rustls::PeerMisbehaved::InvalidKeyShare))?; Ok(self @@ -104,3 +111,11 @@ impl_kx! {SecP256R1, rustls::NamedGroup::secp256r1, p256::ecdh::EphemeralSecret, #[cfg(feature = "p384")] impl_kx! {SecP384R1, rustls::NamedGroup::secp384r1, p384::ecdh::EphemeralSecret, p384::PublicKey} +pub const ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = &[ + #[cfg(feature = "x25519")] + &X25519, + #[cfg(feature = "p256")] + &SecP256R1, + #[cfg(feature = "p384")] + &SecP384R1 +]; \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 016047b..7daad2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,7 +44,7 @@ use alloc::sync::Arc; use rustls::crypto::{ CipherSuiteCommon, CryptoProvider, GetRandomFailed, KeyProvider, SecureRandom, }; -use rustls::{crypto, CipherSuite, SupportedCipherSuite, Tls13CipherSuite}; +use rustls::{CipherSuite, SupportedCipherSuite, Tls13CipherSuite}; #[cfg(feature = "tls12")] use rustls::SignatureScheme; @@ -55,7 +55,7 @@ pub struct Provider; pub fn provider() -> CryptoProvider { CryptoProvider { cipher_suites: ALL_CIPHER_SUITES.to_vec(), - kx_groups: ALL_KX_GROUPS.to_vec(), + kx_groups: kx::ALL_KX_GROUPS.to_vec(), signature_verification_algorithms: verify::ALGORITHMS, secure_random: &Provider, key_provider: &Provider, @@ -81,14 +81,16 @@ impl KeyProvider for Provider { } #[cfg(feature = "tls12")] -const TLS12_ECDSA_SCHEMES: [SignatureScheme; 4] = [ +const TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[ + #[cfg(feature = "p256")] SignatureScheme::ECDSA_NISTP256_SHA256, + #[cfg(feature = "p384")] SignatureScheme::ECDSA_NISTP384_SHA384, - SignatureScheme::ECDSA_NISTP521_SHA512, + #[cfg(feature = "ed25519")] SignatureScheme::ED25519, ]; -#[cfg(feature = "tls12")] +#[cfg(all(feature = "tls12", feature = "rsa"))] const TLS12_RSA_SCHEMES: [SignatureScheme; 6] = [ SignatureScheme::RSA_PKCS1_SHA256, SignatureScheme::RSA_PKCS1_SHA384, @@ -98,7 +100,7 @@ const TLS12_RSA_SCHEMES: [SignatureScheme; 6] = [ SignatureScheme::RSA_PSS_SHA512, ]; -#[cfg(feature = "tls12")] +#[cfg(all(feature = "tls12", feature = "aes-gcm"))] pub const TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite { common: CipherSuiteCommon { @@ -107,12 +109,12 @@ pub const TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = confidentiality_limit: u64::MAX, }, kx: rustls::crypto::KeyExchangeAlgorithm::ECDHE, - sign: &TLS12_ECDSA_SCHEMES, + sign: TLS12_ECDSA_SCHEMES, aead_alg: &aead::gcm::Tls12Aes128Gcm, prf_provider: &rustls::crypto::tls12::PrfUsingHmac(hmac::SHA256), }); -#[cfg(feature = "tls12")] +#[cfg(all(feature = "tls12", feature = "aes-gcm"))] pub const TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite { common: CipherSuiteCommon { @@ -121,12 +123,12 @@ pub const TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = confidentiality_limit: u64::MAX, }, kx: rustls::crypto::KeyExchangeAlgorithm::ECDHE, - sign: &TLS12_ECDSA_SCHEMES, + sign: TLS12_ECDSA_SCHEMES, prf_provider: &rustls::crypto::tls12::PrfUsingHmac(hmac::SHA384), aead_alg: &aead::gcm::Tls12Aes256Gcm, }); -#[cfg(feature = "tls12")] +#[cfg(all(feature = "tls12", feature = "chacha20poly1305"))] pub const TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite { common: CipherSuiteCommon { @@ -136,18 +138,12 @@ pub const TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = }, prf_provider: &rustls::crypto::tls12::PrfUsingHmac(hmac::SHA256), kx: rustls::crypto::KeyExchangeAlgorithm::ECDHE, - sign: &TLS12_ECDSA_SCHEMES, + sign: TLS12_ECDSA_SCHEMES, aead_alg: &aead::chacha20::Chacha20Poly1305, }); -#[cfg(feature = "tls12")] -const TLS_ECDHE_ECDSA_SUITES: &[SupportedCipherSuite] = &[ - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, -]; -#[cfg(feature = "tls12")] +#[cfg(all(feature = "tls12", feature = "aes-gcm", feature = "rsa"))] pub const TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite { common: CipherSuiteCommon { @@ -161,7 +157,7 @@ pub const TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = prf_provider: &rustls::crypto::tls12::PrfUsingHmac(hmac::SHA256), }); -#[cfg(feature = "tls12")] +#[cfg(all(feature = "tls12", feature = "aes-gcm", feature = "ecdsa", feature = "rsa"))] pub const TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite { common: CipherSuiteCommon { @@ -175,7 +171,7 @@ pub const TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = aead_alg: &aead::gcm::Tls12Aes256Gcm, }); -#[cfg(feature = "tls12")] +#[cfg(all(feature = "tls12", feature = "rsa", feature = "chacha20poly1305"))] pub const TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite { common: CipherSuiteCommon { @@ -189,23 +185,26 @@ pub const TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = aead_alg: &aead::chacha20::Chacha20Poly1305, }); -#[cfg(feature = "tls12")] -const TLS_ECDHE_RSA_SUITES: &[SupportedCipherSuite] = &[ +#[cfg(all(feature = "tls12", feature = "ecdsa"))] +const TLS12_SUITES: &[SupportedCipherSuite] = &[ + #[cfg(feature = "aes-gcm")] + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + #[cfg(feature = "aes-gcm")] + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + #[cfg(feature = "chacha20poly1305")] + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + #[cfg(all(feature = "rsa", feature = "aes-gcm"))] TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + #[cfg(all(feature = "rsa", feature = "aes-gcm"))] TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + #[cfg(all(feature = "rsa", feature = "chacha20poly1305"))] TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, ]; -#[cfg(feature = "tls12")] -const TLS12_SUITES: &[SupportedCipherSuite] = misc::const_concat_slices!( - SupportedCipherSuite, - TLS_ECDHE_ECDSA_SUITES, - TLS_ECDHE_RSA_SUITES -); - #[cfg(not(feature = "tls12"))] const TLS12_SUITES: &[SupportedCipherSuite] = &[]; +#[cfg(feature = "aes-gcm")] pub const TLS13_AES_128_GCM_SHA256: SupportedCipherSuite = SupportedCipherSuite::Tls13(&Tls13CipherSuite { common: CipherSuiteCommon { @@ -218,6 +217,7 @@ pub const TLS13_AES_128_GCM_SHA256: SupportedCipherSuite = quic: None, }); +#[cfg(feature = "aes-gcm")] pub const TLS13_AES_256_GCM_SHA384: SupportedCipherSuite = SupportedCipherSuite::Tls13(&Tls13CipherSuite { common: CipherSuiteCommon { @@ -230,9 +230,7 @@ pub const TLS13_AES_256_GCM_SHA384: SupportedCipherSuite = quic: None, }); -const TLS13_AES_SUITES: &[SupportedCipherSuite] = - &[TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384]; - +#[cfg(feature = "chacha20poly1305")] pub const TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = SupportedCipherSuite::Tls13(&Tls13CipherSuite { common: CipherSuiteCommon { @@ -245,11 +243,14 @@ pub const TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = quic: None, }); -const TLS13_SUITES: &[SupportedCipherSuite] = misc::const_concat_slices!( - SupportedCipherSuite, - TLS13_AES_SUITES, - &[TLS13_CHACHA20_POLY1305_SHA256] -); +const TLS13_SUITES: &[SupportedCipherSuite] = &[ + #[cfg(feature = "aes-gcm")] + TLS13_AES_128_GCM_SHA256, + #[cfg(feature = "aes-gcm")] + TLS13_AES_256_GCM_SHA384, + #[cfg(feature = "chacha20poly1305")] + TLS13_CHACHA20_POLY1305_SHA256 +]; static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = misc::const_concat_slices!( SupportedCipherSuite, @@ -272,22 +273,13 @@ pub use verify::eddsa::ED25519; #[cfg(feature = "rsa")] pub use verify::rsa::{RSA_PKCS1_SHA256, RSA_PKCS1_SHA384, RSA_PKCS1_SHA512, RSA_PSS_SHA256, RSA_PSS_SHA384, RSA_PSS_SHA512}; -const ALL_KX_GROUPS: &[&dyn crypto::SupportedKxGroup] = &[ - #[cfg(feature = "x25519")] - &X25519, - #[cfg(feature = "p256")] - &SecP256R1, - #[cfg(feature = "p384")] - &SecP384R1 -]; - mod aead; mod hash; mod hmac; -#[cfg(any(feature = "x25519", feature = "p256", feature = "p384"))] mod kx; mod misc; +#[cfg(feature = "quic")] pub mod quic; pub mod sign; mod verify; diff --git a/src/sign.rs b/src/sign.rs index b28533d..26a6e96 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -84,7 +84,7 @@ pub fn any_supported_type(der: &PrivateKeyDer<'_>) -> Result return Ok(Arc::new(key)); } - #[cfg(any(feature = "p256", feature = "p384"))] + #[cfg(feature = "ecdsa")] if let Ok(key) = any_ecdsa_type(der) { return Ok(key); } @@ -97,7 +97,7 @@ pub fn any_supported_type(der: &PrivateKeyDer<'_>) -> Result Err(rustls::Error::General("unsupported private key format".into())) } -#[cfg(any(feature = "p256", feature = "p384"))] +#[cfg(feature = "ecdsa")] /// Extract any supported ECDSA key from the given DER input. /// /// # Errors @@ -128,7 +128,7 @@ pub fn any_eddsa_type(der: &PrivateKeyDer<'_>) -> Result, ru Ed25519SigningKey::try_from(der).map(|x| Arc::new(x) as _) } -#[cfg(any(feature = "p256", feature = "p384"))] +#[cfg(feature = "ecdsa")] pub mod ecdsa; #[cfg(feature = "ed25519")] pub mod eddsa; diff --git a/src/verify.rs b/src/verify.rs index 92a0289..5559890 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -74,7 +74,7 @@ pub static ALGORITHMS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms { ], }; -#[cfg(any(feature = "p256", feature = "p384"))] +#[cfg(feature = "ecdsa")] pub mod ecdsa; #[cfg(feature = "ed25519")] pub mod eddsa; From 8b42f6b21569d231d7f191b4e83a34330e1bc11a Mon Sep 17 00:00:00 2001 From: Adam Michalik Date: Wed, 1 Oct 2025 22:09:17 -0400 Subject: [PATCH 3/3] . --- .gitignore | 2 +- src/aead/chacha20.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 3e9f0e3..b36a85b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ debug/ target/ **/*.rs.bk *.pdb -.idea/ \ No newline at end of file +.idea/ diff --git a/src/aead/chacha20.rs b/src/aead/chacha20.rs index 7096f7f..c71d947 100644 --- a/src/aead/chacha20.rs +++ b/src/aead/chacha20.rs @@ -15,11 +15,9 @@ use rustls::{ConnectionTrafficSecrets, ContentType, ProtocolVersion}; #[cfg(feature = "tls12")] use rustls::crypto::cipher::{KeyBlockShape, Tls12AeadAlgorithm, NONCE_LEN}; - #[cfg(feature = "chacha20poly1305")] pub struct Chacha20Poly1305; - #[cfg(feature = "chacha20poly1305")] impl Tls13AeadAlgorithm for Chacha20Poly1305 { fn encrypter(&self, key: AeadKey, iv: Iv) -> Box {