use crate::{group::errors::ValidationError, tree::index::SecretTreeLeafIndex, treesync::TreeSync};
use core_group::{proposals::QueuedProposal, staged_commit::StagedCommit};
use openmls_traits::OpenMlsCryptoProvider;
use crate::{
ciphersuite::{hash_ref::KeyPackageRef, signable::Verifiable},
error::LibraryError,
tree::sender_ratchet::SenderRatchetConfiguration,
};
use super::*;
pub(crate) struct DecryptedMessage {
plaintext: VerifiableMlsPlaintext,
}
impl DecryptedMessage {
pub(crate) fn from_inbound_plaintext(
inbound_message: MlsMessageIn,
) -> Result<Self, ValidationError> {
if let MlsMessage::Plaintext(plaintext) = inbound_message.mls_message {
Self::from_plaintext(*plaintext)
} else {
Err(ValidationError::WrongWireFormat)
}
}
pub(crate) fn from_inbound_ciphertext(
inbound_message: MlsMessageIn,
backend: &impl OpenMlsCryptoProvider,
group: &mut CoreGroup,
sender_ratchet_configuration: &SenderRatchetConfiguration,
) -> Result<Self, ValidationError> {
if let MlsMessage::Ciphertext(ciphertext) = inbound_message.mls_message {
let ciphersuite = group.ciphersuite();
let (message_secrets, old_leaves) = group
.message_secrets_and_leaves_mut(ciphertext.epoch())
.map_err(|_| MessageDecryptionError::AeadError)?;
let sender_data = ciphertext.sender_data(message_secrets, backend, ciphersuite)?;
let sender_index = match group.sender_index(&sender_data.sender) {
Ok(i) => i,
Err(_) => {
old_leaves
.into_iter()
.find_map(|(index, kpr)| {
if kpr == sender_data.sender {
Some(index)
} else {
None
}
})
.ok_or(ValidationError::UnknownMember)?
}
};
let sender_index = SecretTreeLeafIndex(sender_index);
let message_secrets = group
.message_secrets_mut(ciphertext.epoch())
.map_err(|_| MessageDecryptionError::AeadError)?;
let plaintext = ciphertext.to_plaintext(
ciphersuite,
backend,
message_secrets,
sender_index,
sender_ratchet_configuration,
sender_data,
)?;
Self::from_plaintext(plaintext)
} else {
Err(ValidationError::WrongWireFormat)
}
}
fn from_plaintext(plaintext: VerifiableMlsPlaintext) -> Result<Self, ValidationError> {
if plaintext.sender().is_member()
&& plaintext.wire_format() != WireFormat::MlsCiphertext
&& plaintext.membership_tag().is_none()
{
return Err(ValidationError::MissingMembershipTag);
}
if plaintext.content_type() == ContentType::Commit && plaintext.confirmation_tag().is_none()
{
return Err(ValidationError::MissingConfirmationTag);
}
if plaintext.content_type() == ContentType::Application {
if plaintext.wire_format() != WireFormat::MlsCiphertext {
return Err(ValidationError::UnencryptedApplicationMessage);
} else if !plaintext.sender().is_member() {
return Err(LibraryError::custom("Expected sender to be member.").into());
}
}
Ok(DecryptedMessage { plaintext })
}
pub(crate) fn credential(
&self,
treesync: &TreeSync,
old_leaves: &[(u32, KeyPackageRef)],
) -> Result<Credential, ValidationError> {
let sender = self.sender();
match sender {
Sender::Member(hash_ref) => {
match treesync.leaf_from_id(hash_ref) {
Some(sender_leaf) => Ok(sender_leaf.key_package().credential().clone()),
None => {
if let Some((sender_index, _)) =
old_leaves.iter().find(|(_, kpr)| kpr == hash_ref)
{
match treesync
.leaf(*sender_index)
.map_err(|_| ValidationError::UnknownMember)?
{
Some(node) => Ok(node.key_package().credential().clone()),
None => Err(ValidationError::UnknownMember),
}
} else {
Err(ValidationError::UnknownMember)
}
}
}
}
Sender::Preconfigured(_) => unimplemented!(),
Sender::NewMember => {
if let MlsPlaintextContentType::Commit(commit) = self.plaintext().content() {
if let Some(path) = commit.path() {
Ok(path.leaf_key_package().credential().clone())
} else {
Err(ValidationError::NoPath)
}
} else {
Err(ValidationError::NotACommit)
}
}
}
}
pub fn sender(&self) -> &Sender {
self.plaintext.sender()
}
pub(crate) fn plaintext(&self) -> &VerifiableMlsPlaintext {
&self.plaintext
}
}
#[derive(Debug)]
pub struct UnverifiedMessage {
plaintext: VerifiableMlsPlaintext,
credential: Option<Credential>,
aad_option: Option<Vec<u8>>,
}
impl UnverifiedMessage {
pub(crate) fn from_decrypted_message(
decrypted_message: DecryptedMessage,
credential: Option<Credential>,
) -> Self {
UnverifiedMessage {
plaintext: decrypted_message.plaintext,
credential,
aad_option: None,
}
}
pub fn epoch(&self) -> GroupEpoch {
self.plaintext.epoch()
}
pub fn aad(&self) -> &Option<Vec<u8>> {
&self.aad_option
}
pub fn sender(&self) -> &Sender {
self.plaintext.sender()
}
pub fn credential(&self) -> Option<&Credential> {
self.credential.as_ref()
}
pub(crate) fn into_parts(self) -> (VerifiableMlsPlaintext, Option<Credential>) {
(self.plaintext, self.credential)
}
}
pub(crate) enum UnverifiedContextMessage {
Group(UnverifiedGroupMessage),
#[allow(dead_code)]
Preconfigured(UnverifiedPreconfiguredMessage),
}
impl UnverifiedContextMessage {
pub(crate) fn from_unverified_message(
unverified_message: UnverifiedMessage,
message_secrets: &MessageSecrets,
backend: &impl OpenMlsCryptoProvider,
) -> Result<Self, ValidationError> {
let (mut plaintext, credential_option) = unverified_message.into_parts();
if plaintext.sender().is_member() {
plaintext.set_context(message_secrets.serialized_context().to_vec());
if plaintext.wire_format() != WireFormat::MlsCiphertext {
plaintext.verify_membership(backend, message_secrets.membership_key())?;
}
}
match plaintext.sender() {
Sender::Member(_) | Sender::NewMember => {
Ok(UnverifiedContextMessage::Group(UnverifiedGroupMessage {
plaintext,
credential: credential_option.ok_or_else(|| {
ValidationError::from(LibraryError::custom("Expected credential"))
})?,
}))
}
Sender::Preconfigured(_) => unimplemented!(),
}
}
}
pub(crate) struct UnverifiedGroupMessage {
plaintext: VerifiableMlsPlaintext,
credential: Credential,
}
impl UnverifiedGroupMessage {
pub(crate) fn into_verified(
self,
backend: &impl OpenMlsCryptoProvider,
signature_key: Option<&SignaturePublicKey>,
) -> Result<VerifiedMemberMessage, ValidationError> {
let verified_member_message = if let Some(signature_public_key) = signature_key {
self.plaintext
.verify_with_key(backend, signature_public_key)
} else {
self.plaintext.verify(backend, &self.credential)
}
.map(|plaintext| VerifiedMemberMessage { plaintext })
.map_err(|_| ValidationError::InvalidSignature)?;
Ok(verified_member_message)
}
}
pub(crate) struct UnverifiedPreconfiguredMessage {
plaintext: VerifiableMlsPlaintext,
}
impl UnverifiedPreconfiguredMessage {
pub(crate) fn into_verified(
self,
backend: &impl OpenMlsCryptoProvider,
signature_key: &SignaturePublicKey,
) -> Result<VerifiedExternalMessage, ValidationError> {
self.plaintext
.verify_with_key(backend, signature_key)
.map(|_plaintext| VerifiedExternalMessage { _plaintext })
.map_err(|_| ValidationError::InvalidSignature)
}
}
pub(crate) struct VerifiedMemberMessage {
plaintext: MlsPlaintext,
}
impl VerifiedMemberMessage {
pub(crate) fn plaintext(&self) -> &MlsPlaintext {
&self.plaintext
}
pub(crate) fn take_plaintext(self) -> MlsPlaintext {
self.plaintext
}
}
pub(crate) struct VerifiedExternalMessage {
_plaintext: MlsPlaintext,
}
impl VerifiedExternalMessage {
pub(crate) fn _plaintext(&self) -> &MlsPlaintext {
&self._plaintext
}
pub(crate) fn _take_plaintext(self) -> MlsPlaintext {
self._plaintext
}
}
#[derive(Debug)]
pub enum ProcessedMessage {
ApplicationMessage(ApplicationMessage),
ProposalMessage(Box<QueuedProposal>),
StagedCommitMessage(Box<StagedCommit>),
}
#[derive(Debug, PartialEq)]
pub struct ApplicationMessage {
bytes: Vec<u8>,
}
impl ApplicationMessage {
pub(crate) fn new(bytes: Vec<u8>) -> Self {
Self { bytes }
}
pub fn into_bytes(self) -> Vec<u8> {
self.bytes
}
}