From a04c185fb7222f7a3eea68a1b9c5b312cfc2669c Mon Sep 17 00:00:00 2001 From: YX Cao Date: Mon, 27 Nov 2023 17:00:57 -0800 Subject: [PATCH] Upgrade to use rustls 0.22.0-alpha.4 (#12) * build: upgrade to use rustls 0.22.0-alpha.4 * feat: add signer impl - Add crate `rustls-mbedtls-provider-utils` - Add signer impl * feat: add SignatureVerificationAlgorithm * fix: fix tests * test: update test code to fit with mbedtls * fix implementation * fix clippy * test: add more unit tests * test: add more unit tests * ci: turn of CARGO_INCREMENTAL Turn off CARGO_INCREMENTAL to ensure cache & test coverage works correctly. * style: fmt * build: update ws default-members Add rustls-mbedtls-provider-utils to default-members * docs: fix rustdoc * refactor: better prefer order Update `RSA_SIGNATURE_SCHEME_PREFER_LIST` to have a better order. --- .github/workflows/build.yml | 1 + .gitignore | 1 + Cargo.lock | 35 +- Cargo.toml | 9 +- examples/Cargo.toml | 4 +- rustls-mbedcrypto-provider/Cargo.toml | 19 +- .../examples/internal/bench.rs | 34 +- rustls-mbedcrypto-provider/src/hash.rs | 9 + rustls-mbedcrypto-provider/src/kx.rs | 13 +- rustls-mbedcrypto-provider/src/lib.rs | 71 +++- rustls-mbedcrypto-provider/src/sign.rs | 222 ++++++++++++ .../src/signature_verify_algo.rs | 151 +++++++++ rustls-mbedcrypto-provider/src/tls12.rs | 5 +- rustls-mbedcrypto-provider/src/tls13.rs | 4 +- rustls-mbedcrypto-provider/tests/api.rs | 317 +++++++++++------- .../tests/common/mod.rs | 102 ++++-- rustls-mbedpki-provider/Cargo.toml | 5 +- .../src/client_cert_verifier.rs | 31 +- rustls-mbedpki-provider/src/lib.rs | 165 ++------- .../src/server_cert_verifier.rs | 31 +- rustls-mbedpki-provider/src/tests_common.rs | 32 +- rustls-mbedtls-provider-utils/Cargo.toml | 28 ++ rustls-mbedtls-provider-utils/src/error.rs | 109 ++++++ rustls-mbedtls-provider-utils/src/hash.rs | 143 ++++++++ rustls-mbedtls-provider-utils/src/lib.rs | 40 +++ rustls-mbedtls-provider-utils/src/pk.rs | 156 +++++++++ 26 files changed, 1391 insertions(+), 346 deletions(-) create mode 100644 rustls-mbedcrypto-provider/src/sign.rs create mode 100644 rustls-mbedcrypto-provider/src/signature_verify_algo.rs create mode 100644 rustls-mbedtls-provider-utils/Cargo.toml create mode 100644 rustls-mbedtls-provider-utils/src/error.rs create mode 100644 rustls-mbedtls-provider-utils/src/hash.rs create mode 100644 rustls-mbedtls-provider-utils/src/lib.rs create mode 100644 rustls-mbedtls-provider-utils/src/pk.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fed2782..310e179 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,6 +17,7 @@ on: env: CARGO_TERM_COLOR: always CARGO_NET_RETRY: 10 + CARGO_INCREMENTAL: 0 jobs: build: diff --git a/.gitignore b/.gitignore index d26870e..b5e07eb 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ admin/rustfmt **/._.DS_Store /.idea /default.profraw +.cargo/ diff --git a/Cargo.lock b/Cargo.lock index 3a3cedc..cb3b5c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,6 +106,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb" +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -416,7 +422,7 @@ dependencies = [ "rs-libc", "serde", "serde_derive", - "yasna", + "yasna 0.2.2", ] [[package]] @@ -655,7 +661,8 @@ dependencies = [ [[package]] name = "rustls" version = "0.22.0-alpha.4" -source = "git+https://github.com/rustls/rustls?rev=b776a5778ad333653670c34ff9125d8ae59b6047#b776a5778ad333653670c34ff9125d8ae59b6047" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c23376606de66c7b9249d091b59ee55b52df72063e1cae7bb44e0691c9e5150" dependencies = [ "log", "ring", @@ -669,14 +676,17 @@ dependencies = [ name = "rustls-mbedcrypto-provider" version = "0.0.1-alpha.1" dependencies = [ + "bit-vec 0.6.3", "env_logger", "log", "mbedtls", "rustls", + "rustls-mbedtls-provider-utils", "rustls-pemfile 2.0.0-alpha.2", "rustls-pki-types", "rustls-webpki", "webpki-roots", + "yasna 0.3.2", ] [[package]] @@ -686,6 +696,7 @@ dependencies = [ "chrono", "mbedtls", "rustls", + "rustls-mbedtls-provider-utils", "rustls-pemfile 1.0.3", "rustls-pki-types", "x509-parser", @@ -702,6 +713,15 @@ dependencies = [ "rustls-native-certs", ] +[[package]] +name = "rustls-mbedtls-provider-utils" +version = "0.1.0-alpha.1" +dependencies = [ + "mbedtls", + "rustls", + "rustls-pki-types", +] + [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -1140,10 +1160,19 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79af3189e6b0484c9fd54208f8eeb8818cadee00ec81438b67a64c8e6f2f3694" dependencies = [ - "bit-vec", + "bit-vec 0.5.1", "num-bigint 0.2.6", ] +[[package]] +name = "yasna" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de7bff972b4f2a06c85f6d8454b09df153af7e3a4ec2aac81db1b105b684ddb" +dependencies = [ + "bit-vec 0.6.3", +] + [[package]] name = "zeroize" version = "1.6.0" diff --git a/Cargo.toml b/Cargo.toml index 7a370c8..fd64931 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,9 @@ [workspace] -members = ["examples","rustls-mbedcrypto-provider", "rustls-mbedpki-provider"] -default-members = ["rustls-mbedcrypto-provider", "rustls-mbedpki-provider"] +members = [ + "examples", + "rustls-mbedcrypto-provider", + "rustls-mbedpki-provider", + "rustls-mbedtls-provider-utils", +] +default-members = ["rustls-mbedcrypto-provider", "rustls-mbedpki-provider", "rustls-mbedtls-provider-utils"] resolver = "2" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 0402e39..5e54756 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -10,7 +10,5 @@ publish = false rustls-mbedcrypto-provider = { path = "../rustls-mbedcrypto-provider" } rustls-mbedpki-provider = { path = "../rustls-mbedpki-provider" } env_logger = "0.10" -# TODO: upgrade to use formal 0.22.0 or 0.22.0-* versions when availabe -rustls = { git = "https://github.com/rustls/rustls", rev = "b776a5778ad333653670c34ff9125d8ae59b6047", version = "0.22.0-alpha.4", default-features = false } +rustls = { version = "0.22.0-alpha.4", default-features = false } rustls-native-certs = "0.6.3" - diff --git a/rustls-mbedcrypto-provider/Cargo.toml b/rustls-mbedcrypto-provider/Cargo.toml index 435eb00..34f4757 100644 --- a/rustls-mbedcrypto-provider/Cargo.toml +++ b/rustls-mbedcrypto-provider/Cargo.toml @@ -12,12 +12,21 @@ categories = ["network-programming", "cryptography"] resolver = "2" [dependencies] -# TODO: upgrade to use formal 0.22.0 or 0.22.0-* versions when availabe -rustls = { git = "https://github.com/rustls/rustls", rev = "b776a5778ad333653670c34ff9125d8ae59b6047", version = "0.22.0-alpha.4", default-features = false } +rustls = { version = "0.22.0-alpha.4", default-features = false } mbedtls = { version = "0.12.0-alpha.2", default-features = false, features = [ "std", ] } -log = { version = "0.4.20", optional = true } +log = { version = "0.4.4", optional = true } +pki-types = { package = "rustls-pki-types", version = "0.2.1", features = [ + "std", +] } +webpki = { package = "rustls-webpki", version = "0.102.0-alpha.6", features = [ + "alloc", + "std", +], default-features = false } +utils = { package = "rustls-mbedtls-provider-utils", path = "../rustls-mbedtls-provider-utils", version = "0.1.0-alpha.1" } +yasna = { version = "0.3", default-features = false, features = ["bit-vec"] } +bit-vec = "0.6.3" [target.'cfg(target_env = "msvc")'.dependencies] # mbedtls need feature `time` to build when targeting msvc @@ -27,7 +36,7 @@ mbedtls = { version = "0.12.0-alpha.2", default-features = false, features = [ ] } [dev-dependencies] -rustls = { git = "https://github.com/rustls/rustls", rev = "b776a5778ad333653670c34ff9125d8ae59b6047", version = "0.22.0-alpha.4", default-features = false, features = [ +rustls = { version = "0.22.0-alpha.4", default-features = false, features = [ "ring", ] } webpki = { package = "rustls-webpki", version = "0.102.0-alpha.1", default-features = false, features = [ @@ -38,7 +47,7 @@ pki-types = { package = "rustls-pki-types", version = "0.2.0" } webpki-roots = "0.26.0-alpha.2" rustls-pemfile = "=2.0.0-alpha.2" env_logger = "0.10" -log = { version = "0.4.20" } +log = { version = "0.4.4" } [features] default = ["logging", "tls12"] diff --git a/rustls-mbedcrypto-provider/examples/internal/bench.rs b/rustls-mbedcrypto-provider/examples/internal/bench.rs index cd0fde1..02b4164 100644 --- a/rustls-mbedcrypto-provider/examples/internal/bench.rs +++ b/rustls-mbedcrypto-provider/examples/internal/bench.rs @@ -21,7 +21,7 @@ use std::time::{Duration, Instant}; use pki_types::{CertificateDer, PrivateKeyDer}; use rustls::client::Resumption; -use rustls::crypto::ring::Ticketer; +use rustls::crypto::ring::{cipher_suite, Ticketer}; use rustls::server::{NoServerSessionStorage, ServerSessionMemoryCache, WebPkiClientVerifier}; use rustls::RootCertStore; use rustls::{ClientConfig, ClientConnection}; @@ -178,68 +178,60 @@ static ALL_BENCHMARKS: &[BenchmarkParam] = &[ #[cfg(feature = "tls12")] BenchmarkParam::new( KeyType::Rsa, - rustls::cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, &rustls::version::TLS12, ), #[cfg(feature = "tls12")] BenchmarkParam::new( KeyType::Ecdsa, - rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + cipher_suite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, &rustls::version::TLS12, ), #[cfg(feature = "tls12")] BenchmarkParam::new( KeyType::Rsa, - rustls::cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, &rustls::version::TLS12, ), #[cfg(feature = "tls12")] BenchmarkParam::new( KeyType::Rsa, - rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, &rustls::version::TLS12, ), #[cfg(feature = "tls12")] BenchmarkParam::new( KeyType::Rsa, - rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + cipher_suite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, &rustls::version::TLS12, ), #[cfg(feature = "tls12")] BenchmarkParam::new( KeyType::Ecdsa, - rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, &rustls::version::TLS12, ), #[cfg(feature = "tls12")] BenchmarkParam::new( KeyType::Ecdsa, - rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, &rustls::version::TLS12, ), BenchmarkParam::new( KeyType::Rsa, - rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256, - &rustls::version::TLS13, - ), - BenchmarkParam::new( - KeyType::Rsa, - rustls::cipher_suite::TLS13_AES_256_GCM_SHA384, - &rustls::version::TLS13, - ), - BenchmarkParam::new( - KeyType::Rsa, - rustls::cipher_suite::TLS13_AES_128_GCM_SHA256, + cipher_suite::TLS13_CHACHA20_POLY1305_SHA256, &rustls::version::TLS13, ), + BenchmarkParam::new(KeyType::Rsa, cipher_suite::TLS13_AES_256_GCM_SHA384, &rustls::version::TLS13), + BenchmarkParam::new(KeyType::Rsa, cipher_suite::TLS13_AES_128_GCM_SHA256, &rustls::version::TLS13), BenchmarkParam::new( KeyType::Ecdsa, - rustls::cipher_suite::TLS13_AES_128_GCM_SHA256, + cipher_suite::TLS13_AES_128_GCM_SHA256, &rustls::version::TLS13, ), BenchmarkParam::new( KeyType::Ed25519, - rustls::cipher_suite::TLS13_AES_128_GCM_SHA256, + cipher_suite::TLS13_AES_128_GCM_SHA256, &rustls::version::TLS13, ), ]; diff --git a/rustls-mbedcrypto-provider/src/hash.rs b/rustls-mbedcrypto-provider/src/hash.rs index 4b74042..25c15d5 100644 --- a/rustls-mbedcrypto-provider/src/hash.rs +++ b/rustls-mbedcrypto-provider/src/hash.rs @@ -43,6 +43,15 @@ pub(crate) static MBED_SHA_384: Algorithm = Algorithm { output_len: 384 / 8, }; +/// SHA-512 as specified in [FIPS 180-4]. +/// +/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf +pub(crate) static MBED_SHA_512: Algorithm = Algorithm { + hash_algorithm: HashAlgorithm::SHA512, + hash_type: mbedtls::hash::Type::Sha512, + output_len: 512 / 8, +}; + impl hash::Hash for Hash { fn start(&self) -> Box { Box::new(HashContext(MbedHashContext::new(self.0))) diff --git a/rustls-mbedcrypto-provider/src/kx.rs b/rustls-mbedcrypto-provider/src/kx.rs index 6d34fea..dbcd47f 100644 --- a/rustls-mbedcrypto-provider/src/kx.rs +++ b/rustls-mbedcrypto-provider/src/kx.rs @@ -8,7 +8,6 @@ use super::agreement; use crate::error::mbedtls_err_to_rustls_general_error; -use crate::log::error; use alloc::boxed::Box; use alloc::fmt; use alloc::format; @@ -42,15 +41,12 @@ impl fmt::Debug for KxGroup { } impl SupportedKxGroup for KxGroup { - fn start(&self) -> Result, rustls::crypto::GetRandomFailed> { + fn start(&self) -> Result, Error> { let mut pk = PkMbed::generate_ec( &mut super::rng::rng_new().ok_or(rustls::crypto::GetRandomFailed)?, self.agreement_algorithm.group_id, ) - .map_err(|_err| { - error!("Encountered error when generating ec key, mbedtls error: {}", _err); - rustls::crypto::GetRandomFailed - })?; + .map_err(|err| rustls::Error::General(format!("Encountered error when generating ec key, mbedtls error: {}", err)))?; fn get_key_pair(pk: &mut PkMbed, kx_group: &KxGroup) -> Result { let group = EcGroup::new(kx_group.agreement_algorithm.group_id)?; @@ -68,10 +64,7 @@ impl SupportedKxGroup for KxGroup { match get_key_pair(&mut pk, self) { Ok(group) => Ok(Box::new(group)), - Err(_err) => { - error!("Unexpected mbedtls error: {}", _err); - Err(rustls::crypto::GetRandomFailed) - } + Err(err) => Err(rustls::Error::General(format!("Unexpected mbedtls error: {}", err))), } } diff --git a/rustls-mbedcrypto-provider/src/lib.rs b/rustls-mbedcrypto-provider/src/lib.rs index 65733f9..b491c9f 100644 --- a/rustls-mbedcrypto-provider/src/lib.rs +++ b/rustls-mbedcrypto-provider/src/lib.rs @@ -80,14 +80,18 @@ pub(crate) mod hash; pub(crate) mod hmac; pub(crate) mod kx; +/// Message signing interfaces. +pub mod sign; +/// Supported signature verify algorithms +pub mod signature_verify_algo; /// TLS1.2 ciphersuites implementation. #[cfg(feature = "tls12")] -pub mod tls12; +pub(crate) mod tls12; /// TLS1.3 ciphersuites implementation. -pub mod tls13; +pub(crate) mod tls13; use mbedtls::rng::Random; -use rustls::SupportedCipherSuite; +use rustls::{SignatureScheme, SupportedCipherSuite, WebPkiSupportedAlgorithms}; /// RNG supported by *mbedtls* pub mod rng { @@ -137,6 +141,17 @@ impl rustls::crypto::CryptoProvider for Mbedtls { fn default_kx_groups(&self) -> &'static [&'static dyn rustls::crypto::SupportedKxGroup] { ALL_KX_GROUPS } + + fn load_private_key( + &self, + key_der: pki_types::PrivateKeyDer<'static>, + ) -> Result, rustls::Error> { + Ok(alloc::sync::Arc::new(sign::MbedTlsPkSigningKey::new(&key_der)?)) + } + + fn signature_verification_algorithms(&self) -> WebPkiSupportedAlgorithms { + SUPPORTED_SIG_ALGS + } } /// The cipher suite configuration that an application should use by default. @@ -166,6 +181,56 @@ pub static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = &[ tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, ]; +/// All defined cipher suites supported by *mbedtls* appear in this module. +pub mod cipher_suite { + #[cfg(feature = "tls12")] + pub use super::tls12::{ + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + }; + pub use super::tls13::{TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256}; +} + +/// A `WebPkiSupportedAlgorithms` value that reflects pki's capabilities when +/// compiled against *mbedtls*. +static SUPPORTED_SIG_ALGS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms { + all: &[ + signature_verify_algo::ECDSA_P256_SHA256, + signature_verify_algo::ECDSA_P256_SHA384, + signature_verify_algo::ECDSA_P384_SHA256, + signature_verify_algo::ECDSA_P384_SHA384, + signature_verify_algo::RSA_PSS_SHA256, + signature_verify_algo::RSA_PSS_SHA384, + signature_verify_algo::RSA_PSS_SHA512, + signature_verify_algo::RSA_PKCS1_SHA256, + signature_verify_algo::RSA_PKCS1_SHA384, + signature_verify_algo::RSA_PKCS1_SHA512, + ], + mapping: &[ + ( + SignatureScheme::ECDSA_NISTP384_SHA384, + &[ + signature_verify_algo::ECDSA_P384_SHA384, + signature_verify_algo::ECDSA_P256_SHA384, + ], + ), + ( + SignatureScheme::ECDSA_NISTP256_SHA256, + &[ + signature_verify_algo::ECDSA_P256_SHA256, + signature_verify_algo::ECDSA_P384_SHA256, + ], + ), + (SignatureScheme::RSA_PSS_SHA512, &[signature_verify_algo::RSA_PSS_SHA512]), + (SignatureScheme::RSA_PSS_SHA384, &[signature_verify_algo::RSA_PSS_SHA384]), + (SignatureScheme::RSA_PSS_SHA256, &[signature_verify_algo::RSA_PSS_SHA256]), + (SignatureScheme::RSA_PKCS1_SHA512, &[signature_verify_algo::RSA_PKCS1_SHA512]), + (SignatureScheme::RSA_PKCS1_SHA384, &[signature_verify_algo::RSA_PKCS1_SHA384]), + (SignatureScheme::RSA_PKCS1_SHA256, &[signature_verify_algo::RSA_PKCS1_SHA256]), + ], +}; + /// All defined key exchange groups supported by *mbedtls* appear in this module. /// /// [`ALL_KX_GROUPS`] is provided as an array of all of these values. diff --git a/rustls-mbedcrypto-provider/src/sign.rs b/rustls-mbedcrypto-provider/src/sign.rs new file mode 100644 index 0000000..467be2e --- /dev/null +++ b/rustls-mbedcrypto-provider/src/sign.rs @@ -0,0 +1,222 @@ +use alloc::string::String; +use alloc::vec; +use alloc::{boxed::Box, sync::Arc, vec::Vec}; +use core::fmt::Debug; +use mbedtls::pk::{EcGroupId, ECDSA_MAX_LEN}; +use rustls::SignatureScheme; +use std::sync::Mutex; +use utils::error::mbedtls_err_into_rustls_err; +use utils::hash::{buffer_for_hash_type, rustls_signature_scheme_to_mbedtls_hash_type}; +use utils::pk::rustls_signature_scheme_to_mbedtls_pk_options; + +struct MbedTlsSigner(Arc>, SignatureScheme); + +impl Debug for MbedTlsSigner { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("MbedTlsSigner") + .field(&"Arc>") + .field(&self.1) + .finish() + } +} + +impl rustls::sign::Signer for MbedTlsSigner { + fn sign(&self, message: &[u8]) -> Result, rustls::Error> { + let hash_type = rustls_signature_scheme_to_mbedtls_hash_type(self.1); + let mut hash = buffer_for_hash_type(hash_type).ok_or_else(|| rustls::Error::General("unexpected hash type".into()))?; + let hash_size = mbedtls::hash::Md::hash(hash_type, message, &mut hash).map_err(mbedtls_err_into_rustls_err)?; + + let mut pk = self + .0 + .lock() + .expect("poisoned PK lock!"); + if let Some(opts) = rustls_signature_scheme_to_mbedtls_pk_options(self.1) { + pk.set_options(opts); + } + + fn sig_len_for_pk(pk: &mbedtls::pk::Pk) -> usize { + match pk.pk_type() { + mbedtls::pk::Type::Eckey | mbedtls::pk::Type::EckeyDh | mbedtls::pk::Type::Ecdsa => ECDSA_MAX_LEN, + _ => pk.len() / 8, + } + } + let mut sig = vec![0; sig_len_for_pk(&pk)]; + let sig_len = pk + .sign( + hash_type, + &hash[..hash_size], + &mut sig, + &mut crate::rng::rng_new().ok_or(rustls::Error::FailedToGetRandomBytes)?, + ) + .map_err(mbedtls_err_into_rustls_err)?; + sig.truncate(sig_len); + Ok(sig) + } + + fn scheme(&self) -> SignatureScheme { + self.1 + } +} + +/// A [`SigningKey`] implemented by using [`mbedtls`] +/// +/// [`SigningKey`]: rustls::sign::SigningKey +pub struct MbedTlsPkSigningKey { + pk: Arc>, + pk_type: mbedtls::pk::Type, + signature_algorithm: rustls::SignatureAlgorithm, + ec_signature_scheme: Option, +} + +impl Debug for MbedTlsPkSigningKey { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("MbedTlsPkSigningKey") + .field("pk", &"Arc>") + .field("pk_type", &self.pk_type) + .field("signature_algorithm", &self.signature_algorithm) + .field("ec_signature_scheme", &self.ec_signature_scheme) + .finish() + } +} + +impl MbedTlsPkSigningKey { + /// Make a new `MbedTlsPkSigningKey` from a DER encoding. + pub fn new(der: &pki_types::PrivateKeyDer<'_>) -> Result { + let pk = mbedtls::pk::Pk::from_private_key(der.secret_der(), None) + .map_err(|err| rustls::Error::Other(rustls::OtherError(alloc::sync::Arc::new(err))))?; + let pk_type = pk.pk_type(); + let signature_algorithm = pk_type_to_signature_algo(pk_type); + let ec_signature_scheme = if signature_algorithm == rustls::SignatureAlgorithm::ECDSA { + Some( + match pk + .curve() + .map_err(|err| rustls::Error::Other(rustls::OtherError(alloc::sync::Arc::new(err))))? + { + EcGroupId::SecP256R1 => SignatureScheme::ECDSA_NISTP256_SHA256, + EcGroupId::SecP384R1 => SignatureScheme::ECDSA_NISTP384_SHA384, + EcGroupId::SecP521R1 => SignatureScheme::ECDSA_NISTP521_SHA512, + _ => { + return Err(rustls::Error::General(String::from( + "MbedTlsPkSigningKey: unsupported ec curve", + ))) + } + }, + ) + } else { + None + }; + Ok(Self { + pk: alloc::sync::Arc::new(std::sync::Mutex::new(pk)), + pk_type, + signature_algorithm, + ec_signature_scheme, + }) + } +} + +const RSA_SIGNATURE_SCHEME_PREFER_LIST: &[SignatureScheme] = &[ + SignatureScheme::RSA_PSS_SHA512, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA256, + SignatureScheme::RSA_PKCS1_SHA512, + SignatureScheme::RSA_PKCS1_SHA384, + SignatureScheme::RSA_PKCS1_SHA256, +]; + +impl rustls::sign::SigningKey for MbedTlsPkSigningKey { + fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option> { + match self.pk_type { + mbedtls::pk::Type::Rsa | mbedtls::pk::Type::RsaAlt | mbedtls::pk::Type::RsassaPss => { + // choose a rsa schema + for scheme in RSA_SIGNATURE_SCHEME_PREFER_LIST { + if offered.contains(scheme) { + let signer = MbedTlsSigner(Arc::clone(&self.pk), *scheme); + return Some(Box::new(signer)); + } + } + None + } + mbedtls::pk::Type::Eckey | mbedtls::pk::Type::EckeyDh | mbedtls::pk::Type::Ecdsa => { + let scheme = self + .ec_signature_scheme + .expect("validated"); + if offered.contains(&scheme) { + let signer = MbedTlsSigner(Arc::clone(&self.pk), scheme); + return Some(Box::new(signer)); + } + None + } + _ => None, + } + } + + fn algorithm(&self) -> rustls::SignatureAlgorithm { + self.signature_algorithm + } +} + +fn pk_type_to_signature_algo(pk_type: mbedtls::pk::Type) -> rustls::SignatureAlgorithm { + use rustls::SignatureAlgorithm; + match pk_type { + mbedtls::pk::Type::Rsa => SignatureAlgorithm::RSA, + mbedtls::pk::Type::Ecdsa => SignatureAlgorithm::ECDSA, + mbedtls::pk::Type::RsassaPss => SignatureAlgorithm::RSA, + mbedtls::pk::Type::RsaAlt => SignatureAlgorithm::RSA, + mbedtls::pk::Type::Eckey => SignatureAlgorithm::ECDSA, + mbedtls::pk::Type::EckeyDh => SignatureAlgorithm::Unknown(255), + mbedtls::pk::Type::Custom => SignatureAlgorithm::Unknown(255), + mbedtls::pk::Type::None => SignatureAlgorithm::Unknown(255), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rustls::{sign::SigningKey, SignatureAlgorithm}; + + #[test] + fn test_signing_key() { + let ec_key_pem = include_str!("../../test-ca/ecdsa/end.key"); + let der: pki_types::PrivateKeyDer<'static> = + rustls_pemfile::pkcs8_private_keys(&mut std::io::BufReader::new(ec_key_pem.as_bytes())) + .next() + .unwrap() + .unwrap() + .into(); + let key = MbedTlsPkSigningKey::new(&der).unwrap(); + assert_eq!("MbedTlsPkSigningKey { pk: \"Arc>\", pk_type: Eckey, signature_algorithm: ECDSA, ec_signature_scheme: Some(ECDSA_NISTP256_SHA256) }", format!("{:?}", key)); + assert!(key + .choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA1]) + .is_none()); + let res = key.choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256]); + assert!(res.is_some()); + assert_eq!( + "Some(MbedTlsSigner(\"Arc>\", ECDSA_NISTP256_SHA256))", + format!("{:?}", res) + ); + } + + #[test] + fn test_pk_type_to_signature_algo() { + assert_eq!(pk_type_to_signature_algo(mbedtls::pk::Type::Rsa), SignatureAlgorithm::RSA); + assert_eq!(pk_type_to_signature_algo(mbedtls::pk::Type::Ecdsa), SignatureAlgorithm::ECDSA); + assert_eq!( + pk_type_to_signature_algo(mbedtls::pk::Type::RsassaPss), + SignatureAlgorithm::RSA + ); + assert_eq!(pk_type_to_signature_algo(mbedtls::pk::Type::RsaAlt), SignatureAlgorithm::RSA); + assert_eq!(pk_type_to_signature_algo(mbedtls::pk::Type::Eckey), SignatureAlgorithm::ECDSA); + assert_eq!( + pk_type_to_signature_algo(mbedtls::pk::Type::EckeyDh), + SignatureAlgorithm::Unknown(255) + ); + assert_eq!( + pk_type_to_signature_algo(mbedtls::pk::Type::Custom), + SignatureAlgorithm::Unknown(255) + ); + assert_eq!( + pk_type_to_signature_algo(mbedtls::pk::Type::None), + SignatureAlgorithm::Unknown(255) + ); + } +} diff --git a/rustls-mbedcrypto-provider/src/signature_verify_algo.rs b/rustls-mbedcrypto-provider/src/signature_verify_algo.rs new file mode 100644 index 0000000..c7f5922 --- /dev/null +++ b/rustls-mbedcrypto-provider/src/signature_verify_algo.rs @@ -0,0 +1,151 @@ +use super::hash::Algorithm as HashAlgorithm; +use alloc::vec; +use mbedtls::pk::{EcGroupId, Pk}; +use pki_types::{AlgorithmIdentifier, InvalidSignature, SignatureVerificationAlgorithm}; +use rustls::SignatureScheme; +use webpki::alg_id; + +/// ECDSA signatures using the P-256 curve and SHA-256. +pub static ECDSA_P256_SHA256: &Algorithm = &Algorithm { + signature_scheme: SignatureScheme::ECDSA_NISTP256_SHA256, + hash_algo: &super::hash::MBED_SHA_256, + public_key_alg_id: alg_id::ECDSA_P256, + ec_group_id: Some(EcGroupId::SecP256R1), + signature_alg_id: alg_id::ECDSA_SHA256, +}; +/// ECDSA signatures using the P-384 curve and SHA-256. +pub static ECDSA_P384_SHA256: &Algorithm = &Algorithm { + signature_scheme: SignatureScheme::ECDSA_NISTP256_SHA256, + hash_algo: &super::hash::MBED_SHA_256, + public_key_alg_id: alg_id::ECDSA_P384, + ec_group_id: Some(EcGroupId::SecP384R1), + signature_alg_id: alg_id::ECDSA_SHA256, +}; +/// ECDSA signatures using the P-384 curve and SHA-384. +pub static ECDSA_P384_SHA384: &Algorithm = &Algorithm { + signature_scheme: SignatureScheme::ECDSA_NISTP384_SHA384, + hash_algo: &super::hash::MBED_SHA_384, + public_key_alg_id: alg_id::ECDSA_P384, + ec_group_id: Some(EcGroupId::SecP384R1), + signature_alg_id: alg_id::ECDSA_SHA384, +}; +/// ECDSA signatures using the P-256 curve and SHA-384. +pub static ECDSA_P256_SHA384: &Algorithm = &Algorithm { + signature_scheme: SignatureScheme::ECDSA_NISTP384_SHA384, + hash_algo: &super::hash::MBED_SHA_384, + public_key_alg_id: alg_id::ECDSA_P256, + ec_group_id: Some(EcGroupId::SecP256R1), + signature_alg_id: alg_id::ECDSA_SHA384, +}; +/// RSA PKCS#1 1.5 signatures using SHA-256. +pub static RSA_PKCS1_SHA256: &Algorithm = &Algorithm { + signature_scheme: SignatureScheme::RSA_PKCS1_SHA256, + hash_algo: &super::hash::MBED_SHA_256, + public_key_alg_id: alg_id::RSA_ENCRYPTION, + ec_group_id: None, + signature_alg_id: alg_id::RSA_PKCS1_SHA256, +}; +/// RSA PKCS#1 1.5 signatures using SHA-384. +pub static RSA_PKCS1_SHA384: &Algorithm = &Algorithm { + signature_scheme: SignatureScheme::RSA_PKCS1_SHA384, + hash_algo: &super::hash::MBED_SHA_384, + public_key_alg_id: alg_id::RSA_ENCRYPTION, + ec_group_id: None, + signature_alg_id: alg_id::RSA_PKCS1_SHA384, +}; +/// RSA PKCS#1 1.5 signatures using SHA-512. +pub static RSA_PKCS1_SHA512: &Algorithm = &Algorithm { + signature_scheme: SignatureScheme::RSA_PKCS1_SHA512, + hash_algo: &super::hash::MBED_SHA_512, + public_key_alg_id: alg_id::RSA_ENCRYPTION, + ec_group_id: None, + signature_alg_id: alg_id::RSA_PKCS1_SHA512, +}; +/// RSA PSS signatures using SHA-256 and of +/// type rsaEncryption; see [RFC 4055 Section 1.2]. +/// +/// [RFC 4055 Section 1.2]: https://tools.ietf.org/html/rfc4055#section-1.2 +pub static RSA_PSS_SHA256: &Algorithm = &Algorithm { + signature_scheme: SignatureScheme::RSA_PSS_SHA256, + hash_algo: &super::hash::MBED_SHA_256, + public_key_alg_id: alg_id::RSA_ENCRYPTION, + ec_group_id: None, + signature_alg_id: alg_id::RSA_PSS_SHA256, +}; +/// RSA PSS signatures using SHA-384 and of +/// type rsaEncryption; see [RFC 4055 Section 1.2]. +/// +/// [RFC 4055 Section 1.2]: https://tools.ietf.org/html/rfc4055#section-1.2 +pub static RSA_PSS_SHA384: &Algorithm = &Algorithm { + signature_scheme: SignatureScheme::RSA_PSS_SHA384, + hash_algo: &super::hash::MBED_SHA_384, + public_key_alg_id: alg_id::RSA_ENCRYPTION, + ec_group_id: None, + signature_alg_id: alg_id::RSA_PSS_SHA384, +}; +/// RSA PSS signatures using SHA-512 and of +/// type rsaEncryption; see [RFC 4055 Section 1.2]. +/// +/// [RFC 4055 Section 1.2]: https://tools.ietf.org/html/rfc4055#section-1.2 +pub static RSA_PSS_SHA512: &Algorithm = &Algorithm { + signature_scheme: SignatureScheme::RSA_PSS_SHA512, + hash_algo: &super::hash::MBED_SHA_512, + public_key_alg_id: alg_id::RSA_ENCRYPTION, + ec_group_id: None, + signature_alg_id: alg_id::RSA_PSS_SHA512, +}; + +/// A signature verify algorithm type +#[derive(Clone, Debug, PartialEq)] +pub struct Algorithm { + signature_scheme: SignatureScheme, + hash_algo: &'static HashAlgorithm, + public_key_alg_id: AlgorithmIdentifier, + ec_group_id: Option, + signature_alg_id: AlgorithmIdentifier, +} + +impl SignatureVerificationAlgorithm for Algorithm { + fn verify_signature(&self, public_key: &[u8], message: &[u8], signature: &[u8]) -> Result<(), InvalidSignature> { + let mut pk = match self.ec_group_id { + None => Pk::from_public_key(public_key).map_err(|_| InvalidSignature)?, + Some(ec_group_id) => { + let spki = yasna::construct_der(|writer| { + writer.write_sequence(|writer| { + writer.next().write_sequence(|w| { + w.next() + .write_der(&self.public_key_alg_id) + }); + writer + .next() + .write_bitvec(&bit_vec::BitVec::from_bytes(public_key)); + }) + }); + let ec_pk = Pk::from_public_key(&spki).map_err(|_| InvalidSignature)?; + let curves_match = ec_pk + .curve() + .is_ok_and(|pk_curve| pk_curve == ec_group_id); + if !curves_match { + return Err(InvalidSignature); + }; + ec_pk + } + }; + + if let Some(opts) = utils::pk::rustls_signature_scheme_to_mbedtls_pk_options(self.signature_scheme) { + pk.set_options(opts); + } + let mut hash = vec![0u8; self.hash_algo.output_len]; + mbedtls::hash::Md::hash(self.hash_algo.hash_type, message, &mut hash).map_err(|_| InvalidSignature)?; + pk.verify(self.hash_algo.hash_type, &hash, signature) + .map_err(|_| InvalidSignature) + } + + fn public_key_alg_id(&self) -> AlgorithmIdentifier { + self.public_key_alg_id + } + + fn signature_alg_id(&self) -> AlgorithmIdentifier { + self.signature_alg_id + } +} diff --git a/rustls-mbedcrypto-provider/src/tls12.rs b/rustls-mbedcrypto-provider/src/tls12.rs index 8980e95..781c699 100644 --- a/rustls-mbedcrypto-provider/src/tls12.rs +++ b/rustls-mbedcrypto-provider/src/tls12.rs @@ -10,7 +10,6 @@ use alloc::boxed::Box; use alloc::vec::Vec; use mbedtls::cipher::raw::{CipherId, CipherMode, CipherType}; use mbedtls::cipher::{Authenticated, Cipher, Decryption, Encryption, Fresh}; -use rustls::cipher_suite::CipherSuiteCommon; use rustls::crypto::cipher::{ make_tls12_aad, AeadKey, BorrowedPlainMessage, Iv, KeyBlockShape, MessageDecrypter, MessageEncrypter, Nonce, OpaqueMessage, PlainMessage, Tls12AeadAlgorithm, UnsupportedOperationError, NONCE_LEN, @@ -20,7 +19,9 @@ use rustls::crypto::KeyExchangeAlgorithm; use super::aead::{self, Algorithm, AES128_GCM, AES256_GCM}; use alloc::string::String; -use rustls::{CipherSuite, ConnectionTrafficSecrets, Error, SignatureScheme, SupportedCipherSuite, Tls12CipherSuite}; +use rustls::{ + CipherSuite, CipherSuiteCommon, ConnectionTrafficSecrets, Error, SignatureScheme, SupportedCipherSuite, Tls12CipherSuite, +}; pub(crate) const GCM_FIXED_IV_LEN: usize = 4; pub(crate) const GCM_EXPLICIT_NONCE_LEN: usize = 8; diff --git a/rustls-mbedcrypto-provider/src/tls13.rs b/rustls-mbedcrypto-provider/src/tls13.rs index 23137c1..a008f85 100644 --- a/rustls-mbedcrypto-provider/src/tls13.rs +++ b/rustls-mbedcrypto-provider/src/tls13.rs @@ -12,7 +12,6 @@ use alloc::string::String; use alloc::vec::Vec; use mbedtls::cipher::raw::CipherType; use mbedtls::cipher::{Authenticated, Cipher, Decryption, Encryption, Fresh}; -use rustls::cipher_suite::CipherSuiteCommon; use rustls::crypto::cipher::{ make_tls13_aad, AeadKey, BorrowedPlainMessage, Iv, MessageDecrypter, MessageEncrypter, Nonce, OpaqueMessage, PlainMessage, Tls13AeadAlgorithm, UnsupportedOperationError, @@ -20,7 +19,8 @@ use rustls::crypto::cipher::{ use rustls::crypto::tls13::HkdfUsingHmac; use rustls::internal::msgs::codec::Codec; use rustls::{ - CipherSuite, ConnectionTrafficSecrets, ContentType, Error, ProtocolVersion, SupportedCipherSuite, Tls13CipherSuite, + CipherSuite, CipherSuiteCommon, ConnectionTrafficSecrets, ContentType, Error, ProtocolVersion, SupportedCipherSuite, + Tls13CipherSuite, }; /// The TLS1.3 ciphersuite TLS_CHACHA20_POLY1305_SHA256 diff --git a/rustls-mbedcrypto-provider/tests/api.rs b/rustls-mbedcrypto-provider/tests/api.rs index 58c7c89..84074ee 100644 --- a/rustls-mbedcrypto-provider/tests/api.rs +++ b/rustls-mbedcrypto-provider/tests/api.rs @@ -5,9 +5,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#![cfg_attr(read_buf, feature(read_buf))] +#![cfg_attr(read_buf, feature(core_io_borrowed_buf))] //! Assorted public API tests. +use core::fmt; +use core::fmt::Debug; use std::cell::RefCell; -use std::fmt; use std::io::{self, IoSlice, Read, Write}; use std::mem; use std::ops::{Deref, DerefMut}; @@ -15,22 +18,26 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use std::sync::Mutex; -use pki_types::{CertificateDer, UnixTime}; -use rustls::client::{verify_server_cert_signed_by_trust_anchor, ResolvesClientCert, Resumption, WebPkiServerVerifier}; -use rustls::internal::msgs::{ - base::Payload, - codec::Codec, - enums::AlertLevel, - handshake::{ClientExtension, HandshakePayload}, - message::{Message, MessagePayload, PlainMessage}, -}; -use rustls::server::{ClientHello, ParsedCertificate, ResolvesServerCert, WebPkiClientVerifier}; +use pki_types::{CertificateDer, PrivateKeyDer, UnixTime}; +use primary_provider::cipher_suite; +use primary_provider::sign::MbedTlsPkSigningKey as RsaSigningKey; +use rustls::client::{verify_server_cert_signed_by_trust_anchor, ResolvesClientCert, Resumption}; +use rustls::internal::msgs::base::Payload; +use rustls::internal::msgs::codec::Codec; +use rustls::internal::msgs::enums::AlertLevel; +use rustls::internal::msgs::handshake::{ClientExtension, HandshakePayload}; +use rustls::internal::msgs::message::{Message, MessagePayload, PlainMessage}; +use rustls::server::{ClientHello, ParsedCertificate, ResolvesServerCert}; +use rustls::DistinguishedName; +use rustls::SupportedCipherSuite; use rustls::{ - sign, AlertDescription, CertificateError, CipherSuite, ClientConfig, ClientConnection, ConnectionCommon, ContentType, - DistinguishedName, Error, KeyLog, PeerIncompatible, PeerMisbehaved, ProtocolVersion, ServerConfig, ServerConnection, - SideData, SignatureScheme, Stream, StreamOwned, SupportedCipherSuite, + sign, AlertDescription, CertificateError, ConnectionCommon, ContentType, Error, KeyLog, PeerIncompatible, PeerMisbehaved, + SideData, }; -use rustls_mbedcrypto_provider::ALL_CIPHER_SUITES; +use rustls::{CipherSuite, ProtocolVersion, SignatureScheme}; +use rustls::{ClientConfig, ClientConnection}; +use rustls::{ServerConfig, ServerConnection}; +use rustls::{Stream, StreamOwned}; mod common; use crate::common::*; @@ -187,7 +194,8 @@ fn check_read_err(reader: &mut dyn io::Read, err_kind: io::ErrorKind) { #[cfg(read_buf)] fn check_read_buf(reader: &mut dyn io::Read, bytes: &[u8]) { - use std::{io::BorrowedBuf, mem::MaybeUninit}; + use core::io::BorrowedBuf; + use std::mem::MaybeUninit; let mut buf = [MaybeUninit::::uninit(); 128]; let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); @@ -197,7 +205,8 @@ fn check_read_buf(reader: &mut dyn io::Read, bytes: &[u8]) { #[cfg(read_buf)] fn check_read_buf_err(reader: &mut dyn io::Read, err_kind: io::ErrorKind) { - use std::{io::BorrowedBuf, mem::MaybeUninit}; + use core::io::BorrowedBuf; + use std::mem::MaybeUninit; let mut buf = [MaybeUninit::::uninit(); 1]; let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); @@ -210,7 +219,7 @@ fn check_read_buf_err(reader: &mut dyn io::Read, err_kind: io::ErrorKind) { #[test] fn config_builder_for_client_rejects_empty_kx_groups() { assert_eq!( - ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + client_config_builder() .with_safe_default_cipher_suites() .with_kx_groups(&[]) .with_safe_default_protocol_versions() @@ -222,7 +231,7 @@ fn config_builder_for_client_rejects_empty_kx_groups() { #[test] fn config_builder_for_client_rejects_empty_cipher_suites() { assert_eq!( - ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + client_config_builder() .with_cipher_suites(&[]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() @@ -235,8 +244,8 @@ fn config_builder_for_client_rejects_empty_cipher_suites() { #[test] fn config_builder_for_client_rejects_incompatible_cipher_suites() { assert_eq!( - ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) - .with_cipher_suites(&[rustls_mbedcrypto_provider::tls13::TLS13_AES_256_GCM_SHA384]) + client_config_builder() + .with_cipher_suites(&[cipher_suite::TLS13_AES_256_GCM_SHA384]) .with_safe_default_kx_groups() .with_protocol_versions(&[&rustls::version::TLS12]) .err(), @@ -247,7 +256,7 @@ fn config_builder_for_client_rejects_incompatible_cipher_suites() { #[test] fn config_builder_for_server_rejects_empty_kx_groups() { assert_eq!( - ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + server_config_builder() .with_safe_default_cipher_suites() .with_kx_groups(&[]) .with_safe_default_protocol_versions() @@ -259,7 +268,7 @@ fn config_builder_for_server_rejects_empty_kx_groups() { #[test] fn config_builder_for_server_rejects_empty_cipher_suites() { assert_eq!( - ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + server_config_builder() .with_cipher_suites(&[]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() @@ -272,8 +281,8 @@ fn config_builder_for_server_rejects_empty_cipher_suites() { #[test] fn config_builder_for_server_rejects_incompatible_cipher_suites() { assert_eq!( - ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) - .with_cipher_suites(&[rustls_mbedcrypto_provider::tls13::TLS13_AES_256_GCM_SHA384]) + server_config_builder() + .with_cipher_suites(&[cipher_suite::TLS13_AES_256_GCM_SHA384]) .with_safe_default_kx_groups() .with_protocol_versions(&[&rustls::version::TLS12]) .err(), @@ -424,30 +433,63 @@ fn server_can_get_client_cert_after_resumption() { } #[test] +#[cfg(feature = "ring")] fn test_config_builders_debug() { - let b = ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS); + let b = server_config_builder(); + assert_eq!( + "ConfigBuilder { state: WantsCipherSuites(Ring) }", + format!("{:?}", b) + ); + let b = b.with_cipher_suites(&[cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]); + assert_eq!("ConfigBuilder { state: WantsKxGroups { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], provider: Ring } }", format!("{:?}", b)); + let b = b.with_kx_groups(&[primary_provider::kx_group::X25519]); + assert_eq!("ConfigBuilder { state: WantsVersions { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], provider: Ring } }", format!("{:?}", b)); + let b = b + .with_protocol_versions(&[&rustls::version::TLS13]) + .unwrap(); + let b = b.with_no_client_auth(); + assert_eq!("ConfigBuilder { state: WantsServerCert { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], provider: Ring, versions: [TLSv1_3], verifier: NoClientAuth } }", format!("{:?}", b)); + + let b = client_config_builder(); + assert_eq!( + "ConfigBuilder { state: WantsCipherSuites(Ring) }", + format!("{:?}", b) + ); + let b = b.with_cipher_suites(&[cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]); + assert_eq!("ConfigBuilder { state: WantsKxGroups { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], provider: Ring } }", format!("{:?}", b)); + let b = b.with_kx_groups(&[primary_provider::kx_group::X25519]); + assert_eq!("ConfigBuilder { state: WantsVersions { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], provider: Ring } }", format!("{:?}", b)); + let b = b + .with_protocol_versions(&[&rustls::version::TLS13]) + .unwrap(); + assert_eq!("ConfigBuilder { state: WantsVerifier { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], provider: Ring, versions: [TLSv1_3] } }", format!("{:?}", b)); +} + +#[test] +fn test_config_builders_debug_mbedtls() { + let b = server_config_builder(); assert_eq!( "ConfigBuilder { state: WantsCipherSuites(Mbedtls) }", format!("{:?}", b) ); - let b = b.with_cipher_suites(&[rustls_mbedcrypto_provider::tls13::TLS13_CHACHA20_POLY1305_SHA256]); + let b = b.with_cipher_suites(&[cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]); assert_eq!("ConfigBuilder { state: WantsKxGroups { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], provider: Mbedtls } }", format!("{:?}", b)); - let b = b.with_kx_groups(&[rustls_mbedcrypto_provider::kx_group::X25519]); + let b = b.with_kx_groups(&[primary_provider::kx_group::X25519]); assert_eq!("ConfigBuilder { state: WantsVersions { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], provider: Mbedtls } }", format!("{:?}", b)); let b = b .with_protocol_versions(&[&rustls::version::TLS13]) .unwrap(); let b = b.with_no_client_auth(); - assert_eq!("ConfigBuilder { state: WantsServerCert { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], provider: Mbedtls, versions: [TLSv1_3], verifier: dyn ClientCertVerifier } }", format!("{:?}", b)); + assert_eq!("ConfigBuilder { state: WantsServerCert { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], provider: Mbedtls, versions: [TLSv1_3], verifier: NoClientAuth } }", format!("{:?}", b)); - let b = ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS); + let b = client_config_builder(); assert_eq!( "ConfigBuilder { state: WantsCipherSuites(Mbedtls) }", format!("{:?}", b) ); - let b = b.with_cipher_suites(&[rustls_mbedcrypto_provider::tls13::TLS13_CHACHA20_POLY1305_SHA256]); + let b = b.with_cipher_suites(&[cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]); assert_eq!("ConfigBuilder { state: WantsKxGroups { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], provider: Mbedtls } }", format!("{:?}", b)); - let b = b.with_kx_groups(&[rustls_mbedcrypto_provider::kx_group::X25519]); + let b = b.with_kx_groups(&[primary_provider::kx_group::X25519]); assert_eq!("ConfigBuilder { state: WantsVersions { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], provider: Mbedtls } }", format!("{:?}", b)); let b = b .with_protocol_versions(&[&rustls::version::TLS13]) @@ -464,12 +506,12 @@ fn server_allow_any_anonymous_or_authenticated_client() { let kt = KeyType::Rsa; for client_cert_chain in [None, Some(kt.get_client_chain())].iter() { let client_auth_roots = get_client_root_store(kt); - let client_auth = WebPkiClientVerifier::builder(client_auth_roots.clone()) + let client_auth = webpki_client_verifier_builder(client_auth_roots.clone()) .allow_unauthenticated() .build() .unwrap(); - let server_config = ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + let server_config = server_config_builder() .with_safe_defaults() .with_client_cert_verifier(client_auth) .with_single_cert(kt.get_chain(), kt.get_key()) @@ -730,7 +772,7 @@ fn test_tls13_late_plaintext_alert() { assert_eq!(server.process_new_packets(), Err(Error::DecryptError)); } -#[derive(Default)] +#[derive(Default, Debug)] struct ServerCheckCertResolve { expected_sni: Option, expected_sigalgs: Option>, @@ -848,7 +890,7 @@ fn client_trims_terminating_dot() { fn check_sigalgs_reduced_by_ciphersuite(kt: KeyType, suite: CipherSuite, expected_sigalgs: Vec) { let client_config = finish_client_config( kt, - ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + client_config_builder() .with_cipher_suites(&[find_suite(suite)]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() @@ -896,11 +938,13 @@ fn server_cert_resolve_reduces_sigalgs_for_ecdsa_ciphersuite() { vec![ SignatureScheme::ECDSA_NISTP384_SHA384, SignatureScheme::ECDSA_NISTP256_SHA256, - SignatureScheme::ED25519, + // mbedtls does not support ED25519 + // SignatureScheme::ED25519, ], ); } +#[derive(Debug)] struct ServerCheckNoSni {} impl ResolvesServerCert for ServerCheckNoSni { @@ -1008,7 +1052,7 @@ fn client_check_server_certificate_ee_revoked() { // Setup a server verifier that will check the EE certificate's revocation status. let crls = vec![kt.end_entity_crl()]; - let builder = WebPkiServerVerifier::builder(get_client_root_store(*kt)) + let builder = webpki_server_verifier_builder(get_client_root_store(*kt)) .with_crls(crls) .only_check_end_entity_revocation(); @@ -1036,12 +1080,12 @@ fn client_check_server_certificate_ee_unknown_revocation() { // allow unknown revocation status (the default). We'll provide CRLs that are not relevant // to the EE cert to ensure its status is unknown. let unrelated_crls = vec![kt.intermediate_crl()]; - let forbid_unknown_verifier = WebPkiServerVerifier::builder(get_client_root_store(*kt)) + let forbid_unknown_verifier = webpki_server_verifier_builder(get_client_root_store(*kt)) .with_crls(unrelated_crls.clone()) .only_check_end_entity_revocation(); // Also set up a verifier builder that will allow unknown revocation status. - let allow_unknown_verifier = WebPkiServerVerifier::builder(get_client_root_store(*kt)) + let allow_unknown_verifier = webpki_server_verifier_builder(get_client_root_store(*kt)) .with_crls(unrelated_crls) .only_check_end_entity_revocation() .allow_unknown_revocation_status(); @@ -1080,13 +1124,13 @@ fn client_check_server_certificate_intermediate_revoked() { // that marks the intermediate certificate as revoked. We allow unknown revocation status // so the EE cert's unknown status doesn't cause an error. let crls = vec![kt.intermediate_crl()]; - let full_chain_verifier_builder = WebPkiServerVerifier::builder(get_client_root_store(*kt)) + let full_chain_verifier_builder = webpki_server_verifier_builder(get_client_root_store(*kt)) .with_crls(crls.clone()) .allow_unknown_revocation_status(); // Also set up a verifier builder that will use the same CRL, but only check the EE certificate // revocation status. - let ee_verifier_builder = WebPkiServerVerifier::builder(get_client_root_store(*kt)) + let ee_verifier_builder = webpki_server_verifier_builder(get_client_root_store(*kt)) .with_crls(crls.clone()) .only_check_end_entity_revocation() .allow_unknown_revocation_status(); @@ -1151,6 +1195,7 @@ fn client_check_server_certificate_helper_api() { } } +#[derive(Debug)] struct ClientCheckCertResolve { query_count: AtomicUsize, expect_queries: usize, @@ -1204,7 +1249,8 @@ fn test_client_cert_resolve(key_type: KeyType, server_config: Arc, ProtocolVersion::TLSv1_2 => vec![ SignatureScheme::ECDSA_NISTP384_SHA384, SignatureScheme::ECDSA_NISTP256_SHA256, - SignatureScheme::ED25519, + // mbedtls does not support ED25519 + // SignatureScheme::ED25519, SignatureScheme::RSA_PSS_SHA512, SignatureScheme::RSA_PSS_SHA384, SignatureScheme::RSA_PSS_SHA256, @@ -1215,7 +1261,8 @@ fn test_client_cert_resolve(key_type: KeyType, server_config: Arc, ProtocolVersion::TLSv1_3 => vec![ SignatureScheme::ECDSA_NISTP384_SHA384, SignatureScheme::ECDSA_NISTP256_SHA256, - SignatureScheme::ED25519, + // mbedtls does not support ED25519 + // SignatureScheme::ED25519, SignatureScheme::RSA_PSS_SHA512, SignatureScheme::RSA_PSS_SHA384, SignatureScheme::RSA_PSS_SHA256, @@ -1253,7 +1300,7 @@ fn client_cert_resolve_default() { let expected_root_hint_subjects = vec![match key_type { KeyType::Rsa => &b"0\x1a1\x180\x16\x06\x03U\x04\x03\x0c\x0fponytown RSA CA"[..], KeyType::Ecdsa => &b"0\x1c1\x1a0\x18\x06\x03U\x04\x03\x0c\x11ponytown ECDSA CA"[..], - KeyType::Ed25519 => &b"0\x1c1\x1a0\x18\x06\x03U\x04\x03\x0c\x11ponytown EdDSA CA"[..], + // KeyType::Ed25519 => &b"0\x1c1\x1a0\x18\x06\x03U\x04\x03\x0c\x11ponytown EdDSA CA"[..], } .to_vec()]; @@ -1267,7 +1314,7 @@ fn client_cert_resolve_server_no_hints() { // arguments. for key_type in ALL_KEY_TYPES.into_iter() { // Build a verifier with no hint subjects. - let verifier = WebPkiClientVerifier::builder(get_client_root_store(key_type)).clear_root_hint_subjects(); + let verifier = webpki_client_verifier_builder(get_client_root_store(key_type)).clear_root_hint_subjects(); let server_config = make_server_config_with_client_verifier(key_type, verifier); let expected_root_hint_subjects = Vec::default(); // no hints expected. test_client_cert_resolve(key_type, server_config.into(), expected_root_hint_subjects); @@ -1284,14 +1331,14 @@ fn client_cert_resolve_server_added_hint() { match key_type { KeyType::Rsa => &b"0\x1a1\x180\x16\x06\x03U\x04\x03\x0c\x0fponytown RSA CA"[..], KeyType::Ecdsa => &b"0\x1c1\x1a0\x18\x06\x03U\x04\x03\x0c\x11ponytown ECDSA CA"[..], - KeyType::Ed25519 => &b"0\x1c1\x1a0\x18\x06\x03U\x04\x03\x0c\x11ponytown EdDSA CA"[..], + // KeyType::Ed25519 => &b"0\x1c1\x1a0\x18\x06\x03U\x04\x03\x0c\x11ponytown EdDSA CA"[..], } .to_vec(), extra_name.clone(), ]; // Create a verifier that adds the extra_name as a hint subject in addition to the ones // from the root cert store. - let verifier = WebPkiClientVerifier::builder(get_client_root_store(key_type)) + let verifier = webpki_client_verifier_builder(get_client_root_store(key_type)) .add_root_hint_subjects([DistinguishedName::from(extra_name.clone())].into_iter()); let server_config = make_server_config_with_client_verifier(key_type, verifier); test_client_cert_resolve(key_type, server_config.into(), expected_hint_subjects); @@ -1319,7 +1366,7 @@ fn client_mandatory_auth_client_revocation_works() { let relevant_crls = vec![kt.client_crl()]; // Only check the EE certificate status. See client_mandatory_auth_intermediate_revocation_works // for testing revocation status of the whole chain. - let ee_verifier_builder = WebPkiClientVerifier::builder(get_client_root_store(*kt)) + let ee_verifier_builder = webpki_client_verifier_builder(get_client_root_store(*kt)) .with_crls(relevant_crls) .only_check_end_entity_revocation(); let revoked_server_config = Arc::new(make_server_config_with_client_verifier(*kt, ee_verifier_builder)); @@ -1327,14 +1374,14 @@ fn client_mandatory_auth_client_revocation_works() { // Create a server configuration that includes a CRL that doesn't cover the client certificate, // and uses the default behaviour of treating unknown revocation status as an error. let unrelated_crls = vec![kt.intermediate_crl()]; - let ee_verifier_builder = WebPkiClientVerifier::builder(get_client_root_store(*kt)) + let ee_verifier_builder = webpki_client_verifier_builder(get_client_root_store(*kt)) .with_crls(unrelated_crls.clone()) .only_check_end_entity_revocation(); let missing_client_crl_server_config = Arc::new(make_server_config_with_client_verifier(*kt, ee_verifier_builder)); // Create a server configuration that includes a CRL that doesn't cover the client certificate, // but change the builder to allow unknown revocation status. - let ee_verifier_builder = WebPkiClientVerifier::builder(get_client_root_store(*kt)) + let ee_verifier_builder = webpki_client_verifier_builder(get_client_root_store(*kt)) .with_crls(unrelated_crls.clone()) .only_check_end_entity_revocation() .allow_unknown_revocation_status(); @@ -1377,14 +1424,14 @@ fn client_mandatory_auth_intermediate_revocation_works() { // is revoked. We check the full chain for revocation status (default), and allow unknown // revocation status so the EE's unknown revocation status isn't an error. let crls = vec![kt.intermediate_crl()]; - let full_chain_verifier_builder = WebPkiClientVerifier::builder(get_client_root_store(*kt)) + let full_chain_verifier_builder = webpki_client_verifier_builder(get_client_root_store(*kt)) .with_crls(crls.clone()) .allow_unknown_revocation_status(); let full_chain_server_config = Arc::new(make_server_config_with_client_verifier(*kt, full_chain_verifier_builder)); // Also create a server configuration that uses the same CRL, but that only checks the EE // cert revocation status. - let ee_only_verifier_builder = WebPkiClientVerifier::builder(get_client_root_store(*kt)) + let ee_only_verifier_builder = webpki_client_verifier_builder(get_client_root_store(*kt)) .with_crls(crls) .only_check_end_entity_revocation() .allow_unknown_revocation_status(); @@ -2171,8 +2218,8 @@ fn make_disjoint_suite_configs() -> (ClientConfig, ServerConfig) { let kt = KeyType::Rsa; let server_config = finish_server_config( kt, - ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) - .with_cipher_suites(&[rustls_mbedcrypto_provider::tls13::TLS13_CHACHA20_POLY1305_SHA256]) + server_config_builder() + .with_cipher_suites(&[cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() .unwrap(), @@ -2180,8 +2227,8 @@ fn make_disjoint_suite_configs() -> (ClientConfig, ServerConfig) { let client_config = finish_client_config( kt, - ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) - .with_cipher_suites(&[rustls_mbedcrypto_provider::tls13::TLS13_AES_256_GCM_SHA384]) + client_config_builder() + .with_cipher_suites(&[cipher_suite::TLS13_AES_256_GCM_SHA384]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() .unwrap(), @@ -2377,7 +2424,7 @@ fn server_exposes_offered_sni_even_if_resolver_fails() { fn sni_resolver_works() { let kt = KeyType::Rsa; let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); - let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); + let signing_key = RsaSigningKey::new(&kt.get_key()).unwrap(); let signing_key: Arc = Arc::new(signing_key); resolver .add("localhost", sign::CertifiedKey::new(kt.get_chain(), signing_key.clone())) @@ -2407,7 +2454,7 @@ fn sni_resolver_works() { fn sni_resolver_rejects_wrong_names() { let kt = KeyType::Rsa; let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); - let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); + let signing_key = RsaSigningKey::new(&kt.get_key()).unwrap(); let signing_key: Arc = Arc::new(signing_key); assert_eq!( @@ -2428,7 +2475,7 @@ fn sni_resolver_rejects_wrong_names() { fn sni_resolver_lower_cases_configured_names() { let kt = KeyType::Rsa; let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); - let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); + let signing_key = RsaSigningKey::new(&kt.get_key()).unwrap(); let signing_key: Arc = Arc::new(signing_key); assert_eq!( @@ -2451,7 +2498,7 @@ fn sni_resolver_lower_cases_queried_names() { // actually, the handshake parser does this, but the effect is the same. let kt = KeyType::Rsa; let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); - let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); + let signing_key = RsaSigningKey::new(&kt.get_key()).unwrap(); let signing_key: Arc = Arc::new(signing_key); assert_eq!( @@ -2473,7 +2520,7 @@ fn sni_resolver_lower_cases_queried_names() { fn sni_resolver_rejects_bad_certs() { let kt = KeyType::Rsa; let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); - let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); + let signing_key = RsaSigningKey::new(&kt.get_key()).unwrap(); let signing_key: Arc = Arc::new(signing_key); assert_eq!( @@ -2628,7 +2675,10 @@ fn do_suite_test( } fn find_suite(suite: CipherSuite) -> SupportedCipherSuite { - for scs in ALL_CIPHER_SUITES.iter().copied() { + for scs in primary_provider::ALL_CIPHER_SUITES + .iter() + .copied() + { if scs.suite() == suite { return scs; } @@ -2697,7 +2747,7 @@ fn negotiated_ciphersuite_default() { #[test] fn all_suites_covered() { - assert_eq!(ALL_CIPHER_SUITES.len(), TEST_CIPHERSUITES.len()); + assert_eq!(primary_provider::ALL_CIPHER_SUITES.len(), TEST_CIPHERSUITES.len()); } #[test] @@ -2707,7 +2757,7 @@ fn negotiated_ciphersuite_client() { let scs = find_suite(suite); let client_config = finish_client_config( kt, - ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + client_config_builder() .with_cipher_suites(&[scs]) .with_safe_default_kx_groups() .with_protocol_versions(&[version]) @@ -2725,7 +2775,7 @@ fn negotiated_ciphersuite_server() { let scs = find_suite(suite); let server_config = finish_server_config( kt, - ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + server_config_builder() .with_cipher_suites(&[scs]) .with_safe_default_kx_groups() .with_protocol_versions(&[version]) @@ -2743,6 +2793,7 @@ struct KeyLogItem { secret: Vec, } +#[derive(Debug)] struct KeyLogToVec { label: &'static str, items: Mutex>, @@ -3307,6 +3358,7 @@ fn tls13_stateless_resumption() { let client_config = Arc::new(client_config); let mut server_config = make_server_config(kt); + // TODO: add mbedtls based Ticketer server_config.ticketer = rustls::crypto::ring::Ticketer::new().unwrap(); let storage = Arc::new(ServerStorage::new()); server_config.session_storage = storage.clone(); @@ -3355,6 +3407,7 @@ fn tls13_stateless_resumption() { Some(3) ); } + #[test] fn early_data_not_available() { let (mut client, _) = make_pair(KeyType::Rsa); @@ -3496,16 +3549,16 @@ fn test_client_does_not_offer_sha1() { #[test] fn test_client_config_keyshare() { - let client_config = make_client_config_with_kx_groups(KeyType::Rsa, &[rustls_mbedcrypto_provider::kx_group::SECP384R1]); - let server_config = make_server_config_with_kx_groups(KeyType::Rsa, &[rustls_mbedcrypto_provider::kx_group::SECP384R1]); + let client_config = make_client_config_with_kx_groups(KeyType::Rsa, &[primary_provider::kx_group::SECP384R1]); + let server_config = make_server_config_with_kx_groups(KeyType::Rsa, &[primary_provider::kx_group::SECP384R1]); let (mut client, mut server) = make_pair_for_configs(client_config, server_config); do_handshake_until_error(&mut client, &mut server).unwrap(); } #[test] fn test_client_config_keyshare_mismatch() { - let client_config = make_client_config_with_kx_groups(KeyType::Rsa, &[rustls_mbedcrypto_provider::kx_group::SECP384R1]); - let server_config = make_server_config_with_kx_groups(KeyType::Rsa, &[rustls_mbedcrypto_provider::kx_group::X25519]); + let client_config = make_client_config_with_kx_groups(KeyType::Rsa, &[primary_provider::kx_group::SECP384R1]); + let server_config = make_server_config_with_kx_groups(KeyType::Rsa, &[primary_provider::kx_group::X25519]); let (mut client, mut server) = make_pair_for_configs(client_config, server_config); assert!(do_handshake_until_error(&mut client, &mut server).is_err()); } @@ -3516,17 +3569,14 @@ fn test_client_sends_helloretryrequest() { // client sends a secp384r1 key share let mut client_config = make_client_config_with_kx_groups( KeyType::Rsa, - &[ - rustls_mbedcrypto_provider::kx_group::SECP384R1, - rustls_mbedcrypto_provider::kx_group::X25519, - ], + &[primary_provider::kx_group::SECP384R1, primary_provider::kx_group::X25519], ); let storage = Arc::new(ClientStorage::new()); client_config.resumption = Resumption::store(storage.clone()); // but server only accepts x25519, so a HRR is required - let server_config = make_server_config_with_kx_groups(KeyType::Rsa, &[rustls_mbedcrypto_provider::kx_group::X25519]); + let server_config = make_server_config_with_kx_groups(KeyType::Rsa, &[primary_provider::kx_group::X25519]); let (mut client, mut server) = make_pair_for_configs(client_config, server_config); @@ -3589,8 +3639,7 @@ fn test_client_sends_helloretryrequest() { #[test] fn test_client_rejects_hrr_with_varied_session_id() { use rustls::internal::msgs::handshake::SessionId; - use rustls_mbedcrypto_provider::MBEDTLS; - let different_session_id = SessionId::random(MBEDTLS).unwrap(); + let different_session_id = SessionId::random(PROVIDER).unwrap(); let assert_client_sends_hello_with_secp384 = |msg: &mut Message| -> Altered { if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload { @@ -3623,13 +3672,10 @@ fn test_client_rejects_hrr_with_varied_session_id() { // client prefers a secp384r1 key share, server only accepts x25519 let client_config = make_client_config_with_kx_groups( KeyType::Rsa, - &[ - rustls_mbedcrypto_provider::kx_group::SECP384R1, - rustls_mbedcrypto_provider::kx_group::X25519, - ], + &[primary_provider::kx_group::SECP384R1, primary_provider::kx_group::X25519], ); - let server_config = make_server_config_with_kx_groups(KeyType::Rsa, &[rustls_mbedcrypto_provider::kx_group::X25519]); + let server_config = make_server_config_with_kx_groups(KeyType::Rsa, &[primary_provider::kx_group::X25519]); let (client, server) = make_pair_for_configs(client_config, server_config); let (mut client, mut server) = (client.into(), server.into()); @@ -3647,19 +3693,17 @@ fn test_client_rejects_hrr_with_varied_session_id() { #[cfg(feature = "tls12")] #[test] fn test_client_attempts_to_use_unsupported_kx_group() { - use rustls_mbedcrypto_provider::kx_group::{SECP384R1, X25519}; - // common to both client configs let shared_storage = Arc::new(ClientStorage::new()); // first, client sends a x25519 and server agrees. x25519 is inserted // into kx group cache. - let mut client_config_1 = make_client_config_with_kx_groups(KeyType::Rsa, &[X25519]); + let mut client_config_1 = make_client_config_with_kx_groups(KeyType::Rsa, &[primary_provider::kx_group::X25519]); client_config_1.resumption = Resumption::store(shared_storage.clone()); // second, client only supports secp-384 and so kx group cache // contains an unusable value. - let mut client_config_2 = make_client_config_with_kx_groups(KeyType::Rsa, &[SECP384R1]); + let mut client_config_2 = make_client_config_with_kx_groups(KeyType::Rsa, &[primary_provider::kx_group::SECP384R1]); client_config_2.resumption = Resumption::store(shared_storage.clone()); let server_config = make_server_config(KeyType::Rsa); @@ -3833,7 +3877,7 @@ fn test_server_mtu_reduction() { } fn check_client_max_fragment_size(size: usize) -> Option { - let mut client_config = make_client_config(KeyType::Ed25519); + let mut client_config = make_client_config(KeyType::Rsa); client_config.max_fragment_size = Some(size); ClientConnection::new(Arc::new(client_config), server_name("localhost")).err() } @@ -3850,6 +3894,39 @@ fn bad_client_max_fragment_sizes() { assert_eq!(check_client_max_fragment_size(0xffff), Some(Error::BadMaxFragmentSize)); } +#[test] +fn handshakes_complete_and_data_flows_with_gratuitious_max_fragment_sizes() { + // general exercising of msgs::fragmenter and msgs::deframer + for kt in ALL_KEY_TYPES.iter() { + for version in rustls::ALL_VERSIONS { + // no hidden significance to these numbers + for frag_size in [37, 61, 101, 257] { + println!("test kt={kt:?} version={version:?} frag={frag_size:?}"); + let mut client_config = make_client_config_with_versions(*kt, &[version]); + client_config.max_fragment_size = Some(frag_size); + let mut server_config = make_server_config(*kt); + server_config.max_fragment_size = Some(frag_size); + + let (mut client, mut server) = make_pair_for_configs(client_config, server_config); + do_handshake(&mut client, &mut server); + + // check server -> client data flow + let pattern = (0x00..=0xffu8).collect::>(); + assert_eq!(pattern.len(), server.writer().write(&pattern).unwrap()); + transfer(&mut server, &mut client); + client.process_new_packets().unwrap(); + check_read(&mut client.reader(), &pattern); + + // and client -> server + assert_eq!(pattern.len(), client.writer().write(&pattern).unwrap()); + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + check_read(&mut server.reader(), &pattern); + } + } + } +} + fn assert_lt(left: usize, right: usize) { if left >= right { panic!("expected {} < {}", left, right); @@ -3972,14 +4049,14 @@ fn test_client_rejects_illegal_tls13_ccs() { #[cfg(feature = "tls12")] #[test] fn test_client_tls12_no_resume_after_server_downgrade() { - let mut client_config = common::make_client_config(KeyType::Ed25519); + let mut client_config = common::make_client_config(KeyType::Rsa); let client_storage = Arc::new(ClientStorage::new()); client_config.resumption = Resumption::store(client_storage.clone()); let client_config = Arc::new(client_config); let server_config_1 = Arc::new(common::finish_server_config( - KeyType::Ed25519, - ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + KeyType::Rsa, + server_config_builder() .with_safe_default_cipher_suites() .with_safe_default_kx_groups() .with_protocol_versions(&[&rustls::version::TLS13]) @@ -3987,8 +4064,8 @@ fn test_client_tls12_no_resume_after_server_downgrade() { )); let mut server_config_2 = common::finish_server_config( - KeyType::Ed25519, - ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + KeyType::Rsa, + server_config_builder() .with_safe_default_cipher_suites() .with_safe_default_kx_groups() .with_protocol_versions(&[&rustls::version::TLS12]) @@ -4025,12 +4102,12 @@ fn test_client_tls12_no_resume_after_server_downgrade() { fn test_acceptor() { use rustls::server::Acceptor; - let client_config = Arc::new(make_client_config(KeyType::Ed25519)); + let client_config = Arc::new(make_client_config(KeyType::Rsa)); let mut client = ClientConnection::new(client_config, server_name("localhost")).unwrap(); let mut buf = Vec::new(); client.write_tls(&mut buf).unwrap(); - let server_config = Arc::new(make_server_config(KeyType::Ed25519)); + let server_config = Arc::new(make_server_config(KeyType::Rsa)); let mut acceptor = Acceptor::default(); acceptor .read_tls(&mut buf.as_slice()) @@ -4197,18 +4274,18 @@ fn test_secret_extraction_enabled() { // Chacha20Poly1305), so that's 2*3 = 6 combinations to test. let kt = KeyType::Rsa; for suite in [ - rustls_mbedcrypto_provider::tls13::TLS13_AES_128_GCM_SHA256, - rustls_mbedcrypto_provider::tls13::TLS13_AES_256_GCM_SHA384, - rustls_mbedcrypto_provider::tls13::TLS13_CHACHA20_POLY1305_SHA256, - rustls_mbedcrypto_provider::tls12::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - rustls_mbedcrypto_provider::tls12::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - rustls_mbedcrypto_provider::tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + cipher_suite::TLS13_AES_128_GCM_SHA256, + cipher_suite::TLS13_AES_256_GCM_SHA384, + cipher_suite::TLS13_CHACHA20_POLY1305_SHA256, + cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + cipher_suite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, ] { let version = suite.version(); println!("Testing suite {:?}", suite.suite().as_str()); // Only offer the cipher suite (and protocol version) that we're testing - let mut server_config = ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + let mut server_config = server_config_builder() .with_cipher_suites(&[suite]) .with_safe_default_kx_groups() .with_protocol_versions(&[version]) @@ -4265,11 +4342,11 @@ fn test_secret_extraction_enabled() { #[cfg(feature = "tls12")] #[test] fn test_secret_extraction_disabled_or_too_early() { - let suite = rustls_mbedcrypto_provider::tls13::TLS13_AES_128_GCM_SHA256; + let suite = cipher_suite::TLS13_AES_128_GCM_SHA256; let kt = KeyType::Rsa; for (server_enable, client_enable) in [(true, false), (false, true)] { - let mut server_config = ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + let mut server_config = server_config_builder() .with_cipher_suites(&[suite]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() @@ -4321,11 +4398,11 @@ fn test_secret_extraction_disabled_or_too_early() { #[test] fn test_received_plaintext_backpressure() { - let suite = rustls_mbedcrypto_provider::tls13::TLS13_AES_128_GCM_SHA256; + let suite = cipher_suite::TLS13_AES_128_GCM_SHA256; let kt = KeyType::Rsa; let server_config = Arc::new( - ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + server_config_builder() .with_cipher_suites(&[suite]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() @@ -4411,7 +4488,7 @@ fn test_debug_server_name_from_string() { fn test_explicit_provider_selection() { let client_config = finish_client_config( KeyType::Rsa, - rustls::ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS).with_safe_defaults(), + rustls::ClientConfig::builder_with_provider(rustls::crypto::ring::RING).with_safe_defaults(), ); let server_config = finish_server_config( KeyType::Rsa, @@ -4453,16 +4530,24 @@ impl rustls::crypto::CryptoProvider for FaultyRandomProvider { fn default_kx_groups(&self) -> &'static [&'static (dyn rustls::crypto::SupportedKxGroup)] { self.parent.default_kx_groups() } + + fn load_private_key(&self, key_der: PrivateKeyDer<'static>) -> Result, Error> { + self.parent.load_private_key(key_der) + } + + fn signature_verification_algorithms(&self) -> rustls::WebPkiSupportedAlgorithms { + self.parent + .signature_verification_algorithms() + } } #[test] fn test_client_construction_fails_if_random_source_fails_in_first_request() { - static PROVIDER: FaultyRandomProvider = - FaultyRandomProvider { parent: rustls_mbedcrypto_provider::MBEDTLS, rand_queue: Mutex::new(b"") }; + static TEST_PROVIDER: FaultyRandomProvider = FaultyRandomProvider { parent: PROVIDER, rand_queue: Mutex::new(b"") }; let client_config = finish_client_config( KeyType::Rsa, - rustls::ClientConfig::builder_with_provider(&PROVIDER).with_safe_defaults(), + rustls::ClientConfig::builder_with_provider(&TEST_PROVIDER).with_safe_defaults(), ); assert_eq!( @@ -4473,14 +4558,12 @@ fn test_client_construction_fails_if_random_source_fails_in_first_request() { #[test] fn test_client_construction_fails_if_random_source_fails_in_second_request() { - static PROVIDER: FaultyRandomProvider = FaultyRandomProvider { - parent: rustls_mbedcrypto_provider::MBEDTLS, - rand_queue: Mutex::new(b"nice random number generator huh"), - }; + static TEST_PROVIDER: FaultyRandomProvider = + FaultyRandomProvider { parent: PROVIDER, rand_queue: Mutex::new(b"nice random number generator huh") }; let client_config = finish_client_config( KeyType::Rsa, - rustls::ClientConfig::builder_with_provider(&PROVIDER).with_safe_defaults(), + rustls::ClientConfig::builder_with_provider(&TEST_PROVIDER).with_safe_defaults(), ); assert_eq!( @@ -4491,8 +4574,8 @@ fn test_client_construction_fails_if_random_source_fails_in_second_request() { #[test] fn test_client_construction_requires_64_bytes_of_random_material() { - static PROVIDER: FaultyRandomProvider = FaultyRandomProvider { - parent: rustls_mbedcrypto_provider::MBEDTLS, + static TEST_PROVIDER: FaultyRandomProvider = FaultyRandomProvider { + parent: PROVIDER, rand_queue: Mutex::new( b"nice random number generator !!!\ it's really not very good is it?", @@ -4501,7 +4584,7 @@ fn test_client_construction_requires_64_bytes_of_random_material() { let client_config = finish_client_config( KeyType::Rsa, - rustls::ClientConfig::builder_with_provider(&PROVIDER).with_safe_defaults(), + rustls::ClientConfig::builder_with_provider(&TEST_PROVIDER).with_safe_defaults(), ); ClientConnection::new(Arc::new(client_config), server_name("localhost")) diff --git a/rustls-mbedcrypto-provider/tests/common/mod.rs b/rustls-mbedcrypto-provider/tests/common/mod.rs index 4d7b7b8..ef85ae7 100644 --- a/rustls-mbedcrypto-provider/tests/common/mod.rs +++ b/rustls-mbedcrypto-provider/tests/common/mod.rs @@ -14,7 +14,7 @@ use std::sync::Arc; use pki_types::{CertificateDer, CertificateRevocationListDer, PrivateKeyDer}; use webpki::extract_trust_anchor; -use rustls::client::ServerCertVerifierBuilder; +use rustls::client::{ServerCertVerifierBuilder, WebPkiServerVerifier}; use rustls::internal::msgs::codec::Reader; use rustls::internal::msgs::message::{Message, OpaqueMessage, PlainMessage}; use rustls::server::{ClientCertVerifierBuilder, WebPkiClientVerifier}; @@ -24,6 +24,9 @@ use rustls::RootCertStore; use rustls::{ClientConfig, ClientConnection}; use rustls::{ConnectionCommon, ServerConfig, ServerConnection, SideData}; +pub use rustls_mbedcrypto_provider as primary_provider; +pub use rustls_mbedcrypto_provider::MBEDTLS as PROVIDER; + macro_rules! embed_files { ( $( @@ -199,17 +202,22 @@ where pub enum KeyType { Rsa, Ecdsa, - Ed25519, + // Ed25519, } -pub static ALL_KEY_TYPES: [KeyType; 3] = [KeyType::Rsa, KeyType::Ecdsa, KeyType::Ed25519]; +pub static ALL_KEY_TYPES: [KeyType; 2] = [ + KeyType::Rsa, + KeyType::Ecdsa, + // ! Ed25519 is not supported by mbedtls + // KeyType::Ed25519, +]; impl KeyType { fn bytes_for(&self, part: &str) -> &'static [u8] { match self { Self::Rsa => bytes_for("rsa", part), Self::Ecdsa => bytes_for("ecdsa", part), - Self::Ed25519 => bytes_for("eddsa", part), + // Self::Ed25519 => bytes_for("eddsa", part), } } @@ -263,6 +271,33 @@ impl KeyType { } } +pub fn server_config_builder() -> rustls::ConfigBuilder { + // ensure `ServerConfig::builder()` is covered, even though it is + // equivalent to `builder_with_provider(PROVIDER)`. + #[cfg(feature = "ring")] + { + rustls::ServerConfig::builder() + } + #[cfg(not(feature = "ring"))] + { + rustls::ServerConfig::builder_with_provider(PROVIDER) + } +} + +pub fn client_config_builder() -> rustls::ConfigBuilder { + // ensure `ClientConfig::builder()` is covered, even though it is + // equivalent to `builder_with_provider(PROVIDER)`. + #[cfg(feature = "ring")] + { + rustls::ClientConfig::builder() + } + + #[cfg(not(feature = "ring"))] + { + rustls::ClientConfig::builder_with_provider(PROVIDER) + } +} + pub fn finish_server_config(kt: KeyType, conf: rustls::ConfigBuilder) -> ServerConfig { conf.with_no_client_auth() .with_single_cert(kt.get_chain(), kt.get_key()) @@ -270,16 +305,13 @@ pub fn finish_server_config(kt: KeyType, conf: rustls::ConfigBuilder ServerConfig { - finish_server_config( - kt, - ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS).with_safe_defaults(), - ) + finish_server_config(kt, server_config_builder().with_safe_defaults()) } pub fn make_server_config_with_versions(kt: KeyType, versions: &[&'static rustls::SupportedProtocolVersion]) -> ServerConfig { finish_server_config( kt, - ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + server_config_builder() .with_safe_default_cipher_suites() .with_safe_default_kx_groups() .with_protocol_versions(versions) @@ -293,7 +325,7 @@ pub fn make_server_config_with_kx_groups( ) -> ServerConfig { finish_server_config( kt, - ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + server_config_builder() .with_safe_default_cipher_suites() .with_kx_groups(kx_groups) .with_safe_default_protocol_versions() @@ -318,11 +350,11 @@ pub fn make_server_config_with_mandatory_client_auth_crls( kt: KeyType, crls: Vec>, ) -> ServerConfig { - make_server_config_with_client_verifier(kt, WebPkiClientVerifier::builder(get_client_root_store(kt)).with_crls(crls)) + make_server_config_with_client_verifier(kt, webpki_client_verifier_builder(get_client_root_store(kt)).with_crls(crls)) } pub fn make_server_config_with_mandatory_client_auth(kt: KeyType) -> ServerConfig { - make_server_config_with_client_verifier(kt, WebPkiClientVerifier::builder(get_client_root_store(kt))) + make_server_config_with_client_verifier(kt, webpki_client_verifier_builder(get_client_root_store(kt))) } pub fn make_server_config_with_optional_client_auth( @@ -331,7 +363,7 @@ pub fn make_server_config_with_optional_client_auth( ) -> ServerConfig { make_server_config_with_client_verifier( kt, - WebPkiClientVerifier::builder(get_client_root_store(kt)) + webpki_client_verifier_builder(get_client_root_store(kt)) .with_crls(crls) .allow_unknown_revocation_status() .allow_unauthenticated(), @@ -339,7 +371,7 @@ pub fn make_server_config_with_optional_client_auth( } pub fn make_server_config_with_client_verifier(kt: KeyType, verifier_builder: ClientCertVerifierBuilder) -> ServerConfig { - ServerConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + server_config_builder() .with_safe_defaults() .with_client_cert_verifier(verifier_builder.build().unwrap()) .with_single_cert(kt.get_chain(), kt.get_key()) @@ -372,17 +404,14 @@ pub fn finish_client_config_with_creds( } pub fn make_client_config(kt: KeyType) -> ClientConfig { - finish_client_config( - kt, - ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS).with_safe_defaults(), - ) + finish_client_config(kt, client_config_builder().with_safe_defaults()) } pub fn make_client_config_with_kx_groups( kt: KeyType, kx_groups: &[&'static dyn rustls::crypto::SupportedKxGroup], ) -> ClientConfig { - let builder = ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + let builder = client_config_builder() .with_safe_default_cipher_suites() .with_kx_groups(kx_groups) .with_safe_default_protocol_versions() @@ -391,7 +420,7 @@ pub fn make_client_config_with_kx_groups( } pub fn make_client_config_with_versions(kt: KeyType, versions: &[&'static rustls::SupportedProtocolVersion]) -> ClientConfig { - let builder = ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + let builder = client_config_builder() .with_safe_default_cipher_suites() .with_safe_default_kx_groups() .with_protocol_versions(versions) @@ -400,17 +429,14 @@ pub fn make_client_config_with_versions(kt: KeyType, versions: &[&'static rustls } pub fn make_client_config_with_auth(kt: KeyType) -> ClientConfig { - finish_client_config_with_creds( - kt, - ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS).with_safe_defaults(), - ) + finish_client_config_with_creds(kt, client_config_builder().with_safe_defaults()) } pub fn make_client_config_with_versions_with_auth( kt: KeyType, versions: &[&'static rustls::SupportedProtocolVersion], ) -> ClientConfig { - let builder = ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + let builder = client_config_builder() .with_safe_default_cipher_suites() .with_safe_default_kx_groups() .with_protocol_versions(versions) @@ -422,7 +448,7 @@ pub fn make_client_config_with_verifier( versions: &[&'static rustls::SupportedProtocolVersion], verifier_builder: ServerCertVerifierBuilder, ) -> ClientConfig { - ClientConfig::builder_with_provider(rustls_mbedcrypto_provider::MBEDTLS) + client_config_builder() .with_safe_default_cipher_suites() .with_safe_default_kx_groups() .with_protocol_versions(versions) @@ -432,6 +458,30 @@ pub fn make_client_config_with_verifier( .with_no_client_auth() } +pub fn webpki_client_verifier_builder(roots: Arc) -> ClientCertVerifierBuilder { + #[cfg(feature = "ring")] + { + WebPkiClientVerifier::builder(roots) + } + + #[cfg(not(feature = "ring"))] + { + WebPkiClientVerifier::builder_with_provider(roots, PROVIDER) + } +} + +pub fn webpki_server_verifier_builder(roots: Arc) -> ServerCertVerifierBuilder { + #[cfg(feature = "ring")] + { + WebPkiServerVerifier::builder(roots) + } + + #[cfg(not(feature = "ring"))] + { + WebPkiServerVerifier::builder_with_provider(roots, PROVIDER) + } +} + pub fn make_pair(kt: KeyType) -> (ClientConnection, ServerConnection) { make_pair_for_configs(make_client_config(kt), make_server_config(kt)) } diff --git a/rustls-mbedpki-provider/Cargo.toml b/rustls-mbedpki-provider/Cargo.toml index 4b66e99..aa7f6a1 100644 --- a/rustls-mbedpki-provider/Cargo.toml +++ b/rustls-mbedpki-provider/Cargo.toml @@ -11,7 +11,7 @@ categories = ["network-programming", "cryptography"] resolver = "2" [dependencies] -rustls = { git = "https://github.com/rustls/rustls", rev = "b776a5778ad333653670c34ff9125d8ae59b6047", version = "0.22.0-alpha.4", default_features = false } +rustls = { version = "0.22.0-alpha.4", default_features = false } mbedtls = { version = "0.12.0-alpha.2", features = [ "x509", "chrono", @@ -23,6 +23,7 @@ chrono = "0.4" pki-types = { package = "rustls-pki-types", version = "0.2.1", features = [ "std", ] } +utils = { package = "rustls-mbedtls-provider-utils", path = "../rustls-mbedtls-provider-utils", version = "0.1.0-alpha.1" } [target.'cfg(target_env = "msvc")'.dependencies] # mbedtls need feature `time` to build when targeting msvc @@ -35,4 +36,4 @@ mbedtls = { version = "0.12.0-alpha.2", default-features = false, features = [ [dev-dependencies] rustls-pemfile = "1.0" -rustls = { git = "https://github.com/rustls/rustls", rev = "b776a5778ad333653670c34ff9125d8ae59b6047", version = "0.22.0-alpha.4" } +rustls = { version = "0.22.0-alpha.4" } diff --git a/rustls-mbedpki-provider/src/client_cert_verifier.rs b/rustls-mbedpki-provider/src/client_cert_verifier.rs index 10ae1ab..a3f7f2d 100644 --- a/rustls-mbedpki-provider/src/client_cert_verifier.rs +++ b/rustls-mbedpki-provider/src/client_cert_verifier.rs @@ -5,18 +5,20 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use std::sync::Arc; - +use alloc::string::String; +use alloc::sync::Arc; +use alloc::vec; +use alloc::vec::Vec; use chrono::NaiveDateTime; use pki_types::{CertificateDer, UnixTime}; use rustls::{ server::danger::{ClientCertVerified, ClientCertVerifier}, DistinguishedName, }; +use utils::error::mbedtls_err_into_rustls_err_with_error_msg; use crate::{ - mbedtls_err_into_rustls_err, mbedtls_err_into_rustls_err_with_error_msg, rustls_cert_to_mbedtls_cert, - verify_certificates_active, verify_tls_signature, CertActiveCheck, + mbedtls_err_into_rustls_err, rustls_cert_to_mbedtls_cert, verify_certificates_active, verify_tls_signature, CertActiveCheck, }; /// A [`rustls`] [`ClientCertVerifier`] implemented using the PKI functionality of @@ -29,6 +31,17 @@ pub struct MbedTlsClientCertVerifier { cert_active_check: CertActiveCheck, } +impl core::fmt::Debug for MbedTlsClientCertVerifier { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("MbedTlsClientCertVerifier") + .field("trusted_cas", &"..") + .field("root_subjects", &self.root_subjects) + .field("verify_callback", &"..") + .field("cert_active_check", &self.cert_active_check) + .finish() + } +} + impl MbedTlsClientCertVerifier { /// Constructs a new [`MbedTlsClientCertVerifier`] object given the provided trusted certificate authority /// certificates. @@ -198,6 +211,16 @@ mod tests { .unwrap() } + #[test] + fn client_cert_verifier_debug() { + let root_ca = CertificateDer::from(include_bytes!("../test-data/rsa/ca.der").to_vec()); + let client_cert_verifier = MbedTlsClientCertVerifier::new([&root_ca]).unwrap(); + assert_eq!( + r#"MbedTlsClientCertVerifier { trusted_cas: "..", root_subjects: [DistinguishedName(301a3118301606035504030c0f706f6e79746f776e20525341204341)], verify_callback: "..", cert_active_check: CertActiveCheck { ignore_expired: false, ignore_not_active_yet: false } }"#, + format!("{:?}", client_cert_verifier) + ); + } + #[test] fn connection_client_cert_verifier() { let client_config = ClientConfig::builder().with_safe_defaults(); diff --git a/rustls-mbedpki-provider/src/lib.rs b/rustls-mbedpki-provider/src/lib.rs index d2af9b6..42841bd 100644 --- a/rustls-mbedpki-provider/src/lib.rs +++ b/rustls-mbedpki-provider/src/lib.rs @@ -31,12 +31,21 @@ // Enable documentation for all features on docs.rs #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(bench, feature(test))] +#![cfg_attr(not(test), no_std)] + +extern crate alloc; + +// This `extern crate` plus the `#![no_std]` attribute changes the default prelude from +// `std::prelude` to `core::prelude`. That forces one to _explicitly_ import (`use`) everything that +// is in `std::prelude` but not in `core::prelude`. This helps maintain no-std support as even +// developers that are not interested in, or aware of, no-std support and / or that never run +// `cargo build --no-default-features` locally will get errors when they rely on `std::prelude` API. +#[cfg(not(test))] +extern crate std; use chrono::NaiveDateTime; -use mbedtls::hash::Type; use pki_types::CertificateDer; use rustls::SignatureScheme; -use std::sync::Arc; #[cfg(test)] mod tests_common; @@ -52,6 +61,7 @@ pub mod server_cert_verifier; pub use client_cert_verifier::MbedTlsClientCertVerifier; pub use server_cert_verifier::MbedTlsServerCertVerifier; +use utils::error::mbedtls_err_into_rustls_err; /// A config about whether to check certificate validity period #[derive(Debug, PartialEq, Eq, Clone, Default)] @@ -62,17 +72,6 @@ pub struct CertActiveCheck { pub ignore_not_active_yet: bool, } -/// Helper function to convert a [`CertificateDer`] to [`mbedtls::x509::Certificate`] -pub fn rustls_cert_to_mbedtls_cert(cert: &CertificateDer) -> mbedtls::Result> { - let cert = mbedtls::x509::Certificate::from_der(cert)?; - Ok(cert) -} - -/// Converts an `mbedtls::Error` into a `rustls::Error` -pub fn mbedtls_err_into_rustls_err(err: mbedtls::Error) -> rustls::Error { - mbedtls_err_into_rustls_err_with_error_msg(err, "") -} - /// All supported signature schemas pub const SUPPORTED_SIGNATURE_SCHEMA: [SignatureScheme; 9] = [ rustls::SignatureScheme::RSA_PSS_SHA512, @@ -86,129 +85,6 @@ pub const SUPPORTED_SIGNATURE_SCHEMA: [SignatureScheme; 9] = [ rustls::SignatureScheme::RSA_PSS_SHA256, ]; -/// Converts an `mbedtls::Error` into a `rustls::Error`; may include the provided `msg` in the -/// returned error (e.g., if returning a `rustls::Error::General` error). -pub fn mbedtls_err_into_rustls_err_with_error_msg(err: mbedtls::Error, msg: &str) -> rustls::Error { - match err { - mbedtls::Error::X509InvalidSignature | - mbedtls::Error::RsaVerifyFailed => rustls::Error::InvalidCertificate(rustls::CertificateError::BadSignature), - - mbedtls::Error::X509CertUnknownFormat | - mbedtls::Error::X509BadInputData => rustls::Error::InvalidCertificate(rustls::CertificateError::BadEncoding), - - // mbedtls::Error::X509AllocFailed | - mbedtls::Error::X509BufferTooSmall | - mbedtls::Error::X509CertVerifyFailed | - mbedtls::Error::X509FatalError | - mbedtls::Error::X509FeatureUnavailable | - // mbedtls::Error::X509FileIoError | - mbedtls::Error::X509InvalidAlg | - mbedtls::Error::X509InvalidDate | - mbedtls::Error::X509InvalidExtensions | - mbedtls::Error::X509InvalidFormat | - mbedtls::Error::X509InvalidSerial | - mbedtls::Error::X509InvalidVersion | - mbedtls::Error::X509SigMismatch | - mbedtls::Error::X509UnknownOid | - mbedtls::Error::X509UnknownSigAlg | - mbedtls::Error::X509UnknownVersion => rustls::Error::InvalidCertificate(rustls::CertificateError::Other(Arc::new(err))), - - mbedtls::Error::X509InvalidName => rustls::Error::InvalidCertificate(rustls::CertificateError::NotValidForName), - - _ => rustls::Error::General(format!("{err}{sep}{msg}", sep = if msg.is_empty() {""} else {"\n"})), - } -} - -/// Helper function to convert rustls [`SignatureScheme`] to mbedtls [`Type`] -pub fn rustls_signature_scheme_to_mbedtls_hash_type(signature_scheme: SignatureScheme) -> Type { - match signature_scheme { - SignatureScheme::RSA_PKCS1_SHA1 => Type::Sha1, - SignatureScheme::ECDSA_SHA1_Legacy => Type::Sha1, - SignatureScheme::RSA_PKCS1_SHA256 => Type::Sha256, - SignatureScheme::ECDSA_NISTP256_SHA256 => Type::Sha256, - SignatureScheme::RSA_PKCS1_SHA384 => Type::Sha384, - SignatureScheme::ECDSA_NISTP384_SHA384 => Type::Sha384, - SignatureScheme::RSA_PKCS1_SHA512 => Type::Sha512, - SignatureScheme::ECDSA_NISTP521_SHA512 => Type::Sha512, - SignatureScheme::RSA_PSS_SHA256 => Type::Sha256, - SignatureScheme::RSA_PSS_SHA384 => Type::Sha384, - SignatureScheme::RSA_PSS_SHA512 => Type::Sha512, - SignatureScheme::ED25519 => Type::None, - SignatureScheme::ED448 => Type::None, - SignatureScheme::Unknown(_) => Type::None, - _ => Type::None, - } -} - -/// Helper function to convert rustls [`SignatureScheme`] to mbedtls [`mbedtls::pk::Options`] -pub fn rustls_signature_scheme_to_mbedtls_pk_options(signature_scheme: SignatureScheme) -> Option { - use mbedtls::pk::Options; - use mbedtls::pk::RsaPadding; - // reference: https://www.rfc-editor.org/rfc/rfc8446.html#section-4.2.3 - match signature_scheme { - SignatureScheme::RSA_PKCS1_SHA1 => None, - SignatureScheme::ECDSA_SHA1_Legacy => None, - SignatureScheme::ECDSA_NISTP256_SHA256 => None, - SignatureScheme::ECDSA_NISTP384_SHA384 => None, - SignatureScheme::ECDSA_NISTP521_SHA512 => None, - SignatureScheme::RSA_PKCS1_SHA256 | SignatureScheme::RSA_PKCS1_SHA384 | SignatureScheme::RSA_PKCS1_SHA512 => { - Some(Options::Rsa { padding: RsaPadding::Pkcs1V15 }) - } - SignatureScheme::RSA_PSS_SHA256 => Some(Options::Rsa { padding: RsaPadding::Pkcs1V21 { mgf: Type::Sha256 } }), - SignatureScheme::RSA_PSS_SHA384 => Some(Options::Rsa { padding: RsaPadding::Pkcs1V21 { mgf: Type::Sha384 } }), - SignatureScheme::RSA_PSS_SHA512 => Some(Options::Rsa { padding: RsaPadding::Pkcs1V21 { mgf: Type::Sha512 } }), - SignatureScheme::ED25519 => None, - SignatureScheme::ED448 => None, - SignatureScheme::Unknown(_) => None, - _ => None, - } -} - -/// Helper function to convert rustls [`SignatureScheme`] to mbedtls [`mbedtls::pk::EcGroupId`] -pub fn rustls_signature_scheme_to_mbedtls_curve_id(signature_scheme: SignatureScheme) -> mbedtls::pk::EcGroupId { - // reference: https://www.rfc-editor.org/rfc/rfc8446.html#section-4.2.3 - use mbedtls::pk::EcGroupId; - match signature_scheme { - SignatureScheme::ECDSA_NISTP256_SHA256 => EcGroupId::SecP256R1, - SignatureScheme::ECDSA_NISTP384_SHA384 => EcGroupId::SecP384R1, - SignatureScheme::ECDSA_NISTP521_SHA512 => EcGroupId::SecP521R1, - SignatureScheme::ECDSA_SHA1_Legacy => EcGroupId::None, - SignatureScheme::RSA_PKCS1_SHA1 => EcGroupId::None, - SignatureScheme::RSA_PKCS1_SHA256 => EcGroupId::None, - SignatureScheme::RSA_PKCS1_SHA384 => EcGroupId::None, - SignatureScheme::RSA_PKCS1_SHA512 => EcGroupId::None, - SignatureScheme::RSA_PSS_SHA256 => EcGroupId::None, - SignatureScheme::RSA_PSS_SHA384 => EcGroupId::None, - SignatureScheme::RSA_PSS_SHA512 => EcGroupId::None, - SignatureScheme::ED25519 => EcGroupId::None, - SignatureScheme::ED448 => EcGroupId::None, - SignatureScheme::Unknown(_) => EcGroupId::None, - _ => EcGroupId::None, - } -} - -/// Returns the size of the message digest given the hash type. -fn hash_size_bytes(hash_type: Type) -> Option { - match hash_type { - mbedtls::hash::Type::None => None, - mbedtls::hash::Type::Md2 => Some(16), - mbedtls::hash::Type::Md4 => Some(16), - mbedtls::hash::Type::Md5 => Some(16), - mbedtls::hash::Type::Sha1 => Some(20), - mbedtls::hash::Type::Sha224 => Some(28), - mbedtls::hash::Type::Sha256 => Some(32), - mbedtls::hash::Type::Sha384 => Some(48), - mbedtls::hash::Type::Sha512 => Some(64), - mbedtls::hash::Type::Ripemd => Some(20), // this is MD_RIPEMD160 - } -} - -/// Returns the a ready to use empty [`Vec`] for the message digest with given hash type. -pub fn buffer_for_hash_type(hash_type: Type) -> Option> { - let size = hash_size_bytes(hash_type)?; - Some(vec![0; size]) -} - /// Verifies that certificates are active, i.e., `now` is between not_before and not_after for /// each certificate fn verify_certificates_active<'a>( @@ -259,11 +135,11 @@ fn verify_tls_signature( ) -> Result { let mut cert = rustls_cert_to_mbedtls_cert(cert).map_err(mbedtls_err_into_rustls_err)?; let pk = cert.public_key_mut(); - let hash_type = rustls_signature_scheme_to_mbedtls_hash_type(dss.scheme); + let hash_type = utils::hash::rustls_signature_scheme_to_mbedtls_hash_type(dss.scheme); - // for tls 1.3, we need to verify the advertised curve in signaure scheme matches the public key + // for tls 1.3, we need to verify the advertised curve in signature scheme matches the public key if is_tls13 { - let signature_curve = rustls_signature_scheme_to_mbedtls_curve_id(dss.scheme); + let signature_curve = utils::pk::rustls_signature_scheme_to_mbedtls_curve_id(dss.scheme); match signature_curve { mbedtls::pk::EcGroupId::None => (), _ => { @@ -279,14 +155,21 @@ fn verify_tls_signature( } } - if let Some(opts) = rustls_signature_scheme_to_mbedtls_pk_options(dss.scheme) { + if let Some(opts) = utils::pk::rustls_signature_scheme_to_mbedtls_pk_options(dss.scheme) { pk.set_options(opts); } - let mut hash = buffer_for_hash_type(hash_type).ok_or_else(|| rustls::Error::General("unexpected hash type".into()))?; + let mut hash = + utils::hash::buffer_for_hash_type(hash_type).ok_or_else(|| rustls::Error::General("unexpected hash type".into()))?; let hash_size = mbedtls::hash::Md::hash(hash_type, message, &mut hash).map_err(mbedtls_err_into_rustls_err)?; pk.verify(hash_type, &hash[..hash_size], dss.signature()) .map_err(mbedtls_err_into_rustls_err)?; Ok(rustls::client::danger::HandshakeSignatureValid::assertion()) } + +/// Helper function to convert a [`CertificateDer`] to [`mbedtls::x509::Certificate`] +pub fn rustls_cert_to_mbedtls_cert(cert: &CertificateDer) -> mbedtls::Result> { + let cert = mbedtls::x509::Certificate::from_der(cert)?; + Ok(cert) +} diff --git a/rustls-mbedpki-provider/src/server_cert_verifier.rs b/rustls-mbedpki-provider/src/server_cert_verifier.rs index 8d23718..ac4ee17 100644 --- a/rustls-mbedpki-provider/src/server_cert_verifier.rs +++ b/rustls-mbedpki-provider/src/server_cert_verifier.rs @@ -5,18 +5,21 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use std::sync::Arc; - +use alloc::string::String; +use alloc::string::ToString; +use alloc::sync::Arc; +use alloc::vec; +use alloc::vec::Vec; use chrono::NaiveDateTime; use pki_types::{CertificateDer, UnixTime}; use rustls::{ client::danger::{ServerCertVerified, ServerCertVerifier}, ServerName, }; +use utils::error::mbedtls_err_into_rustls_err_with_error_msg; use crate::{ - mbedtls_err_into_rustls_err, mbedtls_err_into_rustls_err_with_error_msg, rustls_cert_to_mbedtls_cert, - verify_certificates_active, verify_tls_signature, CertActiveCheck, + mbedtls_err_into_rustls_err, rustls_cert_to_mbedtls_cert, verify_certificates_active, verify_tls_signature, CertActiveCheck, }; /// A [`rustls`] [`ServerCertVerifier`] implemented using the PKI functionality of @@ -27,6 +30,16 @@ pub struct MbedTlsServerCertVerifier { cert_active_check: CertActiveCheck, } +impl core::fmt::Debug for MbedTlsServerCertVerifier { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("MbedTlsServerCertVerifier") + .field("trusted_cas", &"..") + .field("verify_callback", &"..") + .field("cert_active_check", &self.cert_active_check) + .finish() + } +} + impl MbedTlsServerCertVerifier { /// Constructs a new [`MbedTlsServerCertVerifier`] object given the provided trusted certificate authority /// certificates. @@ -210,6 +223,16 @@ mod tests { .with_no_client_auth() } + #[test] + fn server_cert_verifier_debug() { + let root_ca = CertificateDer::from(include_bytes!("../test-data/rsa/ca.der").to_vec()); + let server_cert_verifier = MbedTlsServerCertVerifier::new([&root_ca]).unwrap(); + assert_eq!( + "MbedTlsServerCertVerifier { trusted_cas: \"..\", verify_callback: \"..\", cert_active_check: CertActiveCheck { ignore_expired: false, ignore_not_active_yet: false } }", + format!("{:?}", server_cert_verifier) + ); + } + fn test_connection_server_cert_verifier_with_invalid_certs( invalid_cert_chain: Vec>, ) -> rustls::Error { diff --git a/rustls-mbedpki-provider/src/tests_common.rs b/rustls-mbedpki-provider/src/tests_common.rs index eea0459..950f934 100644 --- a/rustls-mbedpki-provider/src/tests_common.rs +++ b/rustls-mbedpki-provider/src/tests_common.rs @@ -7,7 +7,10 @@ use std::io; -use core::ops::{Deref, DerefMut}; +use core::{ + fmt::Debug, + ops::{Deref, DerefMut}, +}; use pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, UnixTime}; use rustls::{client::danger::ServerCertVerifier, ClientConnection, ConnectionCommon, ServerConnection, SideData}; @@ -81,6 +84,15 @@ pub(crate) struct VerifierWithSupportedVerifySchemes { pub(crate) supported_verify_schemes: Vec, } +impl Debug for VerifierWithSupportedVerifySchemes { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("VerifierWithSupportedVerifySchemes") + .field("verifier", &"..") + .field("supported_verify_schemes", &self.supported_verify_schemes) + .finish() + } +} + impl ServerCertVerifier for VerifierWithSupportedVerifySchemes { fn verify_server_cert( &self, @@ -118,3 +130,21 @@ impl ServerCertVerifier for VerifierWithSupportedVerifySc self.supported_verify_schemes.clone() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn verifier_with_supported_verify_schemes_debug() { + let verifier = VerifierWithSupportedVerifySchemes { + verifier: "Sample Verifier".to_string(), + supported_verify_schemes: vec![ + rustls::SignatureScheme::RSA_PKCS1_SHA1, + rustls::SignatureScheme::ECDSA_NISTP521_SHA512, + ], + }; + + assert_eq!("VerifierWithSupportedVerifySchemes { verifier: \"..\", supported_verify_schemes: [RSA_PKCS1_SHA1, ECDSA_NISTP521_SHA512] }",format!("{:?}", verifier)); + } +} diff --git a/rustls-mbedtls-provider-utils/Cargo.toml b/rustls-mbedtls-provider-utils/Cargo.toml new file mode 100644 index 0000000..5d1033f --- /dev/null +++ b/rustls-mbedtls-provider-utils/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "rustls-mbedtls-provider-utils" +version = "0.1.0-alpha.1" +edition = "2021" +license = "MPL-2.0" +description = "Utility code used in mbedtls based provider for rustls." +homepage = "https://github.com/fortanix/rustls-mbedtls-provider" +repository = "https://github.com/fortanix/rustls-mbedtls-provider" +readme = "../README.md" +authors = ["Fortanix Inc."] +categories = ["network-programming", "cryptography"] +resolver = "2" + +[dependencies] +rustls = { version = "0.22.0-alpha.4", default-features = false } +mbedtls = { version = "0.12.0-alpha.2", default-features = false, features = [ + "std", +] } +pki-types = { package = "rustls-pki-types", version = "0.2.1", features = [ + "std", +] } + +[target.'cfg(target_env = "msvc")'.dependencies] +# mbedtls need feature `time` to build when targeting msvc +mbedtls = { version = "0.12.0-alpha.2", default-features = false, features = [ + "std", + "time", +] } diff --git a/rustls-mbedtls-provider-utils/src/error.rs b/rustls-mbedtls-provider-utils/src/error.rs new file mode 100644 index 0000000..06b1861 --- /dev/null +++ b/rustls-mbedtls-provider-utils/src/error.rs @@ -0,0 +1,109 @@ +use alloc::{format, sync::Arc}; + +/// Converts an `mbedtls::Error` into a `rustls::Error` +pub fn mbedtls_err_into_rustls_err(err: mbedtls::Error) -> rustls::Error { + mbedtls_err_into_rustls_err_with_error_msg(err, "") +} + +/// Converts an `mbedtls::Error` into a `rustls::Error`; may include the provided `msg` in the +/// returned error (e.g., if returning a `rustls::Error::General` error). +pub fn mbedtls_err_into_rustls_err_with_error_msg(err: mbedtls::Error, msg: &str) -> rustls::Error { + match err { + mbedtls::Error::X509InvalidSignature | + mbedtls::Error::RsaVerifyFailed => rustls::Error::InvalidCertificate(rustls::CertificateError::BadSignature), + + mbedtls::Error::X509CertUnknownFormat | + mbedtls::Error::X509BadInputData => rustls::Error::InvalidCertificate(rustls::CertificateError::BadEncoding), + + // mbedtls::Error::X509AllocFailed | + mbedtls::Error::X509BufferTooSmall | + mbedtls::Error::X509CertVerifyFailed | + mbedtls::Error::X509FatalError | + mbedtls::Error::X509FeatureUnavailable | + // mbedtls::Error::X509FileIoError | + mbedtls::Error::X509InvalidAlg | + mbedtls::Error::X509InvalidDate | + mbedtls::Error::X509InvalidExtensions | + mbedtls::Error::X509InvalidFormat | + mbedtls::Error::X509InvalidSerial | + mbedtls::Error::X509InvalidVersion | + mbedtls::Error::X509SigMismatch | + mbedtls::Error::X509UnknownOid | + mbedtls::Error::X509UnknownSigAlg | + mbedtls::Error::X509UnknownVersion => rustls::Error::InvalidCertificate(rustls::CertificateError::Other(Arc::new(err))), + + mbedtls::Error::X509InvalidName => rustls::Error::InvalidCertificate(rustls::CertificateError::NotValidForName), + + _ => rustls::Error::General(format!("{err}{sep}{msg}", sep = if msg.is_empty() {""} else {"\n"})), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rustls::CertificateError; + + #[test] + fn test_mbedtls_err_into_rustls_err() { + assert_eq!( + mbedtls_err_into_rustls_err(mbedtls::Error::X509InvalidSignature), + rustls::Error::InvalidCertificate(CertificateError::BadSignature) + ); + assert_eq!( + mbedtls_err_into_rustls_err(mbedtls::Error::RsaVerifyFailed), + rustls::Error::InvalidCertificate(CertificateError::BadSignature) + ); + assert_eq!( + mbedtls_err_into_rustls_err(mbedtls::Error::X509BadInputData), + rustls::Error::InvalidCertificate(CertificateError::BadEncoding) + ); + assert_eq!( + mbedtls_err_into_rustls_err(mbedtls::Error::X509CertUnknownFormat), + rustls::Error::InvalidCertificate(CertificateError::BadEncoding) + ); + assert_eq!( + mbedtls_err_into_rustls_err(mbedtls::Error::X509InvalidName), + rustls::Error::InvalidCertificate(CertificateError::NotValidForName) + ); + } + + #[test] + fn test_mbedtls_err_into_rustls_err_with_error_msg() { + assert_eq!( + mbedtls_err_into_rustls_err_with_error_msg(mbedtls::Error::X509InvalidSignature, ""), + rustls::Error::InvalidCertificate(CertificateError::BadSignature) + ); + assert_eq!( + mbedtls_err_into_rustls_err_with_error_msg(mbedtls::Error::CipherAuthFailed, ""), + rustls::Error::General(String::from("mbedTLS error CipherAuthFailed")) + ); + assert_eq!( + mbedtls_err_into_rustls_err_with_error_msg(mbedtls::Error::RsaVerifyFailed, ""), + rustls::Error::InvalidCertificate(CertificateError::BadSignature) + ); + assert_eq!( + mbedtls_err_into_rustls_err_with_error_msg(mbedtls::Error::X509InvalidName, ""), + rustls::Error::InvalidCertificate(CertificateError::NotValidForName) + ); + assert_eq!( + format!( + "{:?}", + mbedtls_err_into_rustls_err_with_error_msg(mbedtls::Error::X509UnknownVersion, "") + ), + format!( + "{:?}", + rustls::Error::InvalidCertificate(CertificateError::Other(Arc::new(mbedtls::Error::X509UnknownVersion))) + ) + ); + assert_eq!( + format!( + "{:?}", + mbedtls_err_into_rustls_err_with_error_msg(mbedtls::Error::X509InvalidSerial, "Invalid serial number") + ), + format!( + "{:?}", + rustls::Error::InvalidCertificate(CertificateError::Other(Arc::new(mbedtls::Error::X509InvalidSerial))) + ) + ); + } +} diff --git a/rustls-mbedtls-provider-utils/src/hash.rs b/rustls-mbedtls-provider-utils/src/hash.rs new file mode 100644 index 0000000..32423c2 --- /dev/null +++ b/rustls-mbedtls-provider-utils/src/hash.rs @@ -0,0 +1,143 @@ +use alloc::vec; +use alloc::vec::Vec; +use mbedtls::hash::Type; +use rustls::SignatureScheme; + +/// Returns the size of the message digest given the hash type. +fn hash_size_bytes(hash_type: Type) -> Option { + match hash_type { + Type::None => None, + Type::Md2 => Some(16), + Type::Md4 => Some(16), + Type::Md5 => Some(16), + Type::Sha1 => Some(160 / 8), + Type::Sha224 => Some(224 / 8), + Type::Sha256 => Some(256 / 8), + Type::Sha384 => Some(384 / 8), + Type::Sha512 => Some(512 / 8), + Type::Ripemd => Some(160 / 8), // this is MD_RIPEMD160 + } +} + +/// Returns the a ready to use empty [`Vec`] for the message digest with given hash type. +pub fn buffer_for_hash_type(hash_type: Type) -> Option> { + let size = hash_size_bytes(hash_type)?; + Some(vec![0; size]) +} + +/// Helper function to convert rustls [`SignatureScheme`] to mbedtls [`Type`] +pub fn rustls_signature_scheme_to_mbedtls_hash_type(signature_scheme: SignatureScheme) -> Type { + match signature_scheme { + SignatureScheme::RSA_PKCS1_SHA1 => Type::Sha1, + SignatureScheme::ECDSA_SHA1_Legacy => Type::Sha1, + SignatureScheme::RSA_PKCS1_SHA256 => Type::Sha256, + SignatureScheme::ECDSA_NISTP256_SHA256 => Type::Sha256, + SignatureScheme::RSA_PKCS1_SHA384 => Type::Sha384, + SignatureScheme::ECDSA_NISTP384_SHA384 => Type::Sha384, + SignatureScheme::RSA_PKCS1_SHA512 => Type::Sha512, + SignatureScheme::ECDSA_NISTP521_SHA512 => Type::Sha512, + SignatureScheme::RSA_PSS_SHA256 => Type::Sha256, + SignatureScheme::RSA_PSS_SHA384 => Type::Sha384, + SignatureScheme::RSA_PSS_SHA512 => Type::Sha512, + SignatureScheme::ED25519 => Type::None, + SignatureScheme::ED448 => Type::None, + SignatureScheme::Unknown(_) => Type::None, + _ => Type::None, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_hash_size_bytes() { + assert_eq!(hash_size_bytes(Type::None), None); + assert_eq!(hash_size_bytes(Type::Md2), Some(16)); + assert_eq!(hash_size_bytes(Type::Md4), Some(16)); + assert_eq!(hash_size_bytes(Type::Md5), Some(16)); + assert_eq!(hash_size_bytes(Type::Sha1), Some(20)); + assert_eq!(hash_size_bytes(Type::Sha224), Some(224 / 8)); + assert_eq!(hash_size_bytes(Type::Sha256), Some(256 / 8)); + assert_eq!(hash_size_bytes(Type::Sha384), Some(384 / 8)); + assert_eq!(hash_size_bytes(Type::Sha512), Some(512 / 8)); + assert_eq!(hash_size_bytes(Type::Ripemd), Some(20)); + // Add more test cases if needed + } + + #[test] + fn test_buffer_for_hash_type() { + assert_eq!(buffer_for_hash_type(Type::None), None); + assert_eq!(buffer_for_hash_type(Type::Md2), Some(vec![0; 16])); + assert_eq!(buffer_for_hash_type(Type::Md4), Some(vec![0; 16])); + assert_eq!(buffer_for_hash_type(Type::Md5), Some(vec![0; 16])); + assert_eq!(buffer_for_hash_type(Type::Sha1), Some(vec![0; 20])); + assert_eq!(buffer_for_hash_type(Type::Sha224), Some(vec![0; 28])); + assert_eq!(buffer_for_hash_type(Type::Sha256), Some(vec![0; 32])); + assert_eq!(buffer_for_hash_type(Type::Sha384), Some(vec![0; 48])); + assert_eq!(buffer_for_hash_type(Type::Sha512), Some(vec![0; 64])); + assert_eq!(buffer_for_hash_type(Type::Ripemd), Some(vec![0; 20])); + // Add more test cases if needed + } + + #[test] + fn test_rustls_signature_scheme_to_mbedtls_hash_type() { + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::RSA_PKCS1_SHA1), + Type::Sha1 + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::ECDSA_SHA1_Legacy), + Type::Sha1 + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::RSA_PKCS1_SHA256), + Type::Sha256 + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::ECDSA_NISTP256_SHA256), + Type::Sha256 + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::RSA_PKCS1_SHA384), + Type::Sha384 + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::ECDSA_NISTP384_SHA384), + Type::Sha384 + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::RSA_PKCS1_SHA512), + Type::Sha512 + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::ECDSA_NISTP521_SHA512), + Type::Sha512 + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::RSA_PSS_SHA256), + Type::Sha256 + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::RSA_PSS_SHA384), + Type::Sha384 + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::RSA_PSS_SHA512), + Type::Sha512 + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::ED25519), + Type::None + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::ED448), + Type::None + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_hash_type(SignatureScheme::Unknown(100)), + Type::None + ); + // Add more test cases if needed + } +} diff --git a/rustls-mbedtls-provider-utils/src/lib.rs b/rustls-mbedtls-provider-utils/src/lib.rs new file mode 100644 index 0000000..a30ad5a --- /dev/null +++ b/rustls-mbedtls-provider-utils/src/lib.rs @@ -0,0 +1,40 @@ +//! This crate provides common util code used in `rustls-mbedcrypto-provider` and `rustls-mbedpki-provider` + +// Require docs for public APIs, deny unsafe code, etc. +#![forbid(unsafe_code, unused_must_use)] +#![cfg_attr(not(bench), forbid(unstable_features))] +#![deny( + clippy::alloc_instead_of_core, + clippy::clone_on_ref_ptr, + clippy::std_instead_of_core, + clippy::use_self, + clippy::upper_case_acronyms, + trivial_casts, + trivial_numeric_casts, + missing_docs, + unreachable_pub, + unused_import_braces, + unused_extern_crates, + unused_qualifications +)] +// Enable documentation for all features on docs.rs +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(bench, feature(test))] +#![cfg_attr(not(test), no_std)] + +extern crate alloc; + +// This `extern crate` plus the `#![no_std]` attribute changes the default prelude from +// `std::prelude` to `core::prelude`. That forces one to _explicitly_ import (`use`) everything that +// is in `std::prelude` but not in `core::prelude`. This helps maintain no-std support as even +// developers that are not interested in, or aware of, no-std support and / or that never run +// `cargo build --no-default-features` locally will get errors when they rely on `std::prelude` API. +#[cfg(not(test))] +extern crate std; + +/// Utility code related to error types: [`mbedtls::Error`] and [`rustls::Error`] +pub mod error; +/// Utility code related to [`mbedtls::hash`] types +pub mod hash; +/// Utility code related to [`mbedtls::pk`] types +pub mod pk; diff --git a/rustls-mbedtls-provider-utils/src/pk.rs b/rustls-mbedtls-provider-utils/src/pk.rs new file mode 100644 index 0000000..cbf9b62 --- /dev/null +++ b/rustls-mbedtls-provider-utils/src/pk.rs @@ -0,0 +1,156 @@ +use mbedtls::pk::Type; +use rustls::SignatureScheme; + +/// Helper function to convert [`SignatureScheme`] to [`Type`] +pub fn rustls_signature_scheme_to_mbedtls_pk_type(scheme: &SignatureScheme) -> Option { + match scheme { + SignatureScheme::RSA_PKCS1_SHA1 + | SignatureScheme::RSA_PKCS1_SHA256 + | SignatureScheme::RSA_PKCS1_SHA384 + | SignatureScheme::RSA_PKCS1_SHA512 + | SignatureScheme::RSA_PSS_SHA384 + | SignatureScheme::RSA_PSS_SHA256 + | SignatureScheme::RSA_PSS_SHA512 => Some(Type::Rsa), + SignatureScheme::ECDSA_SHA1_Legacy + | SignatureScheme::ECDSA_NISTP256_SHA256 + | SignatureScheme::ECDSA_NISTP384_SHA384 + | SignatureScheme::ECDSA_NISTP521_SHA512 => Some(Type::Ecdsa), + SignatureScheme::ED25519 => None, + SignatureScheme::ED448 => None, + SignatureScheme::Unknown(_) => None, + _ => None, + } +} + +/// Helper function to convert rustls [`SignatureScheme`] to mbedtls [`mbedtls::pk::Options`] +pub fn rustls_signature_scheme_to_mbedtls_pk_options(signature_scheme: SignatureScheme) -> Option { + use mbedtls::pk::Options; + use mbedtls::pk::RsaPadding; + // reference: https://www.rfc-editor.org/rfc/rfc8446.html#section-4.2.3 + match signature_scheme { + SignatureScheme::RSA_PKCS1_SHA1 => None, + SignatureScheme::ECDSA_SHA1_Legacy => None, + SignatureScheme::ECDSA_NISTP256_SHA256 => None, + SignatureScheme::ECDSA_NISTP384_SHA384 => None, + SignatureScheme::ECDSA_NISTP521_SHA512 => None, + SignatureScheme::RSA_PKCS1_SHA256 | SignatureScheme::RSA_PKCS1_SHA384 | SignatureScheme::RSA_PKCS1_SHA512 => { + Some(Options::Rsa { padding: RsaPadding::Pkcs1V15 }) + } + SignatureScheme::RSA_PSS_SHA256 => { + Some(Options::Rsa { padding: RsaPadding::Pkcs1V21 { mgf: mbedtls::hash::Type::Sha256 } }) + } + SignatureScheme::RSA_PSS_SHA384 => { + Some(Options::Rsa { padding: RsaPadding::Pkcs1V21 { mgf: mbedtls::hash::Type::Sha384 } }) + } + SignatureScheme::RSA_PSS_SHA512 => { + Some(Options::Rsa { padding: RsaPadding::Pkcs1V21 { mgf: mbedtls::hash::Type::Sha512 } }) + } + SignatureScheme::ED25519 => None, + SignatureScheme::ED448 => None, + SignatureScheme::Unknown(_) => None, + _ => None, + } +} + +/// Helper function to convert rustls [`SignatureScheme`] to mbedtls [`mbedtls::pk::EcGroupId`] +pub fn rustls_signature_scheme_to_mbedtls_curve_id(signature_scheme: SignatureScheme) -> mbedtls::pk::EcGroupId { + // reference: https://www.rfc-editor.org/rfc/rfc8446.html#section-4.2.3 + use mbedtls::pk::EcGroupId; + match signature_scheme { + SignatureScheme::ECDSA_NISTP256_SHA256 => EcGroupId::SecP256R1, + SignatureScheme::ECDSA_NISTP384_SHA384 => EcGroupId::SecP384R1, + SignatureScheme::ECDSA_NISTP521_SHA512 => EcGroupId::SecP521R1, + SignatureScheme::ECDSA_SHA1_Legacy => EcGroupId::None, + SignatureScheme::RSA_PKCS1_SHA1 => EcGroupId::None, + SignatureScheme::RSA_PKCS1_SHA256 => EcGroupId::None, + SignatureScheme::RSA_PKCS1_SHA384 => EcGroupId::None, + SignatureScheme::RSA_PKCS1_SHA512 => EcGroupId::None, + SignatureScheme::RSA_PSS_SHA256 => EcGroupId::None, + SignatureScheme::RSA_PSS_SHA384 => EcGroupId::None, + SignatureScheme::RSA_PSS_SHA512 => EcGroupId::None, + SignatureScheme::ED25519 => EcGroupId::None, + SignatureScheme::ED448 => EcGroupId::None, + SignatureScheme::Unknown(_) => EcGroupId::None, + _ => EcGroupId::None, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_rustls_signature_scheme_to_mbedtls_pk_type() { + let test_data = [ + ( + Some(Type::Rsa), + vec![ + SignatureScheme::RSA_PKCS1_SHA1, + SignatureScheme::RSA_PKCS1_SHA256, + SignatureScheme::RSA_PKCS1_SHA384, + SignatureScheme::RSA_PKCS1_SHA512, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA256, + SignatureScheme::RSA_PSS_SHA512, + ], + ), + ( + Some(Type::Ecdsa), + vec![ + SignatureScheme::ECDSA_SHA1_Legacy, + SignatureScheme::ECDSA_NISTP256_SHA256, + SignatureScheme::ECDSA_NISTP384_SHA384, + SignatureScheme::ECDSA_NISTP521_SHA512, + ], + ), + ( + None, + vec![ + SignatureScheme::ED25519, + SignatureScheme::ED448, + SignatureScheme::Unknown(100), + ], + ), + ]; + + for pair in &test_data { + for scheme in &pair.1 { + assert_eq!(pair.0, rustls_signature_scheme_to_mbedtls_pk_type(scheme)); + } + } + } + + #[test] + fn test_rustls_signature_scheme_to_mbedtls_curve_id() { + assert_eq!( + rustls_signature_scheme_to_mbedtls_curve_id(SignatureScheme::ECDSA_NISTP256_SHA256), + mbedtls::pk::EcGroupId::SecP256R1 + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_curve_id(SignatureScheme::ECDSA_NISTP384_SHA384), + mbedtls::pk::EcGroupId::SecP384R1 + ); + assert_eq!( + rustls_signature_scheme_to_mbedtls_curve_id(SignatureScheme::ECDSA_NISTP521_SHA512), + mbedtls::pk::EcGroupId::SecP521R1 + ); + for scheme in [ + SignatureScheme::ECDSA_SHA1_Legacy, + SignatureScheme::RSA_PKCS1_SHA1, + SignatureScheme::RSA_PKCS1_SHA256, + SignatureScheme::RSA_PKCS1_SHA384, + SignatureScheme::RSA_PKCS1_SHA512, + SignatureScheme::RSA_PSS_SHA256, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA512, + SignatureScheme::ED25519, + SignatureScheme::ED448, + SignatureScheme::Unknown(123), + ] { + assert_eq!( + rustls_signature_scheme_to_mbedtls_curve_id(scheme), + mbedtls::pk::EcGroupId::None + ); + } + } +}