Skip to main content

core_crypto_keystore/transaction/
mls.rs

1use openmls_traits::key_store::{MlsEntity, MlsEntityId};
2use rusqlite::Connection;
3
4use crate::{
5    CryptoKeystoreError, Sha256Hash, Transaction,
6    ancillary::ConversationIdRef,
7    deser,
8    entities::{
9        PersistedMlsGroup, StoredEncryptionKeyPair, StoredEpochEncryptionKeypair, StoredEpochEncryptionKeypairPkRef,
10        StoredHpkePrivateKey, StoredKeyPackage, StoredPskBundle,
11    },
12    ser,
13    traits::{Entity as _, EntityDatabaseMutation as _, EntityDeleteBorrowed as _, EntityGetBorrowed as _},
14};
15
16/// Implementation of the `MlsEntity::read` function; we want to share this elsewhere.
17pub(crate) fn read_mls_entity<V: MlsEntity>(conn: &Connection, id: &[u8]) -> Option<V> {
18    if id.is_empty() {
19        return None;
20    }
21
22    match V::ID {
23        MlsEntityId::GroupState => {
24            let v = PersistedMlsGroup::get_borrowed(conn, ConversationIdRef::new(id))
25                .ok()
26                .flatten()?;
27            deser(&v.state).ok()
28        }
29        MlsEntityId::SignatureKeyPair => {
30            unimplemented!("Don't use this API to load a signature key pair. Load a StoredCredential instead.")
31        }
32        MlsEntityId::KeyPackage => {
33            let v = StoredKeyPackage::get_borrowed(conn, id).ok().flatten()?;
34            deser(&v.key_package).ok()
35        }
36        MlsEntityId::HpkePrivateKey => {
37            // stored HPKE private keys are now actually keyed by the _hash_ of the public key, not the key itself
38            let pub_key_hash = Sha256Hash::hash_from(id);
39            let v = StoredHpkePrivateKey::get(conn, &pub_key_hash).ok().flatten()?;
40            deser(&v.secret_key).ok()
41        }
42        MlsEntityId::PskBundle => {
43            let v = StoredPskBundle::get_borrowed(conn, id).ok().flatten()?;
44            deser(&v.psk).ok()
45        }
46        MlsEntityId::EncryptionKeyPair => {
47            let v = StoredEncryptionKeyPair::get_borrowed(conn, id).ok().flatten()?;
48            deser(&v.sk).ok()
49        }
50        MlsEntityId::EpochEncryptionKeyPair => {
51            let kp_ref = StoredEpochEncryptionKeypairPkRef::parse_bytes(id).ok()?;
52            let v = StoredEpochEncryptionKeypair::get_borrowed(conn, kp_ref)
53                .ok()
54                .flatten()?;
55            deser(&v.keypairs).ok()
56        }
57    }
58}
59
60#[cfg_attr(target_os = "unknown", async_trait::async_trait(?Send))]
61#[cfg_attr(not(target_os = "unknown"), async_trait::async_trait)]
62impl openmls_traits::key_store::OpenMlsKeyStore for Transaction {
63    type Error = CryptoKeystoreError;
64
65    async fn store<V: MlsEntity + Sync>(&self, id: &[u8], value: &V) -> Result<(), Self::Error>
66    where
67        Self: Sized,
68    {
69        if id.is_empty() {
70            return Err(CryptoKeystoreError::MlsKeyStoreError(
71                "The provided key is empty".into(),
72            ));
73        }
74
75        let data = ser(value)?;
76
77        match V::ID {
78            MlsEntityId::GroupState => {
79                return Err(CryptoKeystoreError::IncorrectApiUsage(
80                    "Groups must not be saved using OpenMLS's APIs. You should use the keystore's provided methods",
81                ));
82            }
83            MlsEntityId::SignatureKeyPair => {
84                return Err(CryptoKeystoreError::IncorrectApiUsage(
85                    "Signature keys must not be saved using OpenMLS's APIs. Save a credential via the keystore API
86                    instead.",
87                ));
88            }
89            MlsEntityId::KeyPackage => {
90                StoredKeyPackage::from_openmls(id, data, value).save(self)?;
91            }
92            MlsEntityId::HpkePrivateKey => {
93                StoredHpkePrivateKey {
94                    public_key_hash: Sha256Hash::hash_from(id),
95                    secret_key: data,
96                }
97                .save(self)?;
98            }
99            MlsEntityId::PskBundle => {
100                StoredPskBundle {
101                    psk_id: id.into(),
102                    psk: data,
103                }
104                .save(self)?;
105            }
106            MlsEntityId::EncryptionKeyPair => {
107                StoredEncryptionKeyPair {
108                    pk: id.into(),
109                    sk: data,
110                }
111                .save(self)?;
112            }
113            MlsEntityId::EpochEncryptionKeyPair => {
114                let StoredEpochEncryptionKeypairPkRef {
115                    conversation_id,
116                    own_leaf_idx,
117                    epoch,
118                } = StoredEpochEncryptionKeypairPkRef::parse_bytes(id)?;
119                StoredEpochEncryptionKeypair {
120                    conversation_id: conversation_id.bytes().into(),
121                    own_leaf_idx,
122                    epoch,
123                    keypairs: data,
124                }
125                .save(self)?;
126            }
127        }
128
129        Ok(())
130    }
131
132    async fn read<V: MlsEntity>(&self, id: &[u8]) -> Option<V>
133    where
134        Self: Sized,
135    {
136        let conn = self.conn().ok()?;
137        read_mls_entity(&conn, id)
138    }
139
140    async fn delete<V: MlsEntity>(&self, id: &[u8]) -> Result<(), Self::Error> {
141        match V::ID {
142            MlsEntityId::SignatureKeyPair => unimplemented!(
143                "Deleting a signature key pair should not be done through this API, any keypair should be deleted via
144                deleting a credential."
145            ),
146            MlsEntityId::GroupState => PersistedMlsGroup::delete_borrowed(self, ConversationIdRef::new(id))?,
147            MlsEntityId::HpkePrivateKey => StoredHpkePrivateKey::delete(self, &Sha256Hash::hash_from(id))?,
148            MlsEntityId::KeyPackage => StoredKeyPackage::delete_borrowed(self, id)?,
149            MlsEntityId::PskBundle => StoredPskBundle::delete_borrowed(self, id)?,
150            MlsEntityId::EncryptionKeyPair => StoredEncryptionKeyPair::delete_borrowed(self, id)?,
151            MlsEntityId::EpochEncryptionKeyPair => {
152                let kp_ref = StoredEpochEncryptionKeypairPkRef::parse_bytes(id)?;
153                StoredEpochEncryptionKeypair::delete_borrowed(self, kp_ref)?
154            }
155        };
156
157        Ok(())
158    }
159}