1use openmls_traits::crypto::OpenMlsCrypto;
4use openmls_traits::types::Ciphersuite;
5use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
6use thiserror::Error;
7use tls_codec::{
8 Deserialize, Serialize as TlsSerializeTrait, TlsDeserialize, TlsDeserializeBytes, TlsSerialize,
9 TlsSize,
10};
11
12use crate::{
13 binary_tree::LeafNodeIndex,
14 ciphersuite::{
15 signable::{Signable, SignedStruct, Verifiable, VerifiedStruct},
16 AeadKey, AeadNonce, Signature,
17 },
18 extensions::Extensions,
19 group::{GroupContext, GroupEpoch, GroupId},
20 messages::ConfirmationTag,
21};
22
23const SIGNATURE_GROUP_INFO_LABEL: &str = "GroupInfoTBS";
24
25#[derive(Debug, PartialEq, Clone, TlsDeserialize, TlsDeserializeBytes, TlsSize)]
31#[cfg_attr(any(test, feature = "test-utils"), derive(TlsSerialize))]
32pub struct VerifiableGroupInfo {
33 payload: GroupInfoTBS,
34 signature: Signature,
35}
36
37#[derive(Error, Debug, PartialEq, Clone)]
39pub enum GroupInfoError {
40 #[error("Decryption failed.")]
42 DecryptionFailed,
43 #[error("Malformed.")]
45 Malformed,
46}
47
48impl VerifiableGroupInfo {
49 pub fn new(
51 group_context: GroupContext,
52 extensions: Extensions,
53 confirmation_tag: ConfirmationTag,
54 signer: LeafNodeIndex,
55 signature: Signature,
56 ) -> Self {
57 let payload = GroupInfoTBS {
58 group_context,
59 extensions,
60 confirmation_tag,
61 signer,
62 };
63 Self { payload, signature }
64 }
65
66 pub(crate) fn try_from_ciphertext(
67 skey: &AeadKey,
68 nonce: &AeadNonce,
69 ciphertext: &[u8],
70 context: &[u8],
71 crypto: &impl OpenMlsCrypto,
72 ) -> Result<Self, GroupInfoError> {
73 let verifiable_group_info_plaintext = skey
74 .aead_open(crypto, ciphertext, context, nonce)
75 .map_err(|_| GroupInfoError::DecryptionFailed)?;
76
77 let mut verifiable_group_info_plaintext_slice = verifiable_group_info_plaintext.as_slice();
78
79 let verifiable_group_info =
80 VerifiableGroupInfo::tls_deserialize(&mut verifiable_group_info_plaintext_slice)
81 .map_err(|_| GroupInfoError::Malformed)?;
82
83 if !verifiable_group_info_plaintext_slice.is_empty() {
84 return Err(GroupInfoError::Malformed);
85 }
86
87 Ok(verifiable_group_info)
88 }
89
90 pub fn ciphersuite(&self) -> Ciphersuite {
94 self.payload.group_context.ciphersuite()
95 }
96
97 pub(crate) fn signer(&self) -> LeafNodeIndex {
101 self.payload.signer
102 }
103
104 pub fn extensions(&self) -> &Extensions {
108 &self.payload.extensions
109 }
110
111 pub fn group_id(&self) -> &GroupId {
116 self.payload.group_context.group_id()
117 }
118
119 pub fn epoch(&self) -> GroupEpoch {
124 self.payload.group_context.epoch()
125 }
126}
127
128#[cfg(test)]
129impl VerifiableGroupInfo {
130 pub(crate) fn payload_mut(&mut self) -> &mut GroupInfoTBS {
131 &mut self.payload
132 }
133
134 pub(crate) fn break_signature(&mut self) {
136 self.signature.modify(b"");
137 }
138}
139
140#[cfg(any(feature = "test-utils", test))]
141impl From<VerifiableGroupInfo> for GroupInfo {
142 fn from(vgi: VerifiableGroupInfo) -> Self {
143 GroupInfo {
144 payload: vgi.payload,
145 signature: vgi.signature,
146 serialized_payload: None,
147 }
148 }
149}
150
151#[derive(Debug, PartialEq, Clone, TlsSize, SerdeSerialize, SerdeDeserialize)]
168#[cfg_attr(feature = "test-utils", derive(TlsDeserialize))]
169pub struct GroupInfo {
170 payload: GroupInfoTBS,
171 signature: Signature,
172 #[serde(skip)]
173 #[tls_codec(skip)]
174 serialized_payload: Option<Vec<u8>>,
175}
176
177impl TlsSerializeTrait for GroupInfo {
178 fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
179 let mut written = 0;
180 if let Some(ref bytes) = self.serialized_payload {
181 written += writer.write(bytes)?;
182 } else {
183 written += self.payload.tls_serialize(writer)?;
184 }
185 written += self.signature.tls_serialize(writer)?;
186 Ok(written)
187 }
188}
189
190impl GroupInfo {
191 pub fn group_context(&self) -> &GroupContext {
193 &self.payload.group_context
194 }
195
196 pub fn extensions(&self) -> &Extensions {
198 &self.payload.extensions
199 }
200
201 pub fn signature(&self) -> &Signature {
203 &self.signature
204 }
205
206 pub(crate) fn confirmation_tag(&self) -> &ConfirmationTag {
208 &self.payload.confirmation_tag
209 }
210
211 #[cfg(any(feature = "test-utils", test))]
212 pub(crate) fn into_verifiable_group_info(self) -> VerifiableGroupInfo {
213 VerifiableGroupInfo {
214 payload: GroupInfoTBS {
215 group_context: self.payload.group_context,
216 extensions: self.payload.extensions,
217 confirmation_tag: self.payload.confirmation_tag,
218 signer: self.payload.signer,
219 },
220 signature: self.signature,
221 }
222 }
223}
224
225#[derive(
238 Debug,
239 PartialEq,
240 Clone,
241 TlsDeserialize,
242 TlsDeserializeBytes,
243 TlsSerialize,
244 TlsSize,
245 SerdeSerialize,
246 SerdeDeserialize,
247)]
248pub(crate) struct GroupInfoTBS {
249 group_context: GroupContext,
250 extensions: Extensions,
251 confirmation_tag: ConfirmationTag,
252 signer: LeafNodeIndex,
253}
254
255impl GroupInfoTBS {
256 pub(crate) fn new(
258 group_context: GroupContext,
259 extensions: Extensions,
260 confirmation_tag: ConfirmationTag,
261 signer: LeafNodeIndex,
262 ) -> Self {
263 Self {
264 group_context,
265 extensions,
266 confirmation_tag,
267 signer,
268 }
269 }
270}
271
272#[cfg(test)]
273impl GroupInfoTBS {
274 pub(crate) fn group_context_mut(&mut self) -> &mut GroupContext {
275 &mut self.group_context
276 }
277}
278
279impl Signable for GroupInfoTBS {
282 type SignedOutput = GroupInfo;
283
284 fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
285 self.tls_serialize_detached()
286 }
287
288 fn label(&self) -> &str {
289 SIGNATURE_GROUP_INFO_LABEL
290 }
291}
292
293impl SignedStruct<GroupInfoTBS> for GroupInfo {
294 fn from_payload(
295 payload: GroupInfoTBS,
296 signature: Signature,
297 serialized_payload: Vec<u8>,
298 ) -> Self {
299 Self {
300 payload,
301 signature,
302 serialized_payload: Some(serialized_payload),
303 }
304 }
305}
306
307impl Verifiable for VerifiableGroupInfo {
308 type VerifiedStruct = GroupInfo;
309
310 fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
311 self.payload.tls_serialize_detached()
312 }
313
314 fn signature(&self) -> &Signature {
315 &self.signature
316 }
317
318 fn label(&self) -> &str {
319 SIGNATURE_GROUP_INFO_LABEL
320 }
321
322 fn verify(
323 self,
324 crypto: &impl OpenMlsCrypto,
325 pk: &crate::ciphersuite::OpenMlsSignaturePublicKey,
326 ) -> Result<Self::VerifiedStruct, crate::ciphersuite::signable::SignatureError> {
327 self.verify_no_out(crypto, pk)?;
328 Ok(GroupInfo {
329 payload: self.payload,
330 signature: self.signature,
331 serialized_payload: None,
332 })
333 }
334}
335
336impl VerifiedStruct for GroupInfo {}