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