nym_client_core/client/key_manager/
persistence.rs1use crate::client::key_manager::ClientKeys;
5use async_trait::async_trait;
6use rand::{CryptoRng, RngCore};
7use std::error::Error;
8use std::sync::Arc;
9use tokio::sync::Mutex;
10
11#[cfg(not(target_arch = "wasm32"))]
12use crate::config::disk_persistence::ClientKeysPaths;
13#[cfg(not(target_arch = "wasm32"))]
14use nym_crypto::asymmetric::{ed25519, x25519};
15#[cfg(not(target_arch = "wasm32"))]
16use nym_pemstore::traits::{PemStorableKey, PemStorableKeyPair};
17#[cfg(not(target_arch = "wasm32"))]
18use nym_pemstore::KeyPairPath;
19#[cfg(not(target_arch = "wasm32"))]
20use nym_sphinx::acknowledgements::AckKey;
21
22#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
24#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
25pub trait KeyStore {
26 type StorageError: Error;
27
28 async fn load_keys(&self) -> Result<ClientKeys, Self::StorageError>;
29
30 async fn store_keys(&self, keys: &ClientKeys) -> Result<(), Self::StorageError>;
31}
32
33#[cfg(not(target_arch = "wasm32"))]
34#[derive(Debug, thiserror::Error)]
35pub enum OnDiskKeysError {
36 #[error("failed to load {keys} keys from {:?} (private key) and {:?} (public key): {err}", .paths.private_key_path, .paths.public_key_path)]
37 KeyPairLoadFailure {
38 keys: String,
39 paths: nym_pemstore::KeyPairPath,
40 #[source]
41 err: std::io::Error,
42 },
43
44 #[error("failed to store {keys} keys to {:?} (private key) and {:?} (public key): {err}", .paths.private_key_path, .paths.public_key_path)]
45 KeyPairStoreFailure {
46 keys: String,
47 paths: nym_pemstore::KeyPairPath,
48 #[source]
49 err: std::io::Error,
50 },
51
52 #[error("failed to load {key} key from {path}: {err}")]
53 KeyLoadFailure {
54 key: String,
55 path: String,
56 #[source]
57 err: std::io::Error,
58 },
59
60 #[error("failed to store {key} key to {path}: {err}")]
61 KeyStoreFailure {
62 key: String,
63 path: String,
64 #[source]
65 err: std::io::Error,
66 },
67}
68
69#[derive(Clone)]
70#[cfg(not(target_arch = "wasm32"))]
71pub struct OnDiskKeys {
72 paths: ClientKeysPaths,
73}
74
75#[cfg(not(target_arch = "wasm32"))]
76impl From<ClientKeysPaths> for OnDiskKeys {
77 fn from(paths: ClientKeysPaths) -> Self {
78 OnDiskKeys { paths }
79 }
80}
81
82#[cfg(not(target_arch = "wasm32"))]
83impl OnDiskKeys {
84 pub fn new(paths: ClientKeysPaths) -> Self {
85 OnDiskKeys { paths }
86 }
87
88 #[doc(hidden)]
89 pub fn load_encryption_keypair(&self) -> Result<x25519::KeyPair, OnDiskKeysError> {
90 let encryption_paths = self.paths.encryption_key_pair_path();
91 self.load_keypair(encryption_paths, "encryption")
92 }
93
94 #[doc(hidden)]
95 pub fn load_identity_keypair(&self) -> Result<ed25519::KeyPair, OnDiskKeysError> {
96 let identity_paths = self.paths.identity_key_pair_path();
97 self.load_keypair(identity_paths, "identity")
98 }
99
100 fn load_key<T: PemStorableKey>(
101 &self,
102 path: &std::path::Path,
103 name: impl Into<String>,
104 ) -> Result<T, OnDiskKeysError> {
105 nym_pemstore::load_key(path).map_err(|err| OnDiskKeysError::KeyLoadFailure {
106 key: name.into(),
107 path: path.to_str().map(|s| s.to_owned()).unwrap_or_default(),
108 err,
109 })
110 }
111
112 fn load_keypair<T: PemStorableKeyPair>(
113 &self,
114 paths: KeyPairPath,
115 name: impl Into<String>,
116 ) -> Result<T, OnDiskKeysError> {
117 nym_pemstore::load_keypair(&paths).map_err(|err| OnDiskKeysError::KeyPairLoadFailure {
118 keys: name.into(),
119 paths,
120 err,
121 })
122 }
123
124 fn store_key<T: PemStorableKey>(
125 &self,
126 key: &T,
127 path: &std::path::Path,
128 name: impl Into<String>,
129 ) -> Result<(), OnDiskKeysError> {
130 nym_pemstore::store_key(key, path).map_err(|err| OnDiskKeysError::KeyStoreFailure {
131 key: name.into(),
132 path: path.to_str().map(|s| s.to_owned()).unwrap_or_default(),
133 err,
134 })
135 }
136
137 fn store_keypair<T: PemStorableKeyPair>(
138 &self,
139 keys: &T,
140 paths: KeyPairPath,
141 name: impl Into<String>,
142 ) -> Result<(), OnDiskKeysError> {
143 nym_pemstore::store_keypair(keys, &paths).map_err(|err| {
144 OnDiskKeysError::KeyPairStoreFailure {
145 keys: name.into(),
146 paths,
147 err,
148 }
149 })
150 }
151
152 fn load_keys(&self) -> Result<ClientKeys, OnDiskKeysError> {
153 let identity_keypair = self.load_identity_keypair()?;
154 let encryption_keypair = self.load_encryption_keypair()?;
155 let ack_key: AckKey = self.load_key(self.paths.ack_key(), "ack key")?;
156
157 Ok(ClientKeys::from_keys(
158 identity_keypair,
159 encryption_keypair,
160 ack_key,
161 ))
162 }
163
164 fn store_keys(&self, keys: &ClientKeys) -> Result<(), OnDiskKeysError> {
165 let identity_paths = self.paths.identity_key_pair_path();
166 let encryption_paths = self.paths.encryption_key_pair_path();
167
168 self.store_keypair(
169 keys.identity_keypair.as_ref(),
170 identity_paths,
171 "identity keys",
172 )?;
173 self.store_keypair(
174 keys.encryption_keypair.as_ref(),
175 encryption_paths,
176 "encryption keys",
177 )?;
178
179 self.store_key(keys.ack_key.as_ref(), self.paths.ack_key(), "ack key")?;
180
181 Ok(())
182 }
183}
184
185#[cfg(not(target_arch = "wasm32"))]
186#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
187impl KeyStore for OnDiskKeys {
188 type StorageError = OnDiskKeysError;
189
190 async fn load_keys(&self) -> Result<ClientKeys, Self::StorageError> {
191 self.load_keys()
192 }
193
194 async fn store_keys(&self, keys: &ClientKeys) -> Result<(), Self::StorageError> {
195 self.store_keys(keys)
196 }
197}
198
199#[derive(Clone)]
200pub struct InMemEphemeralKeys {
201 keys: Arc<Mutex<ClientKeys>>,
202}
203
204impl InMemEphemeralKeys {
205 pub fn new<R>(rng: &mut R) -> Self
206 where
207 R: RngCore + CryptoRng,
208 {
209 InMemEphemeralKeys {
210 keys: Arc::new(Mutex::new(ClientKeys::generate_new(rng))),
211 }
212 }
213}
214
215#[derive(Debug, thiserror::Error)]
216#[error("old ephemeral keys can't be loaded from storage")]
217pub struct EphemeralKeysError;
218
219#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
220#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
221impl KeyStore for InMemEphemeralKeys {
222 type StorageError = EphemeralKeysError;
223
224 async fn load_keys(&self) -> Result<ClientKeys, Self::StorageError> {
225 Ok(self.keys.lock().await.clone())
226 }
227
228 async fn store_keys(&self, keys: &ClientKeys) -> Result<(), Self::StorageError> {
229 *self.keys.lock().await = keys.clone();
230 Ok(())
231 }
232}