use crate::{
codec::{Decode, Encode},
crypto::{Agreement, EcdhP256Global, EcdhP384Global, X25519Global},
misc::Lease,
rng::CryptoRng,
tls::{
AlertDescription, TlsError, de::De, tls_decode_wrapper::TlsDecodeWrapper,
tls_encode_wrapper::TlsEncodeWrapper,
},
};
pub(crate) type NamedGroupAgreement = NamedGroupParam<EcdhP256Global, EcdhP384Global, X25519Global>;
pub(crate) type NamedGroupPk = NamedGroupParam<
<EcdhP256Global as Agreement>::PublicKey,
<EcdhP384Global as Agreement>::PublicKey,
<X25519Global as Agreement>::PublicKey,
>;
pub(crate) type NamedGroupSs = NamedGroupParam<
<EcdhP256Global as Agreement>::SharedSecret,
<EcdhP384Global as Agreement>::SharedSecret,
<X25519Global as Agreement>::SharedSecret,
>;
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum NamedGroup {
Secp256r1 = 23,
Secp384r1 = 24,
#[default]
X25519 = 29,
}
impl NamedGroup {
pub(crate) const PRIORITY: [Self; 3] = [Self::X25519, Self::Secp256r1, Self::Secp384r1];
pub(crate) fn agreement<RNG>(self, rng: &mut RNG) -> crate::Result<NamedGroupAgreement>
where
RNG: CryptoRng,
{
Ok(match self {
NamedGroup::Secp256r1 => NamedGroupAgreement::Secp256r1(EcdhP256Global::generate(rng)?),
NamedGroup::Secp384r1 => NamedGroupAgreement::Secp384r1(EcdhP384Global::generate(rng)?),
NamedGroup::X25519 => NamedGroupAgreement::X25519(X25519Global::generate(rng)?),
})
}
pub(crate) const fn len() -> usize {
3
}
}
impl<'de> Decode<'de, De> for NamedGroup {
#[inline]
fn decode(dw: &mut TlsDecodeWrapper<'de>) -> crate::Result<Self> {
Self::try_from(<u16 as Decode<De>>::decode(dw)?)
}
}
impl Encode<De> for NamedGroup {
#[inline]
fn encode(&self, ew: &mut TlsEncodeWrapper<'_>) -> crate::Result<()> {
ew.buffer().extend_from_copyable_slice(&u16::from(*self).to_be_bytes())?;
Ok(())
}
}
impl From<NamedGroup> for u16 {
#[inline]
fn from(value: NamedGroup) -> Self {
match value {
NamedGroup::Secp256r1 => 23,
NamedGroup::Secp384r1 => 24,
NamedGroup::X25519 => 29,
}
}
}
impl TryFrom<u16> for NamedGroup {
type Error = crate::Error;
#[inline]
fn try_from(value: u16) -> crate::Result<Self> {
Ok(match value {
23 => NamedGroup::Secp256r1,
24 => NamedGroup::Secp384r1,
29 => NamedGroup::X25519,
_ => return Err(TlsError::UnknownNamedGroup.into()),
})
}
}
impl NamedGroupAgreement {
pub(crate) fn diffie_hellman<const IS_CLIENT: bool>(
self,
other_participant_pk: &[u8],
) -> crate::Result<NamedGroupSs> {
let description =
if IS_CLIENT { AlertDescription::BadRecordMac } else { AlertDescription::IllegalParameter };
Ok(match self {
NamedGroupParam::Secp256r1(elem) => {
NamedGroupSs::Secp256r1(match elem.diffie_hellman(other_participant_pk) {
Ok(el) => el,
Err(_err) => {
return Err(crate::Error::TlsErrorReply(TlsError::DiffieHellmanError, description));
}
})
}
NamedGroupParam::Secp384r1(elem) => {
NamedGroupSs::Secp384r1(match elem.diffie_hellman(other_participant_pk) {
Ok(el) => el,
Err(_err) => {
return Err(crate::Error::TlsErrorReply(TlsError::DiffieHellmanError, description));
}
})
}
NamedGroupParam::X25519(elem) => {
NamedGroupSs::X25519(match elem.diffie_hellman(other_participant_pk) {
Ok(el) => el,
Err(_err) => {
return Err(crate::Error::TlsErrorReply(TlsError::DiffieHellmanError, description));
}
})
}
})
}
pub(crate) fn public_key(&self) -> crate::Result<NamedGroupPk> {
Ok(match self {
NamedGroupParam::Secp256r1(elem) => NamedGroupPk::Secp256r1(elem.public_key()?),
NamedGroupParam::Secp384r1(elem) => NamedGroupPk::Secp384r1(elem.public_key()?),
NamedGroupParam::X25519(elem) => NamedGroupPk::X25519(elem.public_key()?),
})
}
}
#[derive(Debug)]
pub enum NamedGroupParam<A, B, C> {
Secp256r1(A),
Secp384r1(B),
X25519(C),
}
impl<A, B, C> NamedGroupParam<A, B, C> {
#[inline]
pub(crate) const fn named_group(&self) -> NamedGroup {
match self {
NamedGroupParam::Secp256r1(_) => NamedGroup::Secp256r1,
NamedGroupParam::Secp384r1(_) => NamedGroup::Secp384r1,
NamedGroupParam::X25519(_) => NamedGroup::X25519,
}
}
}
impl<A, B, C, T> AsRef<[T]> for NamedGroupParam<A, B, C>
where
A: AsRef<[T]>,
B: AsRef<[T]>,
C: AsRef<[T]>,
{
#[inline]
fn as_ref(&self) -> &[T] {
match self {
NamedGroupParam::Secp256r1(el) => el.as_ref(),
NamedGroupParam::Secp384r1(el) => el.as_ref(),
NamedGroupParam::X25519(el) => el.as_ref(),
}
}
}
impl<A, B, C, T> Lease<[T]> for NamedGroupParam<A, B, C>
where
A: AsRef<[T]>,
B: AsRef<[T]>,
C: AsRef<[T]>,
{
#[inline]
fn lease(&self) -> &[T] {
match self {
NamedGroupParam::Secp256r1(el) => el.as_ref(),
NamedGroupParam::Secp384r1(el) => el.as_ref(),
NamedGroupParam::X25519(el) => el.as_ref(),
}
}
}