core_crypto/e2e_identity/
identity.rs

1use std::str::FromStr;
2
3use x509_cert::der::pem::LineEnding;
4
5use super::{Error, Result};
6use crate::{
7    MlsCredentialType,
8    e2e_identity::{device_status::DeviceStatus, id::WireQualifiedClientId},
9};
10
11/// Represents the identity claims identifying a client
12/// Those claims are verifiable by any member in the group
13#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
14pub struct WireIdentity {
15    /// Unique client identifier e.g. `T4Coy4vdRzianwfOgXpn6A:6add501bacd1d90e@whitehouse.gov`
16    pub client_id: String,
17    /// MLS thumbprint
18    pub thumbprint: String,
19    /// Status of the Credential at the moment T when this object is created
20    pub status: DeviceStatus,
21    /// Indicates whether the credential is Basic or X509
22    pub credential_type: MlsCredentialType,
23    /// In case 'credential_type' is [MlsCredentialType::X509] this is populated
24    pub x509_identity: Option<X509Identity>,
25}
26
27/// Represents the parts of [WireIdentity] that are specific to a X509 certificate (and not a Basic one).
28///
29/// We don't use an enum here since the sole purpose of this is to be exposed through the FFI (and
30/// union types are impossible to carry over the FFI boundary)
31#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
32pub struct X509Identity {
33    /// user handle e.g. `john_wire`
34    pub handle: String,
35    /// Name as displayed in the messaging application e.g. `John Fitzgerald Kennedy`
36    pub display_name: String,
37    /// DNS domain for which this identity proof was generated e.g. `whitehouse.gov`
38    pub domain: String,
39    /// X509 certificate identifying this client in the MLS group ; PEM encoded
40    pub certificate: String,
41    /// X509 certificate serial number
42    pub serial_number: String,
43    /// X509 certificate not before as Unix timestamp
44    pub not_before: u64,
45    /// X509 certificate not after as Unix timestamp
46    pub not_after: u64,
47}
48
49impl<'a> TryFrom<(wire_e2e_identity::prelude::WireIdentity, &'a [u8])> for WireIdentity {
50    type Error = Error;
51
52    fn try_from((i, cert): (wire_e2e_identity::prelude::WireIdentity, &'a [u8])) -> Result<Self> {
53        use x509_cert::der::Decode as _;
54        let document = x509_cert::der::Document::from_der(cert)?;
55        let certificate = document.to_pem("CERTIFICATE", LineEnding::LF)?;
56
57        let client_id = WireQualifiedClientId::from_str(&i.client_id)?;
58
59        Ok(Self {
60            client_id: client_id.try_into()?,
61            status: i.status.into(),
62            thumbprint: i.thumbprint,
63            credential_type: MlsCredentialType::X509,
64            x509_identity: Some(X509Identity {
65                handle: i.handle.to_string(),
66                display_name: i.display_name,
67                domain: i.domain,
68                certificate,
69                serial_number: i.serial_number,
70                not_before: i.not_before,
71                not_after: i.not_after,
72            }),
73        })
74    }
75}