#![forbid(unsafe_code)]
#![deny(missing_docs)]
#![warn(clippy::all)]
extern crate alloc;
mod aead;
mod hash;
mod hmac;
mod kx;
mod quic;
mod sign;
mod verify;
use alloc::sync::Arc;
use rustls::crypto::{CryptoProvider, SupportedKxGroup, WebPkiSupportedAlgorithms};
use rustls::pki_types::SignatureVerificationAlgorithm;
use rustls::{SignatureScheme, SupportedCipherSuite};
pub mod random;
pub mod suites;
pub fn provider() -> CryptoProvider {
CryptoProvider {
cipher_suites: default_cipher_suites().to_vec(),
kx_groups: default_kx_groups().to_vec(),
signature_verification_algorithms: SUPPORTED_SIG_ALGS,
secure_random: &random::Random,
key_provider: &sign::Keys,
}
}
pub fn default_cipher_suites() -> &'static [SupportedCipherSuite] {
suites::ALL
}
pub fn default_kx_groups() -> &'static [&'static dyn SupportedKxGroup] {
KX_GROUPS
}
static KX_GROUPS: &[&dyn SupportedKxGroup] = &[&kx::X25519, &kx::SECP256R1, &kx::SECP384R1];
pub static SUPPORTED_SIG_ALGS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms {
all: &[
&verify::ECDSA_P256_SHA256 as &dyn SignatureVerificationAlgorithm,
&verify::ECDSA_P384_SHA384 as &dyn SignatureVerificationAlgorithm,
&verify::ED25519 as &dyn SignatureVerificationAlgorithm,
&verify::RSA_PKCS1_SHA256 as &dyn SignatureVerificationAlgorithm,
&verify::RSA_PKCS1_SHA384 as &dyn SignatureVerificationAlgorithm,
&verify::RSA_PKCS1_SHA512 as &dyn SignatureVerificationAlgorithm,
&verify::RSA_PSS_SHA256 as &dyn SignatureVerificationAlgorithm,
&verify::RSA_PSS_SHA384 as &dyn SignatureVerificationAlgorithm,
&verify::RSA_PSS_SHA512 as &dyn SignatureVerificationAlgorithm,
],
mapping: &[
(
SignatureScheme::ECDSA_NISTP384_SHA384,
&[&verify::ECDSA_P384_SHA384 as &dyn SignatureVerificationAlgorithm],
),
(
SignatureScheme::ECDSA_NISTP256_SHA256,
&[&verify::ECDSA_P256_SHA256 as &dyn SignatureVerificationAlgorithm],
),
(
SignatureScheme::ED25519,
&[&verify::ED25519 as &dyn SignatureVerificationAlgorithm],
),
(
SignatureScheme::RSA_PSS_SHA512,
&[&verify::RSA_PSS_SHA512 as &dyn SignatureVerificationAlgorithm],
),
(
SignatureScheme::RSA_PSS_SHA384,
&[&verify::RSA_PSS_SHA384 as &dyn SignatureVerificationAlgorithm],
),
(
SignatureScheme::RSA_PSS_SHA256,
&[&verify::RSA_PSS_SHA256 as &dyn SignatureVerificationAlgorithm],
),
(
SignatureScheme::RSA_PKCS1_SHA512,
&[&verify::RSA_PKCS1_SHA512 as &dyn SignatureVerificationAlgorithm],
),
(
SignatureScheme::RSA_PKCS1_SHA384,
&[&verify::RSA_PKCS1_SHA384 as &dyn SignatureVerificationAlgorithm],
),
(
SignatureScheme::RSA_PKCS1_SHA256,
&[&verify::RSA_PKCS1_SHA256 as &dyn SignatureVerificationAlgorithm],
),
],
};
pub fn arc_provider() -> Arc<CryptoProvider> {
Arc::new(provider())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_provider_offers_what_it_says_it_does() {
let p = provider();
assert_eq!(p.cipher_suites.len(), 9, "{:?}", p.cipher_suites);
let names: alloc::vec::Vec<_> = p
.cipher_suites
.iter()
.map(|s| alloc::format!("{:?}", s.suite()))
.collect();
for want in [
"TLS13_AES_256_GCM_SHA384",
"TLS13_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS13_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
] {
assert!(
names.iter().any(|n| n == want),
"{want} is missing: {names:?}"
);
}
assert_eq!(p.kx_groups.len(), 3);
assert_eq!(p.kx_groups[0].name(), rustls::NamedGroup::X25519);
assert_eq!(p.signature_verification_algorithms.all.len(), 9);
assert_eq!(p.signature_verification_algorithms.mapping.len(), 9);
}
#[test]
fn nothing_claims_fips_validation() {
let p = provider();
assert!(!p.fips(), "the provider as a whole claims validation");
let mut checked = 0;
for suite in &p.cipher_suites {
assert!(!suite.fips(), "{:?} claims validation", suite.suite());
checked += 1;
}
for group in &p.kx_groups {
assert!(!group.fips(), "{:?} claims validation", group.name());
checked += 1;
}
for alg in p.signature_verification_algorithms.all {
assert!(!alg.fips(), "a signature algorithm claims validation");
checked += 1;
}
assert!(checked >= 21, "only {checked} components examined");
}
#[test]
fn the_suites_use_this_provider_for_the_key_schedule() {
use rustls::crypto::hash::HashAlgorithm;
for suite in suites::ALL {
let hash = match suite {
SupportedCipherSuite::Tls13(t) => t.common.hash_provider,
SupportedCipherSuite::Tls12(t) => t.common.hash_provider,
};
assert!(
matches!(
hash.algorithm(),
HashAlgorithm::SHA256 | HashAlgorithm::SHA384
),
"{:?} uses an unexpected hash",
suite.suite()
);
assert!(!hash.fips());
}
}
}