core_crypto/
identity.rs

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