1mod errors;
9
10#[cfg(test)]
11pub mod kat;
12
13#[cfg(test)]
14mod tests;
15
16pub use errors::*;
17
18use openmls_traits::{
19 crypto::OpenMlsCrypto,
20 signatures::Signer,
21 types::{Ciphersuite, HpkeCiphertext},
22};
23use serde::{Deserialize, Serialize};
24use tls_codec::{
25 DeserializeBytes, Serialize as TlsSerializeTrait, Size, TlsDeserialize, TlsDeserializeBytes,
26 TlsSerialize, TlsSize, VLByteSlice, VLBytes,
27};
28
29use crate::{
30 binary_tree::array_representation::LeafNodeIndex,
31 ciphersuite::{
32 signable::{Signable, SignedStruct, Verifiable, VerifiedStruct},
33 AeadKey, AeadNonce, OpenMlsSignaturePublicKey, Secret, Signature,
34 },
35 error::LibraryError,
36 framing::WireFormat,
37 group::{GroupEpoch, GroupId},
38 treesync::node::{
39 encryption_keys::{EncryptionKey, EncryptionPrivateKey},
40 leaf_node::LeafNode,
41 },
42 versions::ProtocolVersion,
43};
44
45const TARGETED_MESSAGE_EXPORTER_LABEL: &str = "targeted message";
46const PSK_SUBLABEL: &str = "psk";
47const SENDER_AUTH_DATA_SECRET_SUBLABEL: &str = "sender auth data secret";
48const TARGETED_MESSAGE_TBS_LABEL: &str = "TargetedMessageTBS";
49const TARGETED_MESSAGE_DATA_LABEL: &str = "TargetedMessageData";
50const PSK_LABEL: &str = "MLS 1.0 targeted message psk";
51
52#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TlsSerialize, TlsSize)]
65pub struct TargetedMessage {
66 pub(crate) group_id: GroupId,
67 pub(crate) epoch: GroupEpoch,
68 pub(crate) recipient_leaf_index: u32,
69 pub(crate) authenticated_data: VLBytes,
70 pub(crate) encrypted_sender_auth_data: VLBytes,
71 pub(crate) ciphertext: VLBytes,
72}
73
74impl TargetedMessage {
75 pub fn group_id(&self) -> &GroupId {
77 &self.group_id
78 }
79
80 pub fn epoch(&self) -> GroupEpoch {
82 self.epoch
83 }
84
85 pub fn recipient_leaf_index(&self) -> u32 {
87 self.recipient_leaf_index
88 }
89
90 pub fn authenticated_data(&self) -> &[u8] {
92 self.authenticated_data.as_slice()
93 }
94}
95
96#[derive(Debug, Clone, PartialEq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize)]
98pub struct TargetedMessageIn {
99 pub(crate) group_id: GroupId,
100 pub(crate) epoch: GroupEpoch,
101 pub(crate) recipient_leaf_index: u32,
102 pub(crate) authenticated_data: VLBytes,
103 pub(crate) encrypted_sender_auth_data: VLBytes,
104 pub(crate) ciphertext: VLBytes,
105}
106
107impl TargetedMessageIn {
108 pub fn group_id(&self) -> &GroupId {
110 &self.group_id
111 }
112
113 pub fn epoch(&self) -> GroupEpoch {
115 self.epoch
116 }
117
118 pub fn recipient_leaf_index(&self) -> u32 {
120 self.recipient_leaf_index
121 }
122
123 pub fn authenticated_data(&self) -> &[u8] {
125 self.authenticated_data.as_slice()
126 }
127}
128
129#[cfg(any(feature = "test-utils", test))]
130impl From<TargetedMessageIn> for TargetedMessage {
131 fn from(msg: TargetedMessageIn) -> Self {
132 Self {
133 group_id: msg.group_id,
134 epoch: msg.epoch,
135 recipient_leaf_index: msg.recipient_leaf_index,
136 authenticated_data: msg.authenticated_data,
137 encrypted_sender_auth_data: msg.encrypted_sender_auth_data,
138 ciphertext: msg.ciphertext,
139 }
140 }
141}
142
143impl From<TargetedMessage> for TargetedMessageIn {
144 fn from(msg: TargetedMessage) -> Self {
145 Self {
146 group_id: msg.group_id,
147 epoch: msg.epoch,
148 recipient_leaf_index: msg.recipient_leaf_index,
149 authenticated_data: msg.authenticated_data,
150 encrypted_sender_auth_data: msg.encrypted_sender_auth_data,
151 ciphertext: msg.ciphertext,
152 }
153 }
154}
155
156#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
165pub(crate) struct TargetedMessageContent {
166 application_data: VLBytes,
167 padding_length: usize,
168}
169
170impl TargetedMessageContent {
171 fn new(data: &[u8], padding_length: usize) -> Self {
172 Self {
173 application_data: data.into(),
174 padding_length,
175 }
176 }
177
178 pub(crate) fn application_data(&self) -> &[u8] {
179 self.application_data.as_slice()
180 }
181
182 fn serialize_detached(&self) -> Result<Vec<u8>, tls_codec::Error> {
185 use std::io::Write;
186 let app_data_len = self.application_data.tls_serialized_len();
187 let total_len = app_data_len
190 .checked_add(self.padding_length)
191 .filter(|&len| len <= isize::MAX as usize)
192 .ok_or_else(|| {
193 tls_codec::Error::EncodingError(
194 "Targeted message content exceeds the maximum size.".into(),
195 )
196 })?;
197 let mut buffer = Vec::with_capacity(total_len);
198 self.application_data.tls_serialize(&mut buffer)?;
199 buffer
200 .write_all(&vec![0u8; self.padding_length])
201 .map_err(|e| {
202 tls_codec::Error::EncodingError(format!("Failed to write padding: {e}"))
203 })?;
204 Ok(buffer)
205 }
206
207 fn deserialize_detached(bytes: &[u8]) -> Result<Self, tls_codec::Error> {
210 let (application_data, rest) = VLBytes::tls_deserialize_bytes(bytes)?;
211 if !rest.iter().all(|&b| b == 0x00) {
212 return Err(tls_codec::Error::DecodingError(
213 "Non-zero padding in TargetedMessageContent".into(),
214 ));
215 }
216 Ok(Self {
217 application_data,
218 padding_length: rest.len(),
219 })
220 }
221}
222
223#[derive(Debug, Clone, PartialEq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize)]
233struct TargetedMessageSenderAuthData {
234 sender_leaf_index: u32,
235 signature: Signature,
236 kem_output: VLBytes,
237}
238
239#[derive(TlsSerialize, TlsSize)]
249struct SenderAuthDataAAD<'a> {
250 group_id: &'a GroupId,
251 epoch: GroupEpoch,
252 recipient_leaf_index: u32,
253}
254
255#[derive(TlsSerialize, TlsSize)]
273struct TargetedMessageTBS<'a> {
274 version: ProtocolVersion,
275 wire_format: WireFormat,
276 group_id: &'a GroupId,
277 epoch: GroupEpoch,
278 recipient_leaf_index: u32,
279 authenticated_data: VLByteSlice<'a>,
280 sender_leaf_index: u32,
281 kem_output: VLByteSlice<'a>,
282 ciphertext_hash: VLByteSlice<'a>,
283}
284
285#[derive(TlsSerialize, TlsSize)]
299struct TargetedMessageTBM<'a> {
300 group_id: &'a GroupId,
301 epoch: GroupEpoch,
302 recipient_leaf_index: u32,
303 authenticated_data: VLByteSlice<'a>,
304 sender_leaf_index: u32,
305 kem_output: VLByteSlice<'a>,
306}
307
308#[derive(TlsSerialize, TlsSize)]
318struct TargetedMessagePskId<'a> {
319 group_id: &'a GroupId,
320 epoch: GroupEpoch,
321 label: VLByteSlice<'a>,
322}
323
324impl<'a> TargetedMessagePskId<'a> {
325 fn new(group_id: &'a GroupId, epoch: GroupEpoch) -> Self {
326 Self {
327 group_id,
328 epoch,
329 label: VLByteSlice(PSK_LABEL.as_bytes()),
330 }
331 }
332}
333
334pub(crate) struct TargetedMessageGroupContext<'a> {
338 pub ciphersuite: Ciphersuite,
339 pub group_id: &'a GroupId,
340 pub epoch: GroupEpoch,
341 pub exporter_secret: &'a crate::schedule::ExporterSecret,
342}
343
344#[derive(Debug, Clone, PartialEq)]
346pub struct ProcessedTargetedMessage {
347 sender_leaf_index: LeafNodeIndex,
348 application_data: Vec<u8>,
349 authenticated_data: Vec<u8>,
350}
351
352impl ProcessedTargetedMessage {
353 pub fn sender_leaf_index(&self) -> LeafNodeIndex {
355 self.sender_leaf_index
356 }
357
358 pub fn application_data(&self) -> &[u8] {
360 &self.application_data
361 }
362
363 pub fn authenticated_data(&self) -> &[u8] {
365 &self.authenticated_data
366 }
367
368 pub fn into_data(self) -> (Vec<u8>, Vec<u8>) {
370 (self.application_data, self.authenticated_data)
371 }
372}
373
374fn derive_targeted_message_psk(
376 crypto: &impl OpenMlsCrypto,
377 ciphersuite: Ciphersuite,
378 exporter_secret: &crate::schedule::ExporterSecret,
379) -> Result<Vec<u8>, LibraryError> {
380 exporter_secret
381 .derive_exported_secret(
382 ciphersuite,
383 crypto,
384 TARGETED_MESSAGE_EXPORTER_LABEL,
385 PSK_SUBLABEL.as_bytes(),
386 ciphersuite.hash_length(),
387 )
388 .map_err(LibraryError::unexpected_crypto_error)
389}
390
391fn derive_sender_auth_data_secret(
393 crypto: &impl OpenMlsCrypto,
394 ciphersuite: Ciphersuite,
395 exporter_secret: &crate::schedule::ExporterSecret,
396) -> Result<Secret, LibraryError> {
397 let secret_bytes = exporter_secret
398 .derive_exported_secret(
399 ciphersuite,
400 crypto,
401 TARGETED_MESSAGE_EXPORTER_LABEL,
402 SENDER_AUTH_DATA_SECRET_SUBLABEL.as_bytes(),
403 ciphersuite.hash_length(),
404 )
405 .map_err(LibraryError::unexpected_crypto_error)?;
406 Ok(Secret::from_slice(&secret_bytes))
407}
408
409fn derive_sender_auth_data_key_nonce(
411 crypto: &impl OpenMlsCrypto,
412 ciphersuite: Ciphersuite,
413 sender_auth_data_secret: &Secret,
414 ciphertext: &[u8],
415) -> Result<(AeadKey, AeadNonce), LibraryError> {
416 let sample_len = ciphersuite.hash_length().min(ciphertext.len());
417 let ciphertext_sample = &ciphertext[..sample_len];
418
419 let key_secret = sender_auth_data_secret
420 .kdf_expand_label(
421 crypto,
422 ciphersuite,
423 "key",
424 ciphertext_sample,
425 ciphersuite.aead_key_length(),
426 )
427 .map_err(LibraryError::unexpected_crypto_error)?;
428
429 let nonce_secret = sender_auth_data_secret
430 .kdf_expand_label(
431 crypto,
432 ciphersuite,
433 "nonce",
434 ciphertext_sample,
435 ciphersuite.aead_nonce_length(),
436 )
437 .map_err(LibraryError::unexpected_crypto_error)?;
438
439 Ok((
440 AeadKey::from_secret(key_secret, ciphersuite),
441 AeadNonce::from_secret(nonce_secret),
442 ))
443}
444
445struct TargetedMessageTBSPayload {
447 serialized: Vec<u8>,
448}
449
450impl Signable for TargetedMessageTBSPayload {
451 type SignedOutput = TargetedMessageSignature;
452
453 fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
454 Ok(self.serialized.clone())
455 }
456
457 fn label(&self) -> &str {
458 TARGETED_MESSAGE_TBS_LABEL
459 }
460}
461
462struct TargetedMessageSignature(pub(crate) Signature);
463
464impl SignedStruct<TargetedMessageTBSPayload> for TargetedMessageSignature {
465 fn from_payload(
466 _payload: TargetedMessageTBSPayload,
467 signature: Signature,
468 _serialized_payload: Vec<u8>,
469 ) -> Self {
470 Self(signature)
471 }
472}
473
474struct VerifiableTargetedMessageTBS {
476 serialized: Vec<u8>,
477 signature: Signature,
478}
479
480impl Verifiable for VerifiableTargetedMessageTBS {
481 type VerifiedStruct = VerifiedTargetedMessage;
482
483 fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
484 Ok(self.serialized.clone())
485 }
486
487 fn signature(&self) -> &Signature {
488 &self.signature
489 }
490
491 fn label(&self) -> &str {
492 TARGETED_MESSAGE_TBS_LABEL
493 }
494
495 fn verify(
496 self,
497 crypto: &impl OpenMlsCrypto,
498 pk: &crate::ciphersuite::OpenMlsSignaturePublicKey,
499 ) -> Result<Self::VerifiedStruct, crate::ciphersuite::signable::SignatureError> {
500 self.verify_no_out(crypto, pk)?;
501 Ok(VerifiedTargetedMessage)
502 }
503}
504
505struct VerifiedTargetedMessage;
506impl VerifiedStruct for VerifiedTargetedMessage {}
507
508#[allow(clippy::too_many_arguments)]
510pub(crate) fn create_targeted_message(
511 crypto: &impl OpenMlsCrypto,
512 signer: &impl Signer,
513 ctx: &TargetedMessageGroupContext<'_>,
514 sender_leaf_index: LeafNodeIndex,
515 recipient_leaf_index: LeafNodeIndex,
516 recipient_encryption_key: &EncryptionKey,
517 authenticated_data: &[u8],
518 application_data: &[u8],
519 padding_length: usize,
520) -> Result<TargetedMessage, CreateTargetedMessageError> {
521 let psk = derive_targeted_message_psk(crypto, ctx.ciphersuite, ctx.exporter_secret)?;
522 let sender_auth_data_secret =
523 derive_sender_auth_data_secret(crypto, ctx.ciphersuite, ctx.exporter_secret)?;
524
525 let psk_id = TargetedMessagePskId::new(ctx.group_id, ctx.epoch);
526 let psk_id_bytes = psk_id
527 .tls_serialize_detached()
528 .map_err(LibraryError::missing_bound_check)?;
529
530 let content = TargetedMessageContent::new(application_data, padding_length);
531 let content_bytes = content
532 .serialize_detached()
533 .map_err(LibraryError::missing_bound_check)?;
534
535 let hpke_ct = recipient_encryption_key.encrypt_with_label_psk_resolved_aad(
536 crate::ciphersuite::hpke::PskEncryptParams {
537 label: TARGETED_MESSAGE_DATA_LABEL,
538 context: &[],
541 psk: &psk,
542 psk_id: &psk_id_bytes,
543 ciphersuite: ctx.ciphersuite,
544 },
545 &content_bytes,
546 crypto,
547 |kem_output| {
548 let tbm = TargetedMessageTBM {
549 group_id: ctx.group_id,
550 epoch: ctx.epoch,
551 recipient_leaf_index: recipient_leaf_index.u32(),
552 authenticated_data: VLByteSlice(authenticated_data),
553 sender_leaf_index: sender_leaf_index.u32(),
554 kem_output: VLByteSlice(kem_output),
555 };
556 tbm.tls_serialize_detached()
557 .map_err(LibraryError::missing_bound_check)
558 },
559 )?;
560
561 let ciphertext_hash = crypto
564 .hash(
565 ctx.ciphersuite.hash_algorithm(),
566 hpke_ct.ciphertext.as_slice(),
567 )
568 .map_err(LibraryError::unexpected_crypto_error)?;
569
570 let tbs = TargetedMessageTBS {
571 version: ProtocolVersion::default(),
572 wire_format: WireFormat::TargetedMessage,
573 group_id: ctx.group_id,
574 epoch: ctx.epoch,
575 recipient_leaf_index: recipient_leaf_index.u32(),
576 authenticated_data: VLByteSlice(authenticated_data),
577 sender_leaf_index: sender_leaf_index.u32(),
578 kem_output: VLByteSlice(hpke_ct.kem_output.as_slice()),
579 ciphertext_hash: VLByteSlice(&ciphertext_hash),
580 };
581 let tbs_bytes = tbs
582 .tls_serialize_detached()
583 .map_err(LibraryError::missing_bound_check)?;
584
585 let tbs_payload = TargetedMessageTBSPayload {
586 serialized: tbs_bytes,
587 };
588 let signature = tbs_payload.sign(signer).map_err(|e| {
589 log::error!("Signing targeted message failed: {e:?}");
590 LibraryError::custom("Signing targeted message failed")
591 })?;
592
593 let sender_auth_data = TargetedMessageSenderAuthData {
594 sender_leaf_index: sender_leaf_index.u32(),
595 signature: signature.0,
596 kem_output: hpke_ct.kem_output.as_slice().to_vec().into(),
597 };
598 let sender_auth_data_bytes = sender_auth_data
599 .tls_serialize_detached()
600 .map_err(LibraryError::missing_bound_check)?;
601
602 let (key, nonce) = derive_sender_auth_data_key_nonce(
604 crypto,
605 ctx.ciphersuite,
606 &sender_auth_data_secret,
607 hpke_ct.ciphertext.as_slice(),
608 )?;
609
610 let sender_auth_aad = SenderAuthDataAAD {
611 group_id: ctx.group_id,
612 epoch: ctx.epoch,
613 recipient_leaf_index: recipient_leaf_index.u32(),
614 };
615 let sender_auth_aad_bytes = sender_auth_aad
616 .tls_serialize_detached()
617 .map_err(LibraryError::missing_bound_check)?;
618
619 let encrypted_sender_auth_data = key
620 .aead_seal(
621 crypto,
622 &sender_auth_data_bytes,
623 &sender_auth_aad_bytes,
624 &nonce,
625 )
626 .map_err(LibraryError::unexpected_crypto_error)?;
627
628 Ok(TargetedMessage {
629 group_id: ctx.group_id.clone(),
630 epoch: ctx.epoch,
631 recipient_leaf_index: recipient_leaf_index.u32(),
632 authenticated_data: authenticated_data.to_vec().into(),
633 encrypted_sender_auth_data: encrypted_sender_auth_data.into(),
634 ciphertext: hpke_ct.ciphertext,
635 })
636}
637
638pub(crate) fn process_targeted_message<StorageError>(
640 crypto: &impl OpenMlsCrypto,
641 ctx: &TargetedMessageGroupContext<'_>,
642 own_leaf_index: LeafNodeIndex,
643 own_encryption_private_key: &EncryptionPrivateKey,
644 message: &TargetedMessageIn,
645 leaves: &[Option<&LeafNode>],
646) -> Result<ProcessedTargetedMessage, ProcessTargetedMessageError<StorageError>> {
647 if &message.group_id != ctx.group_id {
649 return Err(ProcessTargetedMessageError::GroupIdMismatch);
650 }
651
652 if message.epoch != ctx.epoch {
654 return Err(ProcessTargetedMessageError::EpochMismatch);
655 }
656
657 if message.recipient_leaf_index != own_leaf_index.u32() {
659 return Err(ProcessTargetedMessageError::NotIntendedRecipient);
660 }
661
662 let sender_auth_data_secret =
663 derive_sender_auth_data_secret(crypto, ctx.ciphersuite, ctx.exporter_secret)?;
664
665 let (key, nonce) = derive_sender_auth_data_key_nonce(
667 crypto,
668 ctx.ciphersuite,
669 &sender_auth_data_secret,
670 message.ciphertext.as_slice(),
671 )?;
672
673 let sender_auth_aad = SenderAuthDataAAD {
674 group_id: ctx.group_id,
675 epoch: ctx.epoch,
676 recipient_leaf_index: own_leaf_index.u32(),
677 };
678 let sender_auth_aad_bytes = sender_auth_aad
679 .tls_serialize_detached()
680 .map_err(LibraryError::missing_bound_check)?;
681
682 let sender_auth_data_bytes = key
684 .aead_open(
685 crypto,
686 message.encrypted_sender_auth_data.as_slice(),
687 &sender_auth_aad_bytes,
688 &nonce,
689 )
690 .map_err(|e| {
691 log::error!("Targeted message sender auth data decryption failed: {e:?}");
692 ProcessTargetedMessageError::SenderAuthDataDecryptionFailed
693 })?;
694
695 let sender_auth_data =
696 TargetedMessageSenderAuthData::tls_deserialize_exact_bytes(&sender_auth_data_bytes)
697 .map_err(|e| {
698 log::error!("Targeted message sender auth data is malformed: {e:?}");
699 ProcessTargetedMessageError::MalformedSenderAuthData
700 })?;
701
702 let sender_leaf_index = LeafNodeIndex::new(sender_auth_data.sender_leaf_index);
703
704 let sender_leaf = leaves
705 .get(sender_leaf_index.usize())
706 .and_then(|opt| opt.as_ref())
707 .ok_or(ProcessTargetedMessageError::SenderNotFound)?;
708 let sender_signature_key = OpenMlsSignaturePublicKey::from_signature_key(
709 sender_leaf.signature_key().clone(),
710 ctx.ciphersuite.signature_algorithm(),
711 );
712
713 let ciphertext_hash = crypto
716 .hash(
717 ctx.ciphersuite.hash_algorithm(),
718 message.ciphertext.as_slice(),
719 )
720 .map_err(LibraryError::unexpected_crypto_error)?;
721
722 let tbs = TargetedMessageTBS {
723 version: ProtocolVersion::default(),
724 wire_format: WireFormat::TargetedMessage,
725 group_id: ctx.group_id,
726 epoch: ctx.epoch,
727 recipient_leaf_index: own_leaf_index.u32(),
728 authenticated_data: VLByteSlice(message.authenticated_data.as_slice()),
729 sender_leaf_index: sender_auth_data.sender_leaf_index,
730 kem_output: VLByteSlice(sender_auth_data.kem_output.as_slice()),
731 ciphertext_hash: VLByteSlice(&ciphertext_hash),
732 };
733 let tbs_bytes = tbs
734 .tls_serialize_detached()
735 .map_err(LibraryError::missing_bound_check)?;
736
737 let verifiable = VerifiableTargetedMessageTBS {
738 serialized: tbs_bytes,
739 signature: sender_auth_data.signature.clone(),
740 };
741
742 verifiable
743 .verify(crypto, &sender_signature_key)
744 .map_err(|e| {
745 log::error!("Targeted message signature verification failed: {e:?}");
746 ProcessTargetedMessageError::SignatureVerificationFailed
747 })?;
748
749 let psk = derive_targeted_message_psk(crypto, ctx.ciphersuite, ctx.exporter_secret)?;
751
752 let psk_id = TargetedMessagePskId::new(ctx.group_id, ctx.epoch);
753 let psk_id_bytes = psk_id
754 .tls_serialize_detached()
755 .map_err(LibraryError::missing_bound_check)?;
756
757 let tbm = TargetedMessageTBM {
758 group_id: ctx.group_id,
759 epoch: ctx.epoch,
760 recipient_leaf_index: own_leaf_index.u32(),
761 authenticated_data: VLByteSlice(message.authenticated_data.as_slice()),
762 sender_leaf_index: sender_auth_data.sender_leaf_index,
763 kem_output: VLByteSlice(sender_auth_data.kem_output.as_slice()),
764 };
765 let tbm_bytes = tbm
766 .tls_serialize_detached()
767 .map_err(LibraryError::missing_bound_check)?;
768
769 let hpke_ciphertext = HpkeCiphertext {
770 kem_output: sender_auth_data.kem_output.as_slice().to_vec().into(),
771 ciphertext: message.ciphertext.as_slice().to_vec().into(),
772 };
773
774 let content_bytes = own_encryption_private_key
775 .decrypt_with_label_psk_aad(
776 crate::ciphersuite::hpke::PskEncryptParams {
777 label: TARGETED_MESSAGE_DATA_LABEL,
778 context: &[],
781 psk: &psk,
782 psk_id: &psk_id_bytes,
783 ciphersuite: ctx.ciphersuite,
784 },
785 &tbm_bytes,
786 &hpke_ciphertext,
787 crypto,
788 )
789 .map_err(|e| {
790 log::error!("Targeted message content decryption failed: {e:?}");
791 ProcessTargetedMessageError::ContentDecryptionFailed
792 })?;
793
794 let content = TargetedMessageContent::deserialize_detached(&content_bytes).map_err(|e| {
795 log::error!("Targeted message content is malformed: {e:?}");
796 ProcessTargetedMessageError::MalformedContent
797 })?;
798
799 Ok(ProcessedTargetedMessage {
800 sender_leaf_index,
801 application_data: content.application_data().to_vec(),
802 authenticated_data: message.authenticated_data.as_slice().to_vec(),
803 })
804}