use crate::{
cipher_suite::{TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256},
header_key::HeaderKey,
};
use core::fmt;
use ring::{aead, hkdf};
use s2n_quic_core::crypto::{self, CryptoError};
#[allow(non_camel_case_types, clippy::all)]
pub enum NegotiatedCipherSuite {
TLS_AES_256_GCM_SHA384(TLS_AES_256_GCM_SHA384),
TLS_CHACHA20_POLY1305_SHA256(TLS_CHACHA20_POLY1305_SHA256),
TLS_AES_128_GCM_SHA256(TLS_AES_128_GCM_SHA256),
}
macro_rules! dispatch {
($self:ident, | $cipher_suite:ident | $expr:expr) => {
match $self {
Self::TLS_AES_256_GCM_SHA384($cipher_suite) => $expr,
Self::TLS_CHACHA20_POLY1305_SHA256($cipher_suite) => $expr,
Self::TLS_AES_128_GCM_SHA256($cipher_suite) => $expr,
}
};
}
impl From<TLS_AES_256_GCM_SHA384> for NegotiatedCipherSuite {
fn from(cipher_suite: TLS_AES_256_GCM_SHA384) -> Self {
Self::TLS_AES_256_GCM_SHA384(cipher_suite)
}
}
impl From<TLS_CHACHA20_POLY1305_SHA256> for NegotiatedCipherSuite {
fn from(cipher_suite: TLS_CHACHA20_POLY1305_SHA256) -> Self {
Self::TLS_CHACHA20_POLY1305_SHA256(cipher_suite)
}
}
impl From<TLS_AES_128_GCM_SHA256> for NegotiatedCipherSuite {
fn from(cipher_suite: TLS_AES_128_GCM_SHA256) -> Self {
Self::TLS_AES_128_GCM_SHA256(cipher_suite)
}
}
impl NegotiatedCipherSuite {
pub fn new(algorithm: &aead::Algorithm, secret: hkdf::Prk) -> Option<(Self, HeaderKey)> {
Some(match algorithm {
_ if algorithm == &aead::AES_256_GCM => {
let (cipher_suite, header_key) = TLS_AES_256_GCM_SHA384::new(secret);
(cipher_suite.into(), header_key)
}
_ if algorithm == &aead::CHACHA20_POLY1305 => {
let (cipher_suite, header_key) = TLS_CHACHA20_POLY1305_SHA256::new(secret);
(cipher_suite.into(), header_key)
}
_ if algorithm == &aead::AES_128_GCM => {
let (cipher_suite, header_key) = TLS_AES_128_GCM_SHA256::new(secret);
(cipher_suite.into(), header_key)
}
_ => return None,
})
}
pub fn update(&self) -> Self {
dispatch!(self, |cipher| cipher.update().into())
}
pub fn update_pmtu(&mut self, pmtu: u16) {
dispatch!(self, |cipher| cipher.update_pmtu(pmtu))
}
}
impl crypto::Key for NegotiatedCipherSuite {
#[inline]
fn decrypt(
&self,
packet_number: u64,
header: &[u8],
payload: &mut [u8],
) -> Result<(), CryptoError> {
dispatch!(self, |cipher| cipher.decrypt(
packet_number,
header,
payload
))
}
#[inline]
fn encrypt(
&self,
packet_number: u64,
header: &[u8],
payload: &mut [u8],
) -> Result<(), CryptoError> {
dispatch!(self, |cipher| cipher.encrypt(
packet_number,
header,
payload
))
}
#[inline]
fn tag_len(&self) -> usize {
dispatch!(self, |cipher| cipher.tag_len())
}
#[inline]
fn aead_confidentiality_limit(&self) -> u64 {
dispatch!(self, |cipher| cipher.aead_confidentiality_limit())
}
#[inline]
fn aead_integrity_limit(&self) -> u64 {
dispatch!(self, |cipher| cipher.aead_integrity_limit())
}
#[inline]
fn cipher_suite(&self) -> s2n_quic_core::crypto::tls::CipherSuite {
dispatch!(self, |cipher| cipher.cipher_suite())
}
}
impl fmt::Debug for NegotiatedCipherSuite {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dispatch!(self, |cipher| cipher.fmt(f))
}
}