mls-spec 2.0.0

This crate is a repository of MLS / RFC9420-related data structures.
Documentation
use crate::{
    SensitiveBytes,
    defs::{Epoch, LeafIndex, ProtocolVersion, WireFormat, labels::KdfLabelKind},
    group::{GroupId, GroupIdRef},
};

pub const WIRE_FORMAT_MLS_TARGETED_MESSAGE: u16 = 0x0006;

#[derive(
    Debug,
    Clone,
    PartialEq,
    Eq,
    tls_codec::TlsSerialize,
    tls_codec::TlsDeserialize,
    tls_codec::TlsSize,
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TargetedMessageSenderAuthData {
    pub sender_leaf_index: LeafIndex,
    pub signature: SensitiveBytes,
    pub kem_output: SensitiveBytes,
}

#[derive(Debug, Clone, PartialEq, Eq, tls_codec::TlsSerialize, tls_codec::TlsSize)]
pub struct TargetedMessageTBM<'a> {
    #[tls_codec(with = "crate::tlspl::bytes")]
    pub group_id: GroupIdRef<'a>,
    pub epoch: &'a Epoch,
    pub recipient_leaf_index: &'a LeafIndex,
    #[tls_codec(with = "crate::tlspl::bytes")]
    pub authenticated_data: &'a [u8],
    pub sender_auth_data: &'a TargetedMessageSenderAuthData,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TargetedMessageTBS<'a> {
    pub group_id: GroupIdRef<'a>,
    pub epoch: &'a Epoch,
    pub recipient_leaf_index: &'a LeafIndex,
    pub authenticated_data: &'a [u8],
    pub sender_leaf_index: &'a LeafIndex,
    pub kem_output: &'a [u8],
    pub ciphertext: &'a [u8],
}

impl<'a> tls_codec::Size for TargetedMessageTBS<'a> {
    fn tls_serialized_len(&self) -> usize {
        ProtocolVersion::Mls10.tls_serialized_len()
            + WireFormat::new_unchecked(WireFormat::MLS_TARGETED_MESSAGE).tls_serialized_len()
            + crate::tlspl::bytes::tls_serialized_len(self.group_id)
            + self.epoch.tls_serialized_len()
            + self.recipient_leaf_index.tls_serialized_len()
            + crate::tlspl::bytes::tls_serialized_len(self.authenticated_data)
            + self.sender_leaf_index.tls_serialized_len()
            + crate::tlspl::bytes::tls_serialized_len(self.kem_output)
            + crate::tlspl::bytes::tls_serialized_len(self.ciphertext)
    }
}

impl<'a> tls_codec::Serialize for TargetedMessageTBS<'a> {
    fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
        let mut written = ProtocolVersion::Mls10.tls_serialize(writer)?;
        written +=
            WireFormat::new_unchecked(WireFormat::MLS_TARGETED_MESSAGE).tls_serialize(writer)?;
        written += crate::tlspl::bytes::tls_serialize(self.group_id, writer)?;
        written += self.epoch.tls_serialize(writer)?;
        written += self.recipient_leaf_index.tls_serialize(writer)?;
        written += crate::tlspl::bytes::tls_serialize(self.authenticated_data, writer)?;
        written += self.sender_leaf_index.tls_serialize(writer)?;
        written += crate::tlspl::bytes::tls_serialize(self.kem_output, writer)?;
        written += crate::tlspl::bytes::tls_serialize(self.ciphertext, writer)?;

        Ok(written)
    }
}

#[derive(
    Debug,
    Clone,
    PartialEq,
    Eq,
    tls_codec::TlsSerialize,
    tls_codec::TlsDeserialize,
    tls_codec::TlsSize,
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TargetedMessage {
    pub group_id: GroupId,
    pub epoch: Epoch,
    pub recipient_leaf_index: LeafIndex,
    pub authenticated_data: SensitiveBytes,
    pub encrypted_sender_auth_data: SensitiveBytes,
    pub ciphertext: SensitiveBytes,
}

#[derive(Debug, Clone, PartialEq, Eq, tls_codec::TlsSerialize, tls_codec::TlsSize)]
pub struct TargetedMessagePreSharedKeyId<'a> {
    #[tls_codec(with = "crate::tlspl::bytes")]
    pub group_id: GroupIdRef<'a>,
    pub epoch: &'a Epoch,
}

impl TargetedMessagePreSharedKeyId<'_> {
    pub const LABEL: KdfLabelKind = KdfLabelKind::TargetedMessagePsk;
}

#[derive(Debug, Clone, PartialEq, Eq, tls_codec::TlsSerialize, tls_codec::TlsSize)]
pub struct TargetedMessageSenderAuthDataAAD<'a> {
    #[tls_codec(with = "crate::tlspl::bytes")]
    pub group_id: GroupIdRef<'a>,
    pub epoch: &'a Epoch,
    pub recipient_leaf_index: &'a LeafIndex,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TargetedMessageContent {
    pub application_data: Vec<u8>,
    pub padding_len: usize,
}

impl tls_codec::Size for TargetedMessageContent {
    fn tls_serialized_len(&self) -> usize {
        crate::tlspl::tls_serialized_len_as_vlvec(self.application_data.len()) + self.padding_len
    }
}

impl tls_codec::Serialize for TargetedMessageContent {
    fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
        let mut written = crate::tlspl::bytes::tls_serialize(&self.application_data, writer)?;
        writer.write_all(&vec![0u8; self.padding_len][..])?;
        written += self.padding_len;
        Ok(written)
    }
}

impl tls_codec::Deserialize for TargetedMessageContent {
    fn tls_deserialize<R: std::io::Read>(bytes: &mut R) -> Result<Self, tls_codec::Error>
    where
        Self: Sized,
    {
        let application_data = crate::tlspl::bytes::tls_deserialize(bytes)?;
        let padding_len = crate::messages::PrivateMessageContent::consume_padding(bytes)?;
        Ok(Self {
            application_data,
            padding_len,
        })
    }
}