core_crypto/mls/client/
identifier.rs

1use super::{
2    CredentialBundle,
3    error::{Error, Result},
4};
5use crate::{
6    RecursiveError,
7    prelude::{CertificateBundle, Client, ClientId},
8};
9use mls_crypto_provider::MlsCryptoProvider;
10use openmls_traits::types::SignatureScheme;
11use std::collections::{HashMap, HashSet};
12
13/// Used by consumers to initializes a MLS client. Encompasses all the client types available.
14/// Could be enriched later with Verifiable Presentations.
15#[derive(Debug, Clone)]
16pub enum ClientIdentifier {
17    /// Basic keypair
18    Basic(ClientId),
19    /// X509 certificate
20    X509(HashMap<SignatureScheme, CertificateBundle>),
21}
22
23impl ClientIdentifier {
24    /// Extract the unique [ClientId] from an identifier. Use with parsimony as, in case of a x509
25    /// certificate this leads to parsing the certificate
26    pub fn get_id(&self) -> Result<std::borrow::Cow<ClientId>> {
27        match self {
28            ClientIdentifier::Basic(id) => Ok(std::borrow::Cow::Borrowed(id)),
29            ClientIdentifier::X509(certs) => {
30                // since ClientId has uniqueness constraints, it is the same for all certificates.
31                // hence no need to compute it for every certificate then verify its uniqueness
32                // that's not a getter's job
33                let cert = certs.values().next().ok_or(Error::NoX509CertificateBundle)?;
34                let id = cert
35                    .get_client_id()
36                    .map_err(RecursiveError::mls_credential("getting client id"))?;
37                Ok(std::borrow::Cow::Owned(id))
38            }
39        }
40    }
41
42    /// Generate a new CredentialBundle (Credential + KeyPair) for each ciphersuite.
43    /// This method does not persist them in the keystore !
44    pub fn generate_credential_bundles(
45        self,
46        backend: &MlsCryptoProvider,
47        signature_schemes: HashSet<SignatureScheme>,
48    ) -> Result<Vec<(SignatureScheme, ClientId, CredentialBundle)>> {
49        match self {
50            ClientIdentifier::Basic(id) => signature_schemes.iter().try_fold(
51                Vec::with_capacity(signature_schemes.len()),
52                |mut acc, &sc| -> Result<_> {
53                    let cb = Client::new_basic_credential_bundle(&id, sc, backend)
54                        .map_err(RecursiveError::mls_credential("creating new basic credential bundle"))?;
55                    acc.push((sc, id.clone(), cb));
56                    Ok(acc)
57                },
58            ),
59            ClientIdentifier::X509(certs) => {
60                let cap = certs.len();
61                certs
62                    .into_iter()
63                    .try_fold(Vec::with_capacity(cap), |mut acc, (sc, cert)| -> Result<_> {
64                        let id = cert
65                            .get_client_id()
66                            .map_err(RecursiveError::mls_credential("getting client id"))?;
67                        let cb = Client::new_x509_credential_bundle(cert)
68                            .map_err(RecursiveError::mls_credential("creating new x509 credential bundle"))?;
69                        acc.push((sc, id, cb));
70                        Ok(acc)
71                    })
72            }
73        }
74    }
75}