Skip to main content

xmtp_id/key_package/
verified_key_package_v2.rs

1use super::WrapperEncryptionExtension;
2use openmls::{
3    credentials::{BasicCredential, errors::BasicCredentialError},
4    key_packages::Lifetime,
5    prelude::{
6        KeyPackage, KeyPackageIn, KeyPackageVerifyError,
7        tls_codec::{Deserialize, Error as TlsCodecError},
8    },
9};
10use openmls_rust_crypto::RustCrypto;
11use prost::Message;
12use std::panic::{self, AssertUnwindSafe};
13use thiserror::Error;
14use xmtp_common::ErrorCode;
15use xmtp_configuration::MLS_PROTOCOL_VERSION;
16use xmtp_configuration::WELCOME_WRAPPER_ENCRYPTION_EXTENSION_ID;
17use xmtp_proto::xmtp::identity::MlsCredential;
18
19#[derive(Debug, Error, ErrorCode)]
20pub enum KeyPackageVerificationError {
21    /// TLS codec error.
22    ///
23    /// MLS TLS encoding/decoding failed. Not retryable.
24    #[error("TLS Codec error: {0}")]
25    TlsError(#[from] TlsCodecError),
26    /// MLS validation error.
27    ///
28    /// Key package verification failed. Not retryable.
29    #[error("mls validation: {0}")]
30    MlsValidation(#[from] KeyPackageVerifyError),
31    /// Wrong credential type.
32    ///
33    /// Unexpected MLS credential type. Not retryable.
34    #[error("wrong credential type")]
35    WrongCredentialType(#[from] BasicCredentialError),
36    #[error(transparent)]
37    #[error_code(inherit)]
38    ConversionError(#[from] xmtp_proto::ConversionError),
39}
40
41impl From<prost::DecodeError> for KeyPackageVerificationError {
42    fn from(value: prost::DecodeError) -> Self {
43        Self::ConversionError(value.into())
44    }
45}
46
47pub struct VerifiedLifetime {
48    pub not_before: u64,
49    pub not_after: u64,
50}
51
52impl From<&Lifetime> for VerifiedLifetime {
53    fn from(value: &Lifetime) -> Self {
54        Self {
55            not_before: value.not_before(),
56            not_after: value.not_after(),
57        }
58    }
59}
60/// A wrapper around the MLS key package struct with some additional fields
61#[derive(Clone, Debug)]
62pub struct VerifiedKeyPackageV2 {
63    pub inner: KeyPackage,
64    pub credential: MlsCredential,
65    pub installation_public_key: Vec<u8>,
66}
67
68impl VerifiedKeyPackageV2 {
69    /// Create a new verified key package from its raw parts.
70    pub fn new(
71        kp: KeyPackage,
72        credential: MlsCredential,
73        installation_public_key: Vec<u8>,
74    ) -> Self {
75        Self {
76            inner: kp,
77            credential,
78            installation_public_key,
79        }
80    }
81
82    /// Create a verified key package from TLS-Serialized bytes.
83    // implements: JOIN-007, JOIN-008
84    pub fn from_bytes(
85        crypto_provider: &RustCrypto,
86        data: &[u8],
87    ) -> Result<Self, KeyPackageVerificationError> {
88        let kp_in: KeyPackageIn = KeyPackageIn::tls_deserialize_exact(data)?;
89        let kp = kp_in.validate(
90            crypto_provider,
91            MLS_PROTOCOL_VERSION,
92            openmls::prelude::LeafNodeLifetimePolicy::Verify,
93        )?;
94
95        kp.try_into()
96    }
97
98    pub fn installation_id(&self) -> Vec<u8> {
99        self.inner.leaf_node().signature_key().as_slice().to_vec()
100    }
101
102    pub fn hpke_init_key(&self) -> Vec<u8> {
103        self.inner.hpke_init_key().as_slice().to_vec()
104    }
105
106    pub fn wrapper_encryption(
107        &self,
108    ) -> Result<Option<WrapperEncryptionExtension>, KeyPackageVerificationError> {
109        self.inner
110            .extensions()
111            .unknown(WELCOME_WRAPPER_ENCRYPTION_EXTENSION_ID)
112            .map(|ext| ext.try_into().map_err(Into::into))
113            .transpose()
114    }
115
116    pub fn life_time(&self) -> Option<VerifiedLifetime> {
117        let lifetime_result = panic::catch_unwind(AssertUnwindSafe(|| {
118            self.inner.life_time() // This might panic
119        }));
120
121        match lifetime_result {
122            Ok(lifetime) => Some(lifetime.into()),
123            Err(_) => None,
124        }
125    }
126}
127
128impl TryFrom<KeyPackage> for VerifiedKeyPackageV2 {
129    type Error = KeyPackageVerificationError;
130
131    // implements: JOIN-004
132    fn try_from(kp: KeyPackage) -> Result<Self, Self::Error> {
133        let leaf_node = kp.leaf_node();
134        let basic_credential = BasicCredential::try_from(leaf_node.credential().clone())?;
135        let pub_key_bytes = leaf_node.signature_key().as_slice().to_vec();
136        let credential = MlsCredential::decode(basic_credential.identity())?;
137
138        Ok(Self::new(kp, credential, pub_key_bytes))
139    }
140}