#![no_std]
#![warn(clippy::exhaustive_enums, clippy::exhaustive_structs, missing_docs)]
#![cfg_attr(bench, feature(test))]
extern crate alloc;
#[cfg(any(feature = "std", test))]
extern crate std;
#[cfg(bench)]
#[expect(unused_extern_crates)]
extern crate test;
use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::sync::Arc;
#[cfg(feature = "std")]
use core::time::Duration;
use pki_types::{FipsStatus, PrivateKeyDer};
use rustls::crypto::kx::SupportedKxGroup;
use rustls::crypto::{
CryptoProvider, GetRandomFailed, KeyProvider, SecureRandom, SignatureScheme, SigningKey,
TicketProducer, TicketerFactory, WebPkiSupportedAlgorithms,
};
use rustls::error::{Error, OtherError};
#[cfg(feature = "std")]
use rustls::ticketer::TicketRotator;
use rustls::{Tls12CipherSuite, Tls13CipherSuite};
pub mod hpke;
pub mod sign;
use sign::{EcdsaSigner, Ed25519Signer, RsaSigningKey};
pub(crate) mod hash;
pub(crate) mod hmac;
pub(crate) mod kx;
pub(crate) mod quic;
#[cfg(feature = "std")]
pub(crate) mod ticketer;
#[cfg(feature = "std")]
use ticketer::Rfc5077Ticketer;
pub(crate) mod tls12;
pub(crate) mod tls13;
pub(crate) mod verify;
pub use verify::{
ALL_VERIFICATION_ALGS, ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P256_SHA512,
ECDSA_P384_SHA256, ECDSA_P384_SHA384, ECDSA_P384_SHA512, ECDSA_P521_SHA256, ECDSA_P521_SHA384,
ECDSA_P521_SHA512, ED25519, RSA_PKCS1_2048_8192_SHA256,
RSA_PKCS1_2048_8192_SHA256_ABSENT_PARAMS, RSA_PKCS1_2048_8192_SHA384,
RSA_PKCS1_2048_8192_SHA384_ABSENT_PARAMS, RSA_PKCS1_2048_8192_SHA512,
RSA_PKCS1_2048_8192_SHA512_ABSENT_PARAMS, RSA_PKCS1_3072_8192_SHA384,
RSA_PSS_2048_8192_SHA256_LEGACY_KEY, RSA_PSS_2048_8192_SHA384_LEGACY_KEY,
RSA_PSS_2048_8192_SHA512_LEGACY_KEY,
};
#[cfg(all(feature = "unstable", not(feature = "fips")))]
pub use verify::{ML_DSA_44, ML_DSA_65, ML_DSA_87};
#[cfg(feature = "fips")]
pub const DEFAULT_FIPS_PROVIDER: CryptoProvider = DEFAULT_PROVIDER;
pub const DEFAULT_PROVIDER: CryptoProvider = CryptoProvider {
tls12_cipher_suites: Cow::Borrowed(DEFAULT_TLS12_CIPHER_SUITES),
tls13_cipher_suites: Cow::Borrowed(DEFAULT_TLS13_CIPHER_SUITES),
kx_groups: Cow::Borrowed(DEFAULT_KX_GROUPS),
signature_verification_algorithms: SUPPORTED_SIG_ALGS,
secure_random: &AwsLcRs,
key_provider: &AwsLcRs,
ticketer_factory: &AwsLcRs,
};
pub const DEFAULT_TLS13_PROVIDER: CryptoProvider = CryptoProvider {
tls12_cipher_suites: Cow::Borrowed(&[]),
..DEFAULT_PROVIDER
};
pub const DEFAULT_TLS12_PROVIDER: CryptoProvider = CryptoProvider {
tls13_cipher_suites: Cow::Borrowed(&[]),
..DEFAULT_PROVIDER
};
pub static DEFAULT_KEY_PROVIDER: &dyn KeyProvider = &AwsLcRs;
pub static DEFAULT_SECURE_RANDOM: &dyn SecureRandom = &AwsLcRs;
#[derive(Debug)]
struct AwsLcRs;
impl SecureRandom for AwsLcRs {
fn fill(&self, buf: &mut [u8]) -> Result<(), GetRandomFailed> {
use aws_lc_rs::rand::SecureRandom;
aws_lc_rs::rand::SystemRandom::new()
.fill(buf)
.map_err(|_| GetRandomFailed)
}
fn fips(&self) -> FipsStatus {
fips()
}
}
impl KeyProvider for AwsLcRs {
fn load_private_key(
&self,
key_der: PrivateKeyDer<'static>,
) -> Result<Box<dyn SigningKey>, Error> {
if let Ok(rsa) = RsaSigningKey::try_from(&key_der) {
return Ok(Box::new(rsa));
}
if let Ok(ecdsa) = EcdsaSigner::try_from(&key_der) {
return Ok(Box::new(ecdsa));
}
if let PrivateKeyDer::Pkcs8(pkcs8) = key_der {
if let Ok(eddsa) = Ed25519Signer::try_from(&pkcs8) {
return Ok(Box::new(eddsa));
}
}
Err(Error::General(
"failed to parse private key as RSA, ECDSA, or EdDSA".into(),
))
}
fn fips(&self) -> FipsStatus {
fips()
}
}
impl TicketerFactory for AwsLcRs {
fn ticketer(&self) -> Result<Arc<dyn TicketProducer>, Error> {
#[cfg(feature = "std")]
{
Ok(Arc::new(TicketRotator::new(
SIX_HOURS,
Rfc5077Ticketer::new,
)?))
}
#[cfg(not(feature = "std"))]
{
Err(Error::General(
"AwsLcRs::ticketer() relies on std-only RwLock via TicketRotator".into(),
))
}
}
fn fips(&self) -> FipsStatus {
fips()
}
}
#[cfg(feature = "std")]
const SIX_HOURS: Duration = Duration::from_secs(6 * 60 * 60);
pub static DEFAULT_TLS12_CIPHER_SUITES: &[&Tls12CipherSuite] = &[
tls12::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls12::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
#[cfg(not(feature = "fips"))]
tls12::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
tls12::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls12::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
#[cfg(not(feature = "fips"))]
tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
];
pub static DEFAULT_TLS13_CIPHER_SUITES: &[&Tls13CipherSuite] = &[
tls13::TLS13_AES_128_GCM_SHA256,
tls13::TLS13_AES_256_GCM_SHA384,
#[cfg(not(feature = "fips"))]
tls13::TLS13_CHACHA20_POLY1305_SHA256,
];
pub static ALL_TLS12_CIPHER_SUITES: &[&Tls12CipherSuite] = &[
tls12::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls12::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls12::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
tls12::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls12::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
];
pub static ALL_TLS13_CIPHER_SUITES: &[&Tls13CipherSuite] = &[
tls13::TLS13_AES_128_GCM_SHA256,
tls13::TLS13_AES_256_GCM_SHA384,
tls13::TLS13_CHACHA20_POLY1305_SHA256,
];
pub mod cipher_suite {
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,
};
}
pub static SUPPORTED_SIG_ALGS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms {
all: &[
ECDSA_P256_SHA256,
ECDSA_P256_SHA384,
ECDSA_P256_SHA512,
ECDSA_P384_SHA256,
ECDSA_P384_SHA384,
ECDSA_P384_SHA512,
ECDSA_P521_SHA256,
ECDSA_P521_SHA384,
ECDSA_P521_SHA512,
ED25519,
RSA_PSS_2048_8192_SHA256_LEGACY_KEY,
RSA_PSS_2048_8192_SHA384_LEGACY_KEY,
RSA_PSS_2048_8192_SHA512_LEGACY_KEY,
RSA_PKCS1_2048_8192_SHA256,
RSA_PKCS1_2048_8192_SHA384,
RSA_PKCS1_2048_8192_SHA512,
RSA_PKCS1_2048_8192_SHA256_ABSENT_PARAMS,
RSA_PKCS1_2048_8192_SHA384_ABSENT_PARAMS,
RSA_PKCS1_2048_8192_SHA512_ABSENT_PARAMS,
],
mapping: &[
(
SignatureScheme::ECDSA_NISTP384_SHA384,
&[ECDSA_P384_SHA384, ECDSA_P256_SHA384, ECDSA_P521_SHA384],
),
(
SignatureScheme::ECDSA_NISTP256_SHA256,
&[ECDSA_P256_SHA256, ECDSA_P384_SHA256, ECDSA_P521_SHA256],
),
(
SignatureScheme::ECDSA_NISTP521_SHA512,
&[ECDSA_P521_SHA512, ECDSA_P384_SHA512, ECDSA_P256_SHA512],
),
(SignatureScheme::ED25519, &[ED25519]),
(
SignatureScheme::RSA_PSS_SHA512,
&[RSA_PSS_2048_8192_SHA512_LEGACY_KEY],
),
(
SignatureScheme::RSA_PSS_SHA384,
&[RSA_PSS_2048_8192_SHA384_LEGACY_KEY],
),
(
SignatureScheme::RSA_PSS_SHA256,
&[RSA_PSS_2048_8192_SHA256_LEGACY_KEY],
),
(
SignatureScheme::RSA_PKCS1_SHA512,
&[RSA_PKCS1_2048_8192_SHA512],
),
(
SignatureScheme::RSA_PKCS1_SHA384,
&[RSA_PKCS1_2048_8192_SHA384],
),
(
SignatureScheme::RSA_PKCS1_SHA256,
&[RSA_PKCS1_2048_8192_SHA256],
),
],
};
pub mod kx_group {
pub use super::kx::{
MLKEM768, SECP256R1, SECP256R1MLKEM768, SECP384R1, X25519, X25519MLKEM768,
};
}
pub static DEFAULT_KX_GROUPS: &[&dyn SupportedKxGroup] = &[
kx_group::X25519MLKEM768,
#[cfg(not(feature = "fips"))]
kx_group::X25519,
kx_group::SECP256R1,
kx_group::SECP384R1,
];
pub static ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = &[
kx_group::X25519MLKEM768,
kx_group::SECP256R1MLKEM768,
kx_group::X25519,
kx_group::SECP256R1,
kx_group::SECP384R1,
kx_group::MLKEM768,
];
mod ring_shim {
use aws_lc_rs::agreement::{self, EphemeralPrivateKey, UnparsedPublicKey};
use rustls::crypto::kx::SharedSecret;
pub(super) fn agree_ephemeral(
priv_key: EphemeralPrivateKey,
peer_key: &UnparsedPublicKey<&[u8]>,
) -> Result<SharedSecret, ()> {
agreement::agree_ephemeral(priv_key, peer_key, (), |secret| {
Ok(SharedSecret::from(secret))
})
}
}
fn fips() -> FipsStatus {
match aws_lc_rs::try_fips_mode().is_ok() {
true => FipsStatus::Pending,
false => FipsStatus::Unvalidated,
}
}
fn unspecified_err(e: aws_lc_rs::error::Unspecified) -> Error {
Error::Other(OtherError::new(e))
}
const MAX_FRAGMENT_LEN: usize = 16384;
#[cfg(test)]
mod tests {
use std::collections::HashSet;
#[cfg(feature = "fips")]
use pki_types::FipsStatus;
#[cfg(feature = "fips")]
#[test]
fn default_suites_are_fips() {
assert!(
super::DEFAULT_TLS12_CIPHER_SUITES
.iter()
.all(|scs| !matches!(scs.fips(), FipsStatus::Unvalidated))
);
assert!(
super::DEFAULT_TLS13_CIPHER_SUITES
.iter()
.all(|scs| !matches!(scs.fips(), FipsStatus::Unvalidated))
);
}
#[cfg(not(feature = "fips"))]
#[test]
fn default_suites() {
assert_eq!(
super::DEFAULT_TLS12_CIPHER_SUITES,
super::ALL_TLS12_CIPHER_SUITES
);
assert_eq!(
super::DEFAULT_TLS13_CIPHER_SUITES,
super::ALL_TLS13_CIPHER_SUITES
);
}
#[test]
fn certificate_sig_algs() {
assert_eq!(
super::SUPPORTED_SIG_ALGS
.all
.iter()
.map(|alg| {
(
alg.public_key_alg_id()
.as_ref()
.to_vec(),
alg.signature_alg_id().as_ref().to_vec(),
)
})
.collect::<HashSet<_>>()
.len(),
super::SUPPORTED_SIG_ALGS.all.len(),
);
}
}