• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 // Copyright by contributors to this project.
3 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
4 
5 use crate::CipherSuiteProvider;
6 use crate::{client::MlsError, group::transcript_hash::ConfirmedTranscriptHash};
7 use alloc::vec::Vec;
8 use core::{
9     fmt::{self, Debug},
10     ops::Deref,
11 };
12 use mls_rs_codec::{MlsDecode, MlsEncode, MlsSize};
13 use mls_rs_core::error::IntoAnyError;
14 
15 #[derive(Clone, PartialEq, MlsSize, MlsEncode, MlsDecode)]
16 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
17 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18 pub struct ConfirmationTag(
19     #[mls_codec(with = "mls_rs_codec::byte_vec")]
20     #[cfg_attr(feature = "serde", serde(with = "mls_rs_core::vec_serde"))]
21     Vec<u8>,
22 );
23 
24 impl Debug for ConfirmationTag {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result25     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26         mls_rs_core::debug::pretty_bytes(&self.0)
27             .named("ConfirmationTag")
28             .fmt(f)
29     }
30 }
31 
32 impl Deref for ConfirmationTag {
33     type Target = Vec<u8>;
deref(&self) -> &Self::Target34     fn deref(&self) -> &Self::Target {
35         &self.0
36     }
37 }
38 
39 impl ConfirmationTag {
40     #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
create<P: CipherSuiteProvider>( confirmation_key: &[u8], confirmed_transcript_hash: &ConfirmedTranscriptHash, cipher_suite_provider: &P, ) -> Result<Self, MlsError>41     pub(crate) async fn create<P: CipherSuiteProvider>(
42         confirmation_key: &[u8],
43         confirmed_transcript_hash: &ConfirmedTranscriptHash,
44         cipher_suite_provider: &P,
45     ) -> Result<Self, MlsError> {
46         cipher_suite_provider
47             .mac(confirmation_key, confirmed_transcript_hash)
48             .await
49             .map(ConfirmationTag)
50             .map_err(|e| MlsError::CryptoProviderError(e.into_any_error()))
51     }
52 
53     #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
matches<P: CipherSuiteProvider>( &self, confirmation_key: &[u8], confirmed_transcript_hash: &ConfirmedTranscriptHash, cipher_suite_provider: &P, ) -> Result<bool, MlsError>54     pub(crate) async fn matches<P: CipherSuiteProvider>(
55         &self,
56         confirmation_key: &[u8],
57         confirmed_transcript_hash: &ConfirmedTranscriptHash,
58         cipher_suite_provider: &P,
59     ) -> Result<bool, MlsError> {
60         let tag = ConfirmationTag::create(
61             confirmation_key,
62             confirmed_transcript_hash,
63             cipher_suite_provider,
64         )
65         .await?;
66 
67         Ok(&tag == self)
68     }
69 }
70 
71 #[cfg(test)]
72 impl ConfirmationTag {
73     #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
empty<P: CipherSuiteProvider>(cipher_suite_provider: &P) -> Self74     pub(crate) async fn empty<P: CipherSuiteProvider>(cipher_suite_provider: &P) -> Self {
75         Self(
76             cipher_suite_provider
77                 .mac(
78                     &alloc::vec![0; cipher_suite_provider.kdf_extract_size()],
79                     &[],
80                 )
81                 .await
82                 .unwrap(),
83         )
84     }
85 }
86 
87 #[cfg(test)]
88 mod tests {
89     use super::*;
90     use crate::crypto::test_utils::{test_cipher_suite_provider, TestCryptoProvider};
91 
92     #[cfg(target_arch = "wasm32")]
93     use wasm_bindgen_test::wasm_bindgen_test as test;
94 
95     #[maybe_async::test(not(mls_build_async), async(mls_build_async, crate::futures_test))]
test_confirmation_tag_matching()96     async fn test_confirmation_tag_matching() {
97         for cipher_suite in TestCryptoProvider::all_supported_cipher_suites() {
98             let cipher_suite_provider = test_cipher_suite_provider(cipher_suite);
99 
100             let confirmed_hash_a = ConfirmedTranscriptHash::from(b"foo_a".to_vec());
101 
102             let confirmation_key_a = b"bar_a".to_vec();
103 
104             let confirmed_hash_b = ConfirmedTranscriptHash::from(b"foo_b".to_vec());
105 
106             let confirmation_key_b = b"bar_b".to_vec();
107 
108             let confirmation_tag = ConfirmationTag::create(
109                 &confirmation_key_a,
110                 &confirmed_hash_a,
111                 &cipher_suite_provider,
112             )
113             .await
114             .unwrap();
115 
116             let matches = confirmation_tag
117                 .matches(
118                     &confirmation_key_a,
119                     &confirmed_hash_a,
120                     &cipher_suite_provider,
121                 )
122                 .await
123                 .unwrap();
124 
125             assert!(matches);
126 
127             let matches = confirmation_tag
128                 .matches(
129                     &confirmation_key_b,
130                     &confirmed_hash_a,
131                     &cipher_suite_provider,
132                 )
133                 .await
134                 .unwrap();
135 
136             assert!(!matches);
137 
138             let matches = confirmation_tag
139                 .matches(
140                     &confirmation_key_a,
141                     &confirmed_hash_b,
142                     &cipher_suite_provider,
143                 )
144                 .await
145                 .unwrap();
146 
147             assert!(!matches);
148         }
149     }
150 }
151