Skip to main content

core_crypto/
identity.rs

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