mls_rs/
identity.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// Copyright by contributors to this project.
3// SPDX-License-Identifier: (Apache-2.0 OR MIT)
4
5/// Basic credential identity provider.
6pub mod basic;
7
8/// X.509 certificate identity provider.
9#[cfg(feature = "x509")]
10pub mod x509 {
11    pub use mls_rs_identity_x509::*;
12}
13
14pub use mls_rs_core::identity::{
15    Credential, CredentialType, CustomCredential, MlsCredential, SigningIdentity,
16};
17
18#[cfg(test)]
19pub(crate) mod test_utils {
20    #[cfg(feature = "std")]
21    use alloc::boxed::Box;
22    use alloc::vec;
23    use alloc::vec::Vec;
24    use mls_rs_core::{
25        crypto::{CipherSuite, CipherSuiteProvider, SignatureSecretKey},
26        error::IntoAnyError,
27        extension::ExtensionList,
28        identity::{
29            Credential, CredentialType, IdentityProvider, MemberValidationContext, SigningIdentity,
30        },
31        time::MlsTime,
32    };
33
34    use crate::crypto::test_utils::test_cipher_suite_provider;
35
36    use super::basic::{BasicCredential, BasicIdentityProvider};
37
38    #[derive(Debug)]
39    #[cfg_attr(feature = "std", derive(thiserror::Error))]
40    #[cfg_attr(
41        feature = "std",
42        error("expected basic or custom credential type 42 found: {0:?}")
43    )]
44    pub struct BasicWithCustomProviderError(CredentialType);
45
46    impl IntoAnyError for BasicWithCustomProviderError {
47        #[cfg(feature = "std")]
48        fn into_dyn_error(self) -> Result<Box<dyn std::error::Error + Send + Sync>, Self> {
49            Ok(self.into())
50        }
51    }
52
53    #[derive(Debug, Clone)]
54    pub struct BasicWithCustomProvider {
55        pub(crate) basic: BasicIdentityProvider,
56        pub(crate) allow_any_custom: bool,
57        supported_cred_types: Vec<CredentialType>,
58    }
59
60    impl BasicWithCustomProvider {
61        pub const CUSTOM_CREDENTIAL_TYPE: u16 = 42;
62
63        pub fn new(basic: BasicIdentityProvider) -> BasicWithCustomProvider {
64            BasicWithCustomProvider {
65                basic,
66                allow_any_custom: false,
67                supported_cred_types: vec![
68                    CredentialType::BASIC,
69                    Self::CUSTOM_CREDENTIAL_TYPE.into(),
70                ],
71            }
72        }
73
74        pub fn with_credential_type(mut self, cred_type: CredentialType) -> Self {
75            self.supported_cred_types.push(cred_type);
76            self
77        }
78
79        #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
80        async fn resolve_custom_identity(
81            &self,
82            signing_id: &SigningIdentity,
83        ) -> Result<Vec<u8>, BasicWithCustomProviderError> {
84            self.basic
85                .identity(signing_id, &Default::default())
86                .await
87                .or_else(|_| {
88                    signing_id
89                        .credential
90                        .as_custom()
91                        .map(|c| {
92                            if c.credential_type
93                                == CredentialType::from(Self::CUSTOM_CREDENTIAL_TYPE)
94                                || self.allow_any_custom
95                            {
96                                Ok(c.data.to_vec())
97                            } else {
98                                Err(BasicWithCustomProviderError(c.credential_type))
99                            }
100                        })
101                        .transpose()?
102                        .ok_or_else(|| {
103                            BasicWithCustomProviderError(signing_id.credential.credential_type())
104                        })
105                })
106        }
107    }
108
109    impl Default for BasicWithCustomProvider {
110        fn default() -> Self {
111            Self::new(BasicIdentityProvider::new())
112        }
113    }
114
115    #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
116    #[cfg_attr(mls_build_async, maybe_async::must_be_async)]
117    impl IdentityProvider for BasicWithCustomProvider {
118        type Error = BasicWithCustomProviderError;
119
120        async fn validate_member(
121            &self,
122            _signing_identity: &SigningIdentity,
123            _timestamp: Option<MlsTime>,
124            _context: MemberValidationContext<'_>,
125        ) -> Result<(), Self::Error> {
126            //TODO: Is it actually beneficial to check the key, or does that already happen elsewhere before
127            //this point?
128            Ok(())
129        }
130
131        async fn validate_external_sender(
132            &self,
133            _signing_identity: &SigningIdentity,
134            _timestamp: Option<MlsTime>,
135            _extensions: Option<&ExtensionList>,
136        ) -> Result<(), Self::Error> {
137            //TODO: Is it actually beneficial to check the key, or does that already happen elsewhere before
138            //this point?
139            Ok(())
140        }
141
142        async fn identity(
143            &self,
144            signing_id: &SigningIdentity,
145            _extensions: &ExtensionList,
146        ) -> Result<Vec<u8>, Self::Error> {
147            self.resolve_custom_identity(signing_id).await
148        }
149
150        async fn valid_successor(
151            &self,
152            predecessor: &SigningIdentity,
153            successor: &SigningIdentity,
154            _extensions: &ExtensionList,
155        ) -> Result<bool, Self::Error> {
156            let predecessor = self.resolve_custom_identity(predecessor).await?;
157            let successor = self.resolve_custom_identity(successor).await?;
158
159            Ok(predecessor == successor)
160        }
161
162        fn supported_types(&self) -> Vec<CredentialType> {
163            self.supported_cred_types.clone()
164        }
165    }
166
167    #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
168    pub async fn get_test_signing_identity(
169        cipher_suite: CipherSuite,
170        identity: &[u8],
171    ) -> (SigningIdentity, SignatureSecretKey) {
172        let provider = test_cipher_suite_provider(cipher_suite);
173        let (secret_key, public_key) = provider.signature_key_generate().await.unwrap();
174
175        let basic = get_test_basic_credential(identity.to_vec());
176
177        (SigningIdentity::new(basic, public_key), secret_key)
178    }
179
180    pub fn get_test_basic_credential(identity: Vec<u8>) -> Credential {
181        BasicCredential::new(identity).into_credential()
182    }
183}