Fix AES256 using wrong hash

Add TLS 1.2
Move aead crypter to boring-additions crate
This commit is contained in:
Jan Rüth 2023-11-20 20:36:55 +01:00
commit 319029f2d4
17 changed files with 424 additions and 51 deletions

View file

@ -1,5 +1,7 @@
[workspace]
members = [
# things that should probably be in boring crate
"boring-additions",
# the main library and tests
"boring-rustls-provider",
# tests and example code
@ -13,4 +15,6 @@ default-members = [
resolver = "2"
[workspace.dependencies]
boring = { version = "4.0", default-features = false }
boring-sys = { version = "4.0", default-features = false }
rustls = { version = "=0.22.0-alpha.4", default-features = false }

View file

@ -13,7 +13,7 @@ Further, the rustls crypto provider API is still not stable it seems. This works
Currently, supports only TLS 1.3:
```
AES_128_GCM_SHA256
AES_256_GCM_SHA256
AES_256_GCM_SHA384
CHACHA20_POLY1305_SHA256
```

View file

@ -0,0 +1,18 @@
[package]
name = "boring-additions"
version = "0.0.1"
authors = ["Jan Rüth <boring-rustls-provider@djiehmail.com>"]
edition = "2021"
license = "MIT"
description = "Boring additions"
publish = false
[dependencies]
aead = { version = "0.5", default_features = false, features = ["alloc"] }
boring = { workspace = true }
boring-sys = { workspace = true }
foreign-types = "0.5"

View file

@ -0,0 +1,187 @@
use std::ptr;
use boring::error::ErrorStack;
use crate::helper::{cvt, cvt_p};
pub struct Algorithm(*const boring_sys::EVP_AEAD);
impl Algorithm {
/// AES-128 in Galois Counter Mode.
///
/// Note: AES-GCM should only be used with 12-byte (96-bit) nonces. Although it is specified to take a variable-length nonce, nonces with other lengths are effectively randomized, which means one must consider collisions. Unless implementing an existing protocol which has already specified incorrect parameters, only use 12-byte nonces.
pub fn aes_128_gcm() -> Self {
Self(unsafe { boring_sys::EVP_aead_aes_128_gcm() })
}
/// AES-256 in Galois Counter Mode.
///
/// Note: AES-GCM should only be used with 12-byte (96-bit) nonces. Although it is specified to take a variable-length nonce, nonces with other lengths are effectively randomized, which means one must consider collisions. Unless implementing an existing protocol which has already specified incorrect parameters, only use 12-byte nonces.
pub fn aes_256_gcm() -> Self {
Self(unsafe { boring_sys::EVP_aead_aes_256_gcm() })
}
/// ChaCha20 and Poly1305 as described in RFC 8439.
pub fn chacha20_poly1305() -> Self {
Self(unsafe { boring_sys::EVP_aead_chacha20_poly1305() })
}
/// ChaCha20-Poly1305 with an extended nonce that makes random generation of nonces safe.
#[allow(unused)]
pub fn xchacha20_poly1305() -> Self {
Self(unsafe { boring_sys::EVP_aead_xchacha20_poly1305() })
}
/// Returns the length, in bytes, of the keys used by aead
pub fn key_length(&self) -> usize {
unsafe { boring_sys::EVP_AEAD_key_length(self.0) }
}
/// Returns the maximum number of additional bytes added by the act of sealing data with aead.
pub fn max_overhead(&self) -> usize {
unsafe { boring_sys::EVP_AEAD_max_overhead(self.0) }
}
/// Returns the maximum tag length when using aead.
#[allow(unused)]
pub fn max_tag_len(&self) -> usize {
unsafe { boring_sys::EVP_AEAD_max_tag_len(self.0) }
}
/// Returns the length, in bytes, of the per-message nonce for aead.
pub fn nonce_len(&self) -> usize {
unsafe { boring_sys::EVP_AEAD_nonce_length(self.0) }
}
}
pub struct Crypter {
ctx: *mut boring_sys::EVP_AEAD_CTX,
max_overhead: usize,
nonce_len: usize,
}
unsafe impl Send for Crypter {}
unsafe impl Sync for Crypter {}
impl Crypter {
pub fn new(aead_alg: Algorithm, key: &[u8]) -> Result<Self, ErrorStack> {
assert_eq!(aead_alg.key_length(), key.len());
boring_sys::init();
let this = unsafe {
Self {
ctx: cvt_p(boring_sys::EVP_AEAD_CTX_new(
aead_alg.0,
key.as_ptr(),
key.len(),
boring_sys::EVP_AEAD_DEFAULT_TAG_LENGTH as usize,
))?,
max_overhead: aead_alg.max_overhead(),
nonce_len: aead_alg.nonce_len(),
}
};
Ok(this)
}
pub fn max_overhead(&self) -> usize {
self.max_overhead
}
/// Encrypts and authenticates buffer and authenticates associated_data.
/// It writes the ciphertext to buffer and the authentication tag to tag.
/// On success, it returns the actual length of the tag
pub fn seal_in_place(
&self,
nonce: &[u8],
associated_data: &[u8],
buffer: &mut [u8],
tag: &mut [u8],
) -> Result<usize, ErrorStack> {
assert!(tag.len() >= self.max_overhead);
assert_eq!(nonce.len(), self.nonce_len);
let mut tag_len = tag.len();
unsafe {
cvt(boring_sys::EVP_AEAD_CTX_seal_scatter(
self.ctx,
buffer.as_mut_ptr(),
tag.as_mut_ptr(),
&mut tag_len,
tag.len(),
nonce.as_ptr(),
nonce.len(),
buffer.as_ptr(),
buffer.len(),
ptr::null_mut(),
0,
associated_data.as_ptr(),
associated_data.len(),
))?;
}
Ok(tag_len)
}
pub fn open_in_place(
&self,
nonce: &[u8],
associated_data: &[u8],
buffer: &mut [u8],
tag: &[u8],
) -> Result<(), ErrorStack> {
assert_eq!(nonce.len(), self.nonce_len);
unsafe {
cvt(boring_sys::EVP_AEAD_CTX_open_gather(
self.ctx,
buffer.as_mut_ptr(),
nonce.as_ptr(),
nonce.len(),
buffer.as_ptr(),
buffer.len(),
tag.as_ptr(),
tag.len(),
associated_data.as_ptr(),
associated_data.len(),
))?;
}
Ok(())
}
}
impl Drop for Crypter {
fn drop(&mut self) {
unsafe {
boring_sys::EVP_AEAD_CTX_free(self.ctx);
}
}
}
#[cfg(test)]
mod tests {
use super::Crypter;
#[test]
fn in_out() {
let key = Crypter::new(super::Algorithm::aes_128_gcm(), &[0u8; 16]).unwrap();
let nonce = [0u8; 12];
let associated_data = "this is signed".as_bytes();
let mut buffer = Vec::with_capacity(26);
buffer.push('A' as u8);
buffer.push('B' as u8);
buffer.push('C' as u8);
buffer.push('D' as u8);
buffer.push('E' as u8);
let mut tag = [0u8; 16];
key.seal_in_place(&nonce, &associated_data, buffer.as_mut_slice(), &mut tag)
.unwrap();
println!("Encrypted: {:02X?}, Tag: {:02X?}", buffer, tag);
key.open_in_place(&nonce, &associated_data, buffer.as_mut_slice(), &tag[..])
.unwrap();
println!("Plaintext: {}", String::from_utf8(buffer).unwrap());
}
}

View file

@ -0,0 +1,29 @@
use std::os::raw::c_int;
use boring::error::ErrorStack;
/// Check the value returned from a BoringSSL ffi call
/// that returns a pointer.
///
/// If the pointer is null, this method returns the BoringSSL
/// ErrorStack as Err, the pointer otherwise.
pub(crate) fn cvt_p<T>(r: *mut T) -> Result<*mut T, ErrorStack> {
if r.is_null() {
Err(ErrorStack::get())
} else {
Ok(r)
}
}
/// Check the value returned from a BoringSSL ffi call that
/// returns a integer.
///
/// Returns the BoringSSL Errorstack when the result is <= 0.
/// And forwards the return code otherwise
pub(crate) fn cvt(r: c_int) -> Result<i32, ErrorStack> {
if r <= 0 {
Err(ErrorStack::get())
} else {
Ok(r)
}
}

View file

@ -0,0 +1,2 @@
pub mod aead;
pub(crate) mod helper;

View file

@ -8,16 +8,19 @@ description = "Boringssl rustls provider"
publish = false
[features]
default = []
default = ["tls12"]
# Use a FIPS-validated version of boringssl.
#fips = ["boring/fips", "boring-sys/fips"]
logging = ["log"]
fips-only = []
tls12 = ["rustls/tls12"]
[dependencies]
aead = {version = "0.5", default_features = false, features = ["alloc"] }
boring = { version = "4.0", default-features = false }
boring-sys = { version = "4.0", default-features = false }
boring = { workspace = true }
boring-additions = { path = "../boring-additions" }
boring-sys = { workspace = true }
foreign-types = "0.5"
lazy_static = "1.4"
log = { version = "0.4.4", optional = true }

View file

@ -2,28 +2,37 @@ use std::marker::PhantomData;
use aead::{AeadCore, AeadInPlace, Nonce, Tag};
use boring::error::ErrorStack;
use rustls::crypto::cipher::{self, make_tls13_aad, Iv};
use boring_additions::aead::Algorithm;
use rustls::crypto::cipher::{self, make_tls12_aad, make_tls13_aad, Iv};
use rustls::{ConnectionTrafficSecrets, ContentType, ProtocolVersion};
use crate::helper::error_stack_to_aead_error;
use self::aead2::Algorithm;
pub(crate) mod aead2;
pub(crate) mod aes;
pub(crate) mod chacha20;
pub(crate) trait BoringCipher {
/// Constructs a new instance of this cipher as an AEAD algorithm
fn new() -> Algorithm;
/// The key size in bytes
fn key_size() -> usize;
/// The IV's fixed length (Not the full IV length, only the part that doesn't change).
/// Together with [`BoringCipher::explicit_nonce_len`] it determines the total
/// lengths of the used nonce.
fn fixed_iv_len() -> usize;
/// The lengths of the explicit nonce. (Not the full nonce length, only the part that changes)
/// See also [`BoringCipher::fixed_iv_len`]
fn explicit_nonce_len() -> usize;
/// Extract keys
fn extract_keys(key: cipher::AeadKey, iv: cipher::Iv) -> ConnectionTrafficSecrets;
}
pub(crate) trait BoringAead: BoringCipher + AeadCore + Send + Sync {}
pub(crate) struct BoringAeadCrypter<T: BoringAead> {
crypter: aead2::Crypter,
crypter: boring_additions::aead::Crypter,
iv: Iv,
tls_version: ProtocolVersion,
phantom: PhantomData<T>,
}
@ -41,7 +50,14 @@ impl<T: BoringAead> AeadCore for BoringAeadCrypter<T> {
}
impl<T: BoringAead> BoringAeadCrypter<T> {
pub fn new(iv: Iv, key: &[u8]) -> Result<Self, ErrorStack> {
pub fn new(iv: Iv, key: &[u8], tls_version: ProtocolVersion) -> Result<Self, ErrorStack> {
assert!(match tls_version {
#[cfg(feature = "tls12")]
ProtocolVersion::TLSv1_2 => true,
ProtocolVersion::TLSv1_3 => true,
_ => false,
});
let cipher = <T as BoringCipher>::new();
assert_eq!(
@ -50,8 +66,9 @@ impl<T: BoringAead> BoringAeadCrypter<T> {
);
let crypter = BoringAeadCrypter {
crypter: aead2::Crypter::new(cipher, key)?,
crypter: boring_additions::aead::Crypter::new(cipher, key)?,
iv,
tls_version,
phantom: PhantomData,
};
Ok(crypter)
@ -104,17 +121,34 @@ where
let nonce = cipher::Nonce::new(&self.iv, seq);
let aad = cipher::make_tls13_aad(total_len);
self.encrypt_in_place(Nonce::<T>::from_slice(&nonce.0), &aad, &mut payload)
.map_err(|_| rustls::Error::EncryptError)
.map(|_| {
cipher::OpaqueMessage::new(
ContentType::ApplicationData,
ProtocolVersion::TLSv1_2,
payload,
)
})
match self.tls_version {
#[cfg(feature = "tls12")]
ProtocolVersion::TLSv1_2 => {
let aad = cipher::make_tls12_aad(seq, msg.typ, msg.version, total_len);
self.encrypt_in_place(Nonce::<T>::from_slice(&nonce.0), &aad, &mut payload)
.map_err(|_| rustls::Error::EncryptError)
.map(|_| cipher::OpaqueMessage::new(msg.typ, msg.version, payload))
}
ProtocolVersion::TLSv1_3 => {
let aad = cipher::make_tls13_aad(total_len);
self.encrypt_in_place(Nonce::<T>::from_slice(&nonce.0), &aad, &mut payload)
.map_err(|_| rustls::Error::EncryptError)
.map(|_| {
cipher::OpaqueMessage::new(
ContentType::ApplicationData,
ProtocolVersion::TLSv1_2,
payload,
)
})
}
_ => unimplemented!(),
}
}
// Next version seems to add this
// fn encrypted_payload_len(&self, payload_len: usize) -> usize {
// payload_len + 1 + self.crypter.max_overhead()
// }
}
impl<T> cipher::MessageDecrypter for BoringAeadCrypter<T>
@ -126,18 +160,26 @@ where
mut m: cipher::OpaqueMessage,
seq: u64,
) -> Result<cipher::PlainMessage, rustls::Error> {
let payload = m.payload_mut();
// construct nonce
let nonce = cipher::Nonce::new(&self.iv, seq);
// construct the aad
let aad = make_tls13_aad(payload.len());
// decrypt on clone to ensure this can be done in parallel
self.decrypt_in_place(Nonce::<T>::from_slice(&nonce.0), &aad, payload)
.map_err(|_| rustls::Error::DecryptError)
.and_then(|_| m.into_tls13_unpadded_message())
// construct the aad and decrypt
match self.tls_version {
#[cfg(feature = "tls12")]
ProtocolVersion::TLSv1_2 => {
let aad = make_tls12_aad(seq, m.typ, m.version, m.payload().len());
self.decrypt_in_place(Nonce::<T>::from_slice(&nonce.0), &aad, m.payload_mut())
.map_err(|_| rustls::Error::DecryptError)
.map(|_| m.into_plain_message())
}
ProtocolVersion::TLSv1_3 => {
let aad = make_tls13_aad(m.payload().len());
self.decrypt_in_place(Nonce::<T>::from_slice(&nonce.0), &aad, m.payload_mut())
.map_err(|_| rustls::Error::DecryptError)
.and_then(|_| m.into_tls13_unpadded_message())
}
_ => unimplemented!(),
}
}
}
@ -153,13 +195,15 @@ impl<T: BoringCipher> Aead<T> {
impl<T: BoringAead + 'static> cipher::Tls13AeadAlgorithm for Aead<T> {
fn encrypter(&self, key: cipher::AeadKey, iv: cipher::Iv) -> Box<dyn cipher::MessageEncrypter> {
Box::new(
BoringAeadCrypter::<T>::new(iv, key.as_ref()).expect("failed to create AEAD crypter"),
BoringAeadCrypter::<T>::new(iv, key.as_ref(), ProtocolVersion::TLSv1_3)
.expect("failed to create AEAD crypter"),
)
}
fn decrypter(&self, key: cipher::AeadKey, iv: cipher::Iv) -> Box<dyn cipher::MessageDecrypter> {
Box::new(
BoringAeadCrypter::<T>::new(iv, key.as_ref()).expect("failed to create AEAD crypter"),
BoringAeadCrypter::<T>::new(iv, key.as_ref(), ProtocolVersion::TLSv1_3)
.expect("failed to create AEAD crypter"),
)
}
@ -175,3 +219,45 @@ impl<T: BoringAead + 'static> cipher::Tls13AeadAlgorithm for Aead<T> {
Ok(<T as BoringCipher>::extract_keys(key, iv))
}
}
#[cfg(feature = "tls12")]
impl<T: BoringAead + 'static> cipher::Tls12AeadAlgorithm for Aead<T> {
fn encrypter(
&self,
key: cipher::AeadKey,
iv: &[u8],
_extra: &[u8],
) -> Box<dyn cipher::MessageEncrypter> {
Box::new(
BoringAeadCrypter::<T>::new(Iv::copy(iv), key.as_ref(), ProtocolVersion::TLSv1_2)
.expect("failed to create AEAD crypter"),
)
}
fn decrypter(&self, key: cipher::AeadKey, iv: &[u8]) -> Box<dyn cipher::MessageDecrypter> {
Box::new(
BoringAeadCrypter::<T>::new(Iv::copy(iv), key.as_ref(), ProtocolVersion::TLSv1_2)
.expect("failed to create AEAD crypter"),
)
}
fn key_block_shape(&self) -> cipher::KeyBlockShape {
cipher::KeyBlockShape {
enc_key_len: <T as BoringCipher>::key_size(),
// there is no benefit of splitting these up here, we'd need to stich them anyways
// by only setting fixed_iv_len we get the full lengths
fixed_iv_len: <T as BoringCipher>::fixed_iv_len()
+ <T as BoringCipher>::explicit_nonce_len(),
explicit_nonce_len: 0,
}
}
fn extract_keys(
&self,
key: cipher::AeadKey,
iv: &[u8],
_explicit: &[u8],
) -> Result<ConnectionTrafficSecrets, cipher::UnsupportedOperationError> {
Ok(<T as BoringCipher>::extract_keys(key, Iv::copy(iv)))
}
}

