use rustls::crypto::tls12::PrfUsingHmac;
use rustls::crypto::tls13::HkdfUsingHmac;
use rustls::crypto::{CipherSuiteCommon, KeyExchangeAlgorithm};
use rustls::{CipherSuite, SignatureScheme, SupportedCipherSuite};
use crate::{aead, hash, hmac, quic};
pub static ALL: &[SupportedCipherSuite] = &[
TLS13_AES_256_GCM_SHA384,
TLS13_AES_128_GCM_SHA256,
TLS13_CHACHA20_POLY1305_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_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,
];
pub static TLS13_AES_256_GCM_SHA384: SupportedCipherSuite =
SupportedCipherSuite::Tls13(&rustls::Tls13CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS13_AES_256_GCM_SHA384,
hash_provider: &hash::SHA384,
confidentiality_limit: 1 << 24,
},
hkdf_provider: &HkdfUsingHmac(&hmac::SHA384),
aead_alg: &aead::TLS13_AES_256_GCM,
quic: Some(&quic::AES_256_GCM),
});
pub static TLS13_AES_128_GCM_SHA256: SupportedCipherSuite =
SupportedCipherSuite::Tls13(&rustls::Tls13CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS13_AES_128_GCM_SHA256,
hash_provider: &hash::SHA256,
confidentiality_limit: 1 << 24,
},
hkdf_provider: &HkdfUsingHmac(&hmac::SHA256),
aead_alg: &aead::TLS13_AES_128_GCM,
quic: Some(&quic::AES_128_GCM),
});
pub static TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
SupportedCipherSuite::Tls13(&rustls::Tls13CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS13_CHACHA20_POLY1305_SHA256,
hash_provider: &hash::SHA256,
confidentiality_limit: u64::MAX,
},
hkdf_provider: &HkdfUsingHmac(&hmac::SHA256),
aead_alg: &aead::TLS13_CHACHA20_POLY1305,
quic: Some(&quic::CHACHA20_POLY1305),
});
pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
hash_provider: &hash::SHA384,
confidentiality_limit: 1 << 23,
},
prf_provider: &PrfUsingHmac(&hmac::SHA384),
kx: KeyExchangeAlgorithm::ECDHE,
sign: TLS12_ECDSA_SCHEMES,
aead_alg: &aead::TLS12_AES_256_GCM,
});
pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
hash_provider: &hash::SHA256,
confidentiality_limit: 1 << 23,
},
prf_provider: &PrfUsingHmac(&hmac::SHA256),
kx: KeyExchangeAlgorithm::ECDHE,
sign: TLS12_ECDSA_SCHEMES,
aead_alg: &aead::TLS12_AES_128_GCM,
});
pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
hash_provider: &hash::SHA256,
confidentiality_limit: u64::MAX,
},
prf_provider: &PrfUsingHmac(&hmac::SHA256),
kx: KeyExchangeAlgorithm::ECDHE,
sign: TLS12_ECDSA_SCHEMES,
aead_alg: &aead::TLS12_CHACHA20_POLY1305,
});
pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
hash_provider: &hash::SHA384,
confidentiality_limit: 1 << 23,
},
prf_provider: &PrfUsingHmac(&hmac::SHA384),
kx: KeyExchangeAlgorithm::ECDHE,
sign: TLS12_RSA_SCHEMES,
aead_alg: &aead::TLS12_AES_256_GCM,
});
pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
hash_provider: &hash::SHA256,
confidentiality_limit: 1 << 23,
},
prf_provider: &PrfUsingHmac(&hmac::SHA256),
kx: KeyExchangeAlgorithm::ECDHE,
sign: TLS12_RSA_SCHEMES,
aead_alg: &aead::TLS12_AES_128_GCM,
});
pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
hash_provider: &hash::SHA256,
confidentiality_limit: u64::MAX,
},
prf_provider: &PrfUsingHmac(&hmac::SHA256),
kx: KeyExchangeAlgorithm::ECDHE,
sign: TLS12_RSA_SCHEMES,
aead_alg: &aead::TLS12_CHACHA20_POLY1305,
});
static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[
SignatureScheme::ED25519,
SignatureScheme::ECDSA_NISTP384_SHA384,
SignatureScheme::ECDSA_NISTP256_SHA256,
];
static TLS12_RSA_SCHEMES: &[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,
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_advertised_schemes_are_all_verifiable() {
let mapped: alloc::vec::Vec<SignatureScheme> = crate::SUPPORTED_SIG_ALGS
.mapping
.iter()
.map(|(scheme, _)| *scheme)
.collect();
let mut checked = 0;
for suite in ALL {
let SupportedCipherSuite::Tls12(t) = suite else {
continue;
};
for scheme in t.sign {
assert!(
mapped.contains(scheme),
"{:?} advertises {scheme:?}, which nothing here verifies",
suite.suite()
);
checked += 1;
}
}
assert!(checked >= 27, "only {checked} advertised schemes examined");
}
#[test]
fn each_suite_uses_the_hash_it_is_named_for() {
use rustls::crypto::hash::HashAlgorithm;
for (suite, want) in [
(&TLS13_AES_256_GCM_SHA384, HashAlgorithm::SHA384),
(&TLS13_AES_128_GCM_SHA256, HashAlgorithm::SHA256),
(
&TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
HashAlgorithm::SHA384,
),
(
&TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
HashAlgorithm::SHA256,
),
(&TLS13_CHACHA20_POLY1305_SHA256, HashAlgorithm::SHA256),
(
&TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
HashAlgorithm::SHA256,
),
(
&TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
HashAlgorithm::SHA384,
),
(
&TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
HashAlgorithm::SHA256,
),
(
&TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
HashAlgorithm::SHA256,
),
] {
let got = match suite {
SupportedCipherSuite::Tls13(t) => t.common.hash_provider.algorithm(),
SupportedCipherSuite::Tls12(t) => t.common.hash_provider.algorithm(),
};
assert_eq!(got, want, "{:?} uses the wrong hash", suite.suite());
}
}
#[test]
fn the_suites_are_ordered_and_distinct() {
let names: alloc::vec::Vec<CipherSuite> = ALL.iter().map(|s| s.suite()).collect();
assert_eq!(names.len(), 9);
for (i, a) in names.iter().enumerate() {
assert!(!names[i + 1..].contains(a), "{a:?} is listed twice");
}
assert_eq!(names[0], CipherSuite::TLS13_AES_256_GCM_SHA384);
assert_eq!(names[1], CipherSuite::TLS13_AES_128_GCM_SHA256);
assert_eq!(names[2], CipherSuite::TLS13_CHACHA20_POLY1305_SHA256);
let first_12 = ALL
.iter()
.position(|s| matches!(s, SupportedCipherSuite::Tls12(_)))
.expect("there are TLS 1.2 suites");
assert!(
ALL[first_12..]
.iter()
.all(|s| matches!(s, SupportedCipherSuite::Tls12(_))),
"the TLS 1.3 and TLS 1.2 suites are interleaved"
);
}
}