1use std::io::{Read, Write};
28
29use openmls_traits::signatures::Signer;
30use serde::{Deserialize, Serialize};
31use tls_codec::{
32 Deserialize as TlsDeserializeTrait, DeserializeBytes, Error, Serialize as TlsSerializeTrait,
33 Size, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize, VLBytes,
34};
35
36#[cfg(test)]
37mod tests;
38
39use crate::{ciphersuite::SignaturePublicKey, group::Member, treesync::LeafNode};
40use errors::*;
41
42#[cfg(doc)]
43use crate::group::MlsGroup;
44
45pub mod errors;
47
48#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
81#[cfg_attr(
82 feature = "0-8-1-storage-format",
83 derive(serde::Serialize, serde::Deserialize)
84)]
85#[cfg_attr(
86 not(feature = "0-8-1-storage-format"),
87 derive(
88 openmls_serialization_helpers::Serialize,
89 openmls_serialization_helpers::Deserialize,
90 )
91)]
92#[repr(u16)]
93pub enum CredentialType {
94 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 0)]
95 Basic = 1,
97 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 1)]
98 X509 = 2,
100 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 3)]
101 Grease(u16),
103 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 2)]
104 Other(u16),
106}
107
108impl CredentialType {
109 pub fn is_grease(&self) -> bool {
114 matches!(self, CredentialType::Grease(_))
115 }
116}
117
118impl Size for CredentialType {
119 fn tls_serialized_len(&self) -> usize {
120 2
121 }
122}
123
124impl TlsDeserializeTrait for CredentialType {
125 fn tls_deserialize<R: Read>(bytes: &mut R) -> Result<Self, Error>
126 where
127 Self: Sized,
128 {
129 let mut extension_type = [0u8; 2];
130 bytes.read_exact(&mut extension_type)?;
131
132 Ok(CredentialType::from(u16::from_be_bytes(extension_type)))
133 }
134}
135
136impl TlsSerializeTrait for CredentialType {
137 fn tls_serialize<W: Write>(&self, writer: &mut W) -> Result<usize, Error> {
138 writer.write_all(&u16::from(*self).to_be_bytes())?;
139
140 Ok(2)
141 }
142}
143
144impl DeserializeBytes for CredentialType {
145 fn tls_deserialize_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error>
146 where
147 Self: Sized,
148 {
149 let mut bytes_ref = bytes;
150 let credential_type = CredentialType::tls_deserialize(&mut bytes_ref)?;
151 Ok((credential_type, bytes_ref))
152 }
153}
154
155impl From<u16> for CredentialType {
156 fn from(value: u16) -> Self {
157 match value {
158 1 => CredentialType::Basic,
159 2 => CredentialType::X509,
160 other if crate::grease::is_grease_value(other) => CredentialType::Grease(other),
161 other => CredentialType::Other(other),
162 }
163 }
164}
165
166impl From<CredentialType> for u16 {
167 fn from(value: CredentialType) -> Self {
168 match value {
169 CredentialType::Basic => 1,
170 CredentialType::X509 => 2,
171 CredentialType::Grease(value) => value,
172 CredentialType::Other(other) => other,
173 }
174 }
175}
176
177#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
188pub struct Certificate {
189 cert_data: Vec<u8>,
190}
191
192#[derive(
222 Debug,
223 PartialEq,
224 Eq,
225 Clone,
226 Serialize,
227 Deserialize,
228 TlsSize,
229 TlsSerialize,
230 TlsDeserialize,
231 TlsDeserializeBytes,
232)]
233pub struct Credential {
234 credential_type: CredentialType,
235 serialized_credential_content: VLBytes,
236}
237
238impl Credential {
239 pub fn credential_type(&self) -> CredentialType {
241 self.credential_type
242 }
243
244 pub fn new(credential_type: CredentialType, serialized_credential: Vec<u8>) -> Self {
247 Self {
248 credential_type,
249 serialized_credential_content: serialized_credential.into(),
250 }
251 }
252
253 pub fn serialized_content(&self) -> &[u8] {
258 self.serialized_credential_content.as_slice()
259 }
260
261 pub fn deserialized<T: tls_codec::Size + tls_codec::Deserialize>(
263 &self,
264 ) -> Result<T, tls_codec::Error> {
265 T::tls_deserialize_exact(&self.serialized_credential_content)
266 }
267}
268
269#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
280pub struct BasicCredential {
281 identity: VLBytes,
282}
283
284impl BasicCredential {
285 pub fn new(identity: Vec<u8>) -> Self {
292 Self {
293 identity: identity.into(),
294 }
295 }
296
297 pub fn identity(&self) -> &[u8] {
299 self.identity.as_slice()
300 }
301}
302
303impl From<BasicCredential> for Credential {
304 fn from(credential: BasicCredential) -> Self {
305 Credential {
306 credential_type: CredentialType::Basic,
307 serialized_credential_content: credential.identity,
308 }
309 }
310}
311
312impl TryFrom<Credential> for BasicCredential {
313 type Error = BasicCredentialError;
314
315 fn try_from(credential: Credential) -> Result<Self, Self::Error> {
316 match credential.credential_type {
317 CredentialType::Basic => Ok(BasicCredential::new(
318 credential.serialized_credential_content.into(),
319 )),
320 _ => Err(errors::BasicCredentialError::WrongCredentialType),
321 }
322 }
323}
324
325#[derive(Debug, Clone)]
329pub struct NewSignerBundle<'a, S: Signer> {
330 pub signer: &'a S,
332 pub credential_with_key: CredentialWithKey,
334}
335
336#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
337pub struct CredentialWithKey {
339 pub credential: Credential,
341 pub signature_key: SignaturePublicKey,
343}
344
345impl From<&LeafNode> for CredentialWithKey {
346 fn from(leaf_node: &LeafNode) -> Self {
347 Self {
348 credential: leaf_node.credential().clone(),
349 signature_key: leaf_node.signature_key().clone(),
350 }
351 }
352}
353
354impl From<&Member> for CredentialWithKey {
355 fn from(member: &Member) -> Self {
356 Self {
357 credential: member.credential.clone(),
358 signature_key: member.signature_key.clone().into(),
359 }
360 }
361}
362
363#[cfg(test)]
364impl CredentialWithKey {
365 pub fn from_parts(credential: Credential, key: &[u8]) -> Self {
366 Self {
367 credential,
368 signature_key: key.into(),
369 }
370 }
371}
372
373#[cfg(any(test, feature = "test-utils"))]
374pub mod test_utils {
375 use openmls_basic_credential::SignatureKeyPair;
376 use openmls_traits::{types::SignatureScheme, OpenMlsProvider};
377
378 use super::{BasicCredential, CredentialWithKey};
379
380 pub fn new_credential(
388 provider: &impl OpenMlsProvider,
389 identity: &[u8],
390 signature_scheme: SignatureScheme,
391 ) -> (CredentialWithKey, SignatureKeyPair) {
392 let credential = BasicCredential::new(identity.into());
393 let signature_keys = SignatureKeyPair::new(signature_scheme).unwrap();
394 signature_keys.store(provider.storage()).unwrap();
395
396 (
397 CredentialWithKey {
398 credential: credential.into(),
399 signature_key: signature_keys.public().into(),
400 },
401 signature_keys,
402 )
403 }
404}
405
406#[cfg(test)]
407mod unit_tests {
408 use tls_codec::{
409 DeserializeBytes, Serialize, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize,
410 };
411
412 use super::{BasicCredential, Credential, CredentialType};
413
414 #[test]
415 fn basic_credential_identity_and_codec() {
416 const IDENTITY: &str = "identity";
417 let basic_credential = BasicCredential::new(IDENTITY.into());
419 assert_eq!(basic_credential.identity(), IDENTITY.as_bytes());
420
421 let credential = Credential::from(basic_credential.clone());
423 let serialized = credential.tls_serialize_detached().unwrap();
424
425 let deserialized = Credential::tls_deserialize_exact_bytes(&serialized).unwrap();
426 assert_eq!(credential.credential_type(), deserialized.credential_type());
427 assert_eq!(
428 credential.serialized_content(),
429 deserialized.serialized_content()
430 );
431
432 let deserialized_basic_credential = BasicCredential::try_from(deserialized).unwrap();
433 assert_eq!(
434 deserialized_basic_credential.identity(),
435 IDENTITY.as_bytes()
436 );
437 assert_eq!(basic_credential, deserialized_basic_credential);
438 }
439
440 #[test]
442 fn custom_credential() {
443 #[derive(
444 Debug, Clone, PartialEq, Eq, TlsSize, TlsSerialize, TlsDeserialize, TlsDeserializeBytes,
445 )]
446 struct CustomCredential {
447 custom_field1: u32,
448 custom_field2: Vec<u8>,
449 custom_field3: Option<u8>,
450 }
451
452 let custom_credential = CustomCredential {
453 custom_field1: 42,
454 custom_field2: vec![1, 2, 3],
455 custom_field3: Some(2),
456 };
457
458 let credential = Credential::new(
459 CredentialType::Other(1234),
460 custom_credential.tls_serialize_detached().unwrap(),
461 );
462
463 let serialized = credential.tls_serialize_detached().unwrap();
464 let deserialized = Credential::tls_deserialize_exact_bytes(&serialized).unwrap();
465 assert_eq!(credential, deserialized);
466
467 let deserialized_custom_credential =
468 CustomCredential::tls_deserialize_exact_bytes(deserialized.serialized_content())
469 .unwrap();
470
471 assert_eq!(custom_credential, deserialized_custom_credential);
472 }
473}