View file

@ -1,8 +1,8 @@
use super::{BoringAead, BoringCipher};
use aead::consts::{U12, U16};
use boring_additions::aead::Algorithm;
use rustls::{crypto::cipher, ConnectionTrafficSecrets};
use super::{aead2::Algorithm, BoringAead, BoringCipher};
pub struct Aes128 {}
impl BoringAead for Aes128 {}
@ -21,6 +21,14 @@ impl BoringCipher for Aes128 {
fn extract_keys(key: cipher::AeadKey, iv: cipher::Iv) -> ConnectionTrafficSecrets {
ConnectionTrafficSecrets::Aes128Gcm { key, iv }
}
fn fixed_iv_len() -> usize {
4
}
fn explicit_nonce_len() -> usize {
8
}
}
impl aead::AeadCore for Aes128 {
@ -47,6 +55,14 @@ impl BoringCipher for Aes256 {
fn extract_keys(key: cipher::AeadKey, iv: cipher::Iv) -> ConnectionTrafficSecrets {
ConnectionTrafficSecrets::Aes256Gcm { key, iv }
}
fn fixed_iv_len() -> usize {
4
}
fn explicit_nonce_len() -> usize {
8
}
}
impl aead::AeadCore for Aes256 {

View file

@ -1,11 +1,11 @@
use super::{BoringAead, BoringCipher};
use aead::{
consts::{U12, U16},
AeadCore,
};
use boring_additions::aead::Algorithm;
use rustls::{crypto::cipher, ConnectionTrafficSecrets};
use super::{aead2::Algorithm, BoringAead, BoringCipher};
pub struct ChaCha20Poly1305 {}
impl BoringAead for ChaCha20Poly1305 {}
@ -24,6 +24,14 @@ impl BoringCipher for ChaCha20Poly1305 {
fn extract_keys(key: cipher::AeadKey, iv: cipher::Iv) -> ConnectionTrafficSecrets {
ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv }
}
fn fixed_iv_len() -> usize {
4
}
fn explicit_nonce_len() -> usize {
8
}
}
impl AeadCore for ChaCha20Poly1305 {

View file

@ -1,6 +1,7 @@
use rustls::crypto::hash;
pub const SHA256: &dyn hash::Hash = &Hash(boring::nid::Nid::SHA256);
pub const SHA384: &dyn hash::Hash = &Hash(boring::nid::Nid::SHA384);
pub struct Hash(pub boring::nid::Nid);

View file

@ -15,6 +15,13 @@ impl BoringHash for Sha256 {
}
}
pub struct Sha384();
impl BoringHash for Sha384 {
fn new() -> boring::hash::MessageDigest {
boring::hash::MessageDigest::sha384()
}
}
pub struct Hkdf<T: BoringHash>(PhantomData<T>);
impl<T: BoringHash> Hkdf<T> {

View file

@ -7,6 +7,7 @@ use crate::helper::{cvt, cvt_p};
#[allow(unused)]
pub const SHA256: &dyn crypto::hmac::Hmac = &BoringHmac(boring::nid::Nid::SHA256);
pub const SHA384: &dyn crypto::hmac::Hmac = &BoringHmac(boring::nid::Nid::SHA384);
pub struct BoringHmac(pub boring::nid::Nid);

View file

@ -13,6 +13,8 @@ mod hkdf;
mod hmac;
mod kx;
mod sign;
#[cfg(feature = "tls12")]
mod tls12;
mod tls13;
mod verify;
@ -27,17 +29,23 @@ impl CryptoProvider for Provider {
}
fn default_cipher_suites(&self) -> &'static [SupportedCipherSuite] {
if boring::fips::enabled() {
ALL_FIPS_SUITES
} else {
#[cfg(feature = "fips-only")]
{
ALL_FIPS_CIPHER_SUITES
}
#[cfg(not(feature = "fips-only"))]
{
ALL_CIPHER_SUITES
}
}
fn default_kx_groups(&self) -> &'static [&'static dyn SupportedKxGroup] {
if boring::fips::enabled() {
#[cfg(feature = "fips-only")]
{
ALL_FIPS_KX_GROUPS
} else {
}
#[cfg(not(feature = "fips-only"))]
{
ALL_KX_GROUPS
}
}
@ -52,22 +60,65 @@ impl CryptoProvider for Provider {
}
fn signature_verification_algorithms(&self) -> rustls::WebPkiSupportedAlgorithms {
verify::ALL_ALGORITHMS
#[cfg(feature = "fips-only")]
{
verify::ALL_FIPS_ALGORITHMS
}
#[cfg(not(feature = "fips-only"))]
{
verify::ALL_ALGORITHMS
}
}
}
static ALL_FIPS_SUITES: &[SupportedCipherSuite] = &[
#[allow(unused)]
static ALL_FIPS_CIPHER_SUITES: &[SupportedCipherSuite] = &[
SupportedCipherSuite::Tls13(&tls13::AES_256_GCM_SHA384),
SupportedCipherSuite::Tls13(&tls13::AES_128_GCM_SHA256),
SupportedCipherSuite::Tls13(&tls13::AES_256_GCM_SHA256),
#[cfg(feature = "tls12")]
SupportedCipherSuite::Tls12(&tls12::ECDHE_ECDSA_AES256_GCM_SHA384),
#[cfg(feature = "tls12")]
SupportedCipherSuite::Tls12(&tls12::ECDHE_RSA_AES256_GCM_SHA384),
#[cfg(feature = "tls12")]
SupportedCipherSuite::Tls12(&tls12::ECDHE_ECDSA_AES128_GCM_SHA256),
#[cfg(feature = "tls12")]
SupportedCipherSuite::Tls12(&tls12::ECDHE_RSA_AES128_GCM_SHA256),
];
#[allow(unused)]
static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = &[
SupportedCipherSuite::Tls13(&tls13::AES_128_GCM_SHA256),
SupportedCipherSuite::Tls13(&tls13::AES_256_GCM_SHA256),
SupportedCipherSuite::Tls13(&tls13::CHACHA20_POLY1305_SHA256),
SupportedCipherSuite::Tls13(&tls13::AES_256_GCM_SHA384),
SupportedCipherSuite::Tls13(&tls13::AES_128_GCM_SHA256),
#[cfg(feature = "tls12")]
SupportedCipherSuite::Tls12(&tls12::ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256),
#[cfg(feature = "tls12")]
SupportedCipherSuite::Tls12(&tls12::ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256),
#[cfg(feature = "tls12")]
SupportedCipherSuite::Tls12(&tls12::ECDHE_ECDSA_AES256_GCM_SHA384),
#[cfg(feature = "tls12")]
SupportedCipherSuite::Tls12(&tls12::ECDHE_RSA_AES256_GCM_SHA384),
#[cfg(feature = "tls12")]
SupportedCipherSuite::Tls12(&tls12::ECDHE_ECDSA_AES128_GCM_SHA256),
#[cfg(feature = "tls12")]
SupportedCipherSuite::Tls12(&tls12::ECDHE_RSA_AES128_GCM_SHA256),
];
pub const ALL_FIPS_KX_GROUPS: &[&dyn SupportedKxGroup] = &[];
/// Allowed KX curves for FIPS are recommended
/// in [NIST SP 800-186](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-186.pdf)
///
/// See Sec. 3.1.2 Table 2
/// Ordered in decending order of security strength
#[allow(unused)]
pub const ALL_FIPS_KX_GROUPS: &[&dyn SupportedKxGroup] = &[
&kx::Secp521r1 as _, // P-521 in FIPS lingo
&kx::X448 as _, // Curve448 in FIPS lingo
&kx::Secp384r1 as _, // P-384 in FIPS lingo
&kx::X25519 as _, // Curve25519 in FIPS lingo
&kx::Secp256r1 as _, // P-256 in FIPS lingo
];
#[allow(unused)]
pub const ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = &[
&kx::X25519 as _,
&kx::X448 as _,

View file

@ -0,0 +1,89 @@
use rustls::{crypto, SignatureScheme, Tls12CipherSuite};
use crate::{aead, hash, hmac};
static ALL_ECDSA_SCHEMES: &[SignatureScheme] = &[
SignatureScheme::ECDSA_NISTP256_SHA256,
SignatureScheme::ECDSA_NISTP384_SHA384,
SignatureScheme::ECDSA_NISTP521_SHA512,
SignatureScheme::ED25519,
SignatureScheme::ED448,
];
static ALL_RSA_SCHEMES: &[SignatureScheme] = &[
SignatureScheme::RSA_PKCS1_SHA256,
SignatureScheme::RSA_PKCS1_SHA384,
SignatureScheme::RSA_PKCS1_SHA512,
SignatureScheme::RSA_PSS_SHA256,
SignatureScheme::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA512,
];
const PRF_SHA256: crypto::tls12::PrfUsingHmac<'_> = crypto::tls12::PrfUsingHmac(hmac::SHA256);
const PRF_SHA384: crypto::tls12::PrfUsingHmac<'_> = crypto::tls12::PrfUsingHmac(hmac::SHA384);
pub static ECDHE_ECDSA_AES128_GCM_SHA256: Tls12CipherSuite = Tls12CipherSuite {
common: rustls::CipherSuiteCommon {
suite: rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
hash_provider: hash::SHA256,
},
aead_alg: &aead::Aead::<aead::aes::Aes128>::DEFAULT,
prf_provider: &PRF_SHA256,
kx: crypto::KeyExchangeAlgorithm::ECDHE,
sign: ALL_ECDSA_SCHEMES,
};
pub static ECDHE_RSA_AES128_GCM_SHA256: Tls12CipherSuite = Tls12CipherSuite {
common: rustls::CipherSuiteCommon {
suite: rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
hash_provider: hash::SHA256,
},
aead_alg: &aead::Aead::<aead::aes::Aes128>::DEFAULT,
prf_provider: &PRF_SHA256,
kx: crypto::KeyExchangeAlgorithm::ECDHE,
sign: ALL_RSA_SCHEMES,
};
pub static ECDHE_ECDSA_AES256_GCM_SHA384: Tls12CipherSuite = Tls12CipherSuite {
common: rustls::CipherSuiteCommon {
suite: rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
hash_provider: hash::SHA384,
},
aead_alg: &aead::Aead::<aead::aes::Aes256>::DEFAULT,
prf_provider: &PRF_SHA384,
kx: crypto::KeyExchangeAlgorithm::ECDHE,
sign: ALL_ECDSA_SCHEMES,
};
pub static ECDHE_RSA_AES256_GCM_SHA384: Tls12CipherSuite = Tls12CipherSuite {
common: rustls::CipherSuiteCommon {
suite: rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
hash_provider: hash::SHA384,
},
aead_alg: &aead::Aead::<aead::aes::Aes256>::DEFAULT,
prf_provider: &PRF_SHA384,
kx: crypto::KeyExchangeAlgorithm::ECDHE,
sign: ALL_RSA_SCHEMES,
};
pub static ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: Tls12CipherSuite = Tls12CipherSuite {
common: rustls::CipherSuiteCommon {
suite: rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
hash_provider: hash::SHA256,
},
aead_alg: &aead::Aead::<aead::chacha20::ChaCha20Poly1305>::DEFAULT,
prf_provider: &PRF_SHA256,
kx: crypto::KeyExchangeAlgorithm::ECDHE,
sign: ALL_ECDSA_SCHEMES,
};
pub static ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: Tls12CipherSuite = Tls12CipherSuite {
common: rustls::CipherSuiteCommon {
suite: rustls::CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
hash_provider: hash::SHA256,
},
aead_alg: &aead::Aead::<aead::chacha20::ChaCha20Poly1305>::DEFAULT,
prf_provider: &PRF_SHA256,
kx: crypto::KeyExchangeAlgorithm::ECDHE,
sign: ALL_RSA_SCHEMES,
};

View file

@ -11,12 +11,12 @@ pub static AES_128_GCM_SHA256: Tls13CipherSuite = Tls13CipherSuite {
aead_alg: &aead::Aead::<aead::aes::Aes128>::DEFAULT,
};
pub static AES_256_GCM_SHA256: Tls13CipherSuite = Tls13CipherSuite {
pub static AES_256_GCM_SHA384: Tls13CipherSuite = Tls13CipherSuite {
common: rustls::CipherSuiteCommon {
suite: rustls::CipherSuite::TLS13_AES_128_GCM_SHA256,
hash_provider: hash::SHA256,
suite: rustls::CipherSuite::TLS13_AES_256_GCM_SHA384,
hash_provider: hash::SHA384,
},
hkdf_provider: &hkdf::Hkdf::<hkdf::Sha256>::DEFAULT,
hkdf_provider: &hkdf::Hkdf::<hkdf::Sha384>::DEFAULT,
aead_alg: &aead::Aead::<aead::aes::Aes256>::DEFAULT,
};

View file

@ -4,6 +4,7 @@ pub(crate) mod ec;
mod ed;
pub(crate) mod rsa;
#[allow(unused)]
pub static ALL_ALGORITHMS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms {
all: &[
&rsa::BoringRsaVerifier::RSA_PKCS1_SHA256,
@ -59,3 +60,60 @@ pub static ALL_ALGORITHMS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms
(SignatureScheme::ED448, &[&ed::BoringEdVerifier::ED448]),
],
};
#[allow(unused)]
pub static ALL_FIPS_ALGORITHMS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms {
all: &[
&rsa::BoringRsaVerifier::RSA_PKCS1_SHA256,
&rsa::BoringRsaVerifier::RSA_PKCS1_SHA384,
&rsa::BoringRsaVerifier::RSA_PKCS1_SHA512,
&rsa::BoringRsaVerifier::RSA_PSS_SHA256,
&rsa::BoringRsaVerifier::RSA_PSS_SHA384,
&rsa::BoringRsaVerifier::RSA_PSS_SHA512,
&ec::BoringEcVerifier::ECDSA_NISTP256_SHA256,
&ec::BoringEcVerifier::ECDSA_NISTP384_SHA384,
&ec::BoringEcVerifier::ECDSA_NISTP521_SHA512,
//&ed::BoringEdVerifier::ED25519, // FIPS 186-5: requires SHA512 but boring doesn't want us to set a digest, correct?
//&ed::BoringEdVerifier::ED448, // FIPS 186-5: requires SHAKE256 but boring doesn't want us to set a digest, correct?
],
mapping: &[
(
SignatureScheme::RSA_PKCS1_SHA256,
&[&rsa::BoringRsaVerifier::RSA_PKCS1_SHA256],
),
(
SignatureScheme::RSA_PKCS1_SHA384,
&[&rsa::BoringRsaVerifier::RSA_PKCS1_SHA384],
),
(
SignatureScheme::RSA_PKCS1_SHA512,
&[&rsa::BoringRsaVerifier::RSA_PKCS1_SHA512],
),
(
SignatureScheme::RSA_PSS_SHA256,
&[&rsa::BoringRsaVerifier::RSA_PSS_SHA256],
),
(
SignatureScheme::RSA_PSS_SHA384,
&[&rsa::BoringRsaVerifier::RSA_PSS_SHA384],
),
(
SignatureScheme::RSA_PSS_SHA512,
&[&rsa::BoringRsaVerifier::RSA_PSS_SHA512],
),
(
SignatureScheme::ECDSA_NISTP256_SHA256,
&[&ec::BoringEcVerifier::ECDSA_NISTP256_SHA256],
),
(
SignatureScheme::ECDSA_NISTP384_SHA384,
&[&ec::BoringEcVerifier::ECDSA_NISTP384_SHA384],
),
(
SignatureScheme::ECDSA_NISTP521_SHA512,
&[&ec::BoringEcVerifier::ECDSA_NISTP521_SHA512],
),
// (SignatureScheme::ED25519, &[&ed::BoringEdVerifier::ED25519]),
// (SignatureScheme::ED448, &[&ed::BoringEdVerifier::ED448]),
],
};