use crate::{
cipher_suite::NegotiatedCipherSuite as CipherSuite, header_key::HeaderKeyPair, Algorithm,
SecretPair,
};
use s2n_quic_core::{
crypto::{CryptoError, Key},
endpoint,
};
#[derive(Debug)]
pub struct KeyPair {
sealer: CipherSuite,
opener: CipherSuite,
}
impl KeyPair {
pub fn new(
endpoint: endpoint::Type,
algorithm: &Algorithm,
secrets: SecretPair,
) -> Option<(Self, HeaderKeyPair)> {
let (sealer_secret, opener_secret) = match endpoint {
endpoint::Type::Client => (secrets.client, secrets.server),
endpoint::Type::Server => (secrets.server, secrets.client),
};
let (sealer, header_sealer) = CipherSuite::new(algorithm, sealer_secret)?;
let (opener, header_opener) = CipherSuite::new(algorithm, opener_secret)?;
let key = Self { sealer, opener };
let header_key = HeaderKeyPair {
sealer: header_sealer,
opener: header_opener,
};
Some((key, header_key))
}
#[inline]
pub fn update(&self) -> Self {
Self {
sealer: self.sealer.update(),
opener: self.opener.update(),
}
}
}
impl Key for KeyPair {
#[inline]
fn decrypt(
&self,
packet_number: u64,
header: &[u8],
payload: &mut [u8],
) -> Result<(), CryptoError> {
self.opener.decrypt(packet_number, header, payload)
}
#[inline]
fn encrypt(
&self,
packet_number: u64,
header: &[u8],
payload: &mut [u8],
) -> Result<(), CryptoError> {
self.sealer.encrypt(packet_number, header, payload)
}
#[inline]
fn tag_len(&self) -> usize {
self.sealer.tag_len()
}
#[inline]
fn aead_confidentiality_limit(&self) -> u64 {
self.sealer.aead_confidentiality_limit()
}
#[inline]
fn aead_integrity_limit(&self) -> u64 {
self.opener.aead_integrity_limit()
}
#[inline]
fn cipher_suite(&self) -> s2n_quic_core::crypto::tls::CipherSuite {
self.opener.cipher_suite()
}
}
macro_rules! negotiated_crypto {
($name:ident, $header_key:ident) => {
#[derive(Debug)]
pub struct $name(crate::negotiated::KeyPair);
impl $name {
pub fn new_server(
algorithm: &$crate::Algorithm,
secrets: $crate::SecretPair,
) -> Option<(Self, $header_key)> {
Self::new(s2n_quic_core::endpoint::Type::Server, algorithm, secrets)
}
pub fn new_client(
algorithm: &$crate::Algorithm,
secrets: $crate::SecretPair,
) -> Option<(Self, $header_key)> {
Self::new(s2n_quic_core::endpoint::Type::Client, algorithm, secrets)
}
pub fn new(
endpoint: s2n_quic_core::endpoint::Type,
algorithm: &$crate::Algorithm,
secrets: $crate::SecretPair,
) -> Option<(Self, $header_key)> {
let (key, header_key) =
crate::negotiated::KeyPair::new(endpoint, algorithm, secrets)?;
let key = Self(key);
let header_key = $header_key(header_key);
Some((key, header_key))
}
#[inline]
#[must_use]
pub fn update(&self) -> Self {
Self(self.0.update())
}
}
impl s2n_quic_core::crypto::Key for $name {
#[inline]
fn decrypt(
&self,
packet_number: u64,
header: &[u8],
payload: &mut [u8],
) -> Result<(), s2n_quic_core::crypto::CryptoError> {
self.0.decrypt(packet_number, header, payload)
}
#[inline]
fn encrypt(
&self,
packet_number: u64,
header: &[u8],
payload: &mut [u8],
) -> Result<(), s2n_quic_core::crypto::CryptoError> {
self.0.encrypt(packet_number, header, payload)
}
#[inline]
fn tag_len(&self) -> usize {
self.0.tag_len()
}
#[inline]
fn aead_confidentiality_limit(&self) -> u64 {
self.0.aead_confidentiality_limit()
}
#[inline]
fn aead_integrity_limit(&self) -> u64 {
self.0.aead_integrity_limit()
}
#[inline]
fn cipher_suite(&self) -> s2n_quic_core::crypto::tls::CipherSuite {
self.0.cipher_suite()
}
}
};
}