Skip to main content

core_crypto/
identity.rs

1use wire_e2e_identity::legacy::device_status::DeviceStatus;
2use x509_cert::der::pem::LineEnding;
3
4use super::{Error, 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, Eq, PartialEq, Ord, PartialOrd)]
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: DeviceStatus,
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, Ord, PartialOrd)]
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 = 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)
51            .map_err(wire_e2e_identity::E2eIdentityError::X509CertDerError)?;
52        let certificate = document
53            .to_pem("CERTIFICATE", LineEnding::LF)
54            .map_err(wire_e2e_identity::E2eIdentityError::X509CertDerError)?;
55
56        let client_id = ClientId::try_from_str_with_base64_user_id(&e2ei_wire_identity.client_id)
57            .map(Some)
58            .map_err(RecursiveError::mls_client("client id from qualified string"))?;
59
60        Ok(Self {
61            client_id,
62            status: e2ei_wire_identity.status.into(),
63            thumbprint: e2ei_wire_identity.thumbprint,
64            credential_type: CredentialType::X509,
65            x509_identity: Some(X509Identity {
66                handle: e2ei_wire_identity.handle.to_string(),
67                display_name: e2ei_wire_identity.display_name,
68                domain: e2ei_wire_identity.domain,
69                certificate,
70                serial_number: e2ei_wire_identity.serial_number,
71                not_before: e2ei_wire_identity.not_before,
72                not_after: e2ei_wire_identity.not_after,
73            }),
74        })
75    }
76}