Skip to main content

core_crypto_keystore/transaction/
mls.rs

1use openmls::prelude::Ciphersuite;
2use openmls_basic_credential::SignatureKeyPair;
3use openmls_traits::key_store::{MlsEntity, MlsEntityId, OpenMlsKeyStore};
4
5use crate::{
6    CryptoKeystoreError, Sha256Hash, Transaction, deser,
7    entities::{
8        PersistedMlsGroup, StoredCredential, StoredEncryptionKeyPair, StoredEpochEncryptionKeypair,
9        StoredHpkePrivateKey, StoredKeypackage, StoredPskBundle,
10    },
11    ser,
12    traits::FetchFromDatabase,
13};
14
15#[cfg_attr(target_os = "unknown", async_trait::async_trait(?Send))]
16#[cfg_attr(not(target_os = "unknown"), async_trait::async_trait)]
17impl OpenMlsKeyStore for Transaction {
18    type Error = CryptoKeystoreError;
19
20    async fn store<V: MlsEntity + Sync>(&self, id: &[u8], value: &V) -> Result<(), Self::Error>
21    where
22        Self: Sized,
23    {
24        if id.is_empty() {
25            return Err(CryptoKeystoreError::MlsKeyStoreError(
26                "The provided key is empty".into(),
27            ));
28        }
29
30        let data = ser(value)?;
31
32        match V::ID {
33            MlsEntityId::GroupState => {
34                return Err(CryptoKeystoreError::IncorrectApiUsage(
35                    "Groups must not be saved using OpenMLS's APIs. You should use the keystore's provided methods",
36                ));
37            }
38            MlsEntityId::SignatureKeyPair => {
39                return Err(CryptoKeystoreError::IncorrectApiUsage(
40                    "Signature keys must not be saved using OpenMLS's APIs. Save a credential via the keystore API
41                    instead.",
42                ));
43            }
44            MlsEntityId::KeyPackage => {
45                let kp = StoredKeypackage {
46                    keypackage_ref: id.into(),
47                    keypackage: data,
48                };
49                self.save(kp).await?;
50            }
51            MlsEntityId::HpkePrivateKey => {
52                let kp = StoredHpkePrivateKey {
53                    pk: id.into(),
54                    sk: data,
55                };
56                self.save(kp).await?;
57            }
58            MlsEntityId::PskBundle => {
59                let kp = StoredPskBundle {
60                    psk_id: id.into(),
61                    psk: data,
62                };
63                self.save(kp).await?;
64            }
65            MlsEntityId::EncryptionKeyPair => {
66                let kp = StoredEncryptionKeyPair {
67                    pk: id.into(),
68                    sk: data,
69                };
70                self.save(kp).await?;
71            }
72            MlsEntityId::EpochEncryptionKeyPair => {
73                let kp = StoredEpochEncryptionKeypair {
74                    id: id.into(),
75                    keypairs: data,
76                };
77                self.save(kp).await?;
78            }
79        }
80
81        Ok(())
82    }
83
84    async fn read<V: MlsEntity>(&self, id: &[u8]) -> Option<V>
85    where
86        Self: Sized,
87    {
88        if id.is_empty() {
89            return None;
90        }
91
92        match V::ID {
93            MlsEntityId::GroupState => {
94                let v = FetchFromDatabase::get_borrowed::<PersistedMlsGroup>(self, id)
95                    .await
96                    .ok()
97                    .flatten()?;
98                deser(&v.state).ok()
99            }
100            MlsEntityId::SignatureKeyPair => {
101                let hash = Sha256Hash::from_existing_hash(id).ok()?;
102                let stored_credential = FetchFromDatabase::get::<StoredCredential>(self, &hash)
103                    .await
104                    .ok()
105                    .flatten()?;
106                let ciphersuite = Ciphersuite::try_from(stored_credential.ciphersuite).ok()?;
107                let signature_scheme = ciphersuite.signature_algorithm();
108
109                let mls_keypair = SignatureKeyPair::from_raw(
110                    signature_scheme,
111                    stored_credential.private_key.to_vec(),
112                    stored_credential.public_key.to_vec(),
113                );
114
115                // In a well designed interface, something like this should not be necessary. However, we don't have
116                // a well-designed interface.
117                let data = ser(&mls_keypair).ok()?;
118                deser(&data).ok()
119            }
120            MlsEntityId::KeyPackage => {
121                let v = FetchFromDatabase::get_borrowed::<StoredKeypackage>(self, id)
122                    .await
123                    .ok()
124                    .flatten()?;
125                deser(&v.keypackage).ok()
126            }
127            MlsEntityId::HpkePrivateKey => {
128                let v = FetchFromDatabase::get_borrowed::<StoredHpkePrivateKey>(self, id)
129                    .await
130                    .ok()
131                    .flatten()?;
132                deser(&v.sk).ok()
133            }
134            MlsEntityId::PskBundle => {
135                let v = FetchFromDatabase::get_borrowed::<StoredPskBundle>(self, id)
136                    .await
137                    .ok()
138                    .flatten()?;
139                deser(&v.psk).ok()
140            }
141            MlsEntityId::EncryptionKeyPair => {
142                let v = FetchFromDatabase::get_borrowed::<StoredEncryptionKeyPair>(self, id)
143                    .await
144                    .ok()
145                    .flatten()?;
146                deser(&v.sk).ok()
147            }
148            MlsEntityId::EpochEncryptionKeyPair => {
149                let v = FetchFromDatabase::get_borrowed::<StoredEpochEncryptionKeypair>(self, id)
150                    .await
151                    .ok()
152                    .flatten()?;
153                deser(&v.keypairs).ok()
154            }
155        }
156    }
157
158    async fn delete<V: MlsEntity>(&self, id: &[u8]) -> Result<(), Self::Error> {
159        match V::ID {
160            MlsEntityId::GroupState => self.remove_borrowed::<PersistedMlsGroup>(id).await?,
161            MlsEntityId::SignatureKeyPair => unimplemented!(
162                "Deleting a signature key pair should not be done through this API, any keypair should be deleted via
163                deleting a credential."
164            ),
165            MlsEntityId::HpkePrivateKey => self.remove_borrowed::<StoredHpkePrivateKey>(id).await?,
166            MlsEntityId::KeyPackage => self.remove_borrowed::<StoredKeypackage>(id).await?,
167            MlsEntityId::PskBundle => self.remove_borrowed::<StoredPskBundle>(id).await?,
168            MlsEntityId::EncryptionKeyPair => self.remove_borrowed::<StoredEncryptionKeyPair>(id).await?,
169            MlsEntityId::EpochEncryptionKeyPair => self.remove_borrowed::<StoredEpochEncryptionKeypair>(id).await?,
170        }
171
172        Ok(())
173    }
174}