use super::config::{
EchConfig, EchConfigContents, EchConfigList, HpkeKeyConfig, HpkeSymCipherSuite,
};
use crate::hpke::{HpkeAead, HpkeKdf, HpkeKem};
use crate::rng::RngCore;
use crate::tls::Error;
use alloc::vec::Vec;
#[derive(Clone, Debug)]
pub struct EchKeyPair {
pub(crate) kem: HpkeKem,
pub(crate) private_key: Vec<u8>,
pub(crate) config: EchConfig,
}
impl EchKeyPair {
pub fn generate<R: RngCore>(
rng: &mut R,
kem: HpkeKem,
config_id: u8,
public_name: &[u8],
maximum_name_length: u8,
cipher_suites: Vec<HpkeSymCipherSuite>,
) -> Result<Self, Error> {
if public_name.is_empty() || public_name.len() > 255 {
return Err(Error::EchDecodeError);
}
if cipher_suites.is_empty() {
return Err(Error::EchDecodeError);
}
let (sk, pk) = kem
.generate_key_pair(rng)
.map_err(|_| Error::EchDecodeError)?;
let key_config = HpkeKeyConfig {
config_id,
kem_id: kem.id(),
public_key: pk,
cipher_suites,
};
let contents = EchConfigContents {
key_config,
maximum_name_length,
public_name: public_name.to_vec(),
extensions: Vec::new(),
};
let config = EchConfig::new(contents);
Ok(Self {
kem,
private_key: sk,
config,
})
}
pub fn config_id(&self) -> u8 {
self.config
.contents
.as_ref()
.map(|c| c.key_config.config_id)
.unwrap_or(0)
}
pub fn config(&self) -> &EchConfig {
&self.config
}
pub fn kem(&self) -> HpkeKem {
self.kem
}
pub(crate) fn private_key_bytes(&self) -> &[u8] {
&self.private_key
}
pub(crate) fn accepts(&self, kdf: HpkeKdf, aead: HpkeAead) -> bool {
let contents = match self.config.contents.as_ref() {
Some(c) => c,
None => return false,
};
contents
.key_config
.cipher_suites
.iter()
.any(|s| s.kdf_id == kdf.id() && s.aead_id == aead.id())
}
}
#[derive(Clone, Debug)]
pub struct EchKeyRing {
pub(crate) pairs: Vec<EchKeyPair>,
}
impl EchKeyRing {
pub fn new() -> Self {
Self { pairs: Vec::new() }
}
pub fn from_pairs(pairs: Vec<EchKeyPair>) -> Self {
Self { pairs }
}
pub fn push(&mut self, pair: EchKeyPair) {
self.pairs.push(pair);
}
pub(crate) fn find_by_config_id(&self, config_id: u8) -> Option<&EchKeyPair> {
self.pairs.iter().find(|p| p.config_id() == config_id)
}
pub fn to_config_list(&self) -> EchConfigList {
EchConfigList::new(self.pairs.iter().map(|p| p.config.clone()).collect())
}
}
impl Default for EchKeyRing {
fn default() -> Self {
Self::new()
}
}