Skip to content

Commit 96dd3c4

Browse files
warusadurabilelmoussaoui
authored andcommitted
portal: Add rekeying support for oo7::portal::Keyring
This change adds `change_secret()` to `oo7::portal::Keyring` API. `change_secret()` change/update the secret associated with a keyring. Note: we need this change for the sever side implementation. Fixes: #47 Signed-off-by: Dhanuka Warusadura <[email protected]>
1 parent 0e4d787 commit 96dd3c4

File tree

1 file changed

+86
-20
lines changed

1 file changed

+86
-20
lines changed

client/src/portal/mod.rs

Lines changed: 86 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use std::io;
3333
use std::{
3434
collections::HashMap,
3535
path::{Path, PathBuf},
36-
sync::{Arc, OnceLock},
36+
sync::Arc,
3737
};
3838

3939
#[cfg(feature = "async-std")]
@@ -81,8 +81,8 @@ pub struct Keyring {
8181
/// Times are stored before reading the file to detect
8282
/// file changes before writing
8383
mtime: Mutex<Option<std::time::SystemTime>>,
84-
key: OnceLock<Key>,
85-
secret: Arc<Secret>,
84+
key: Mutex<Option<Arc<Key>>>,
85+
secret: Mutex<Arc<Secret>>,
8686
}
8787

8888
impl Keyring {
@@ -129,7 +129,7 @@ impl Keyring {
129129
path: path.as_ref().to_path_buf(),
130130
mtime: Mutex::new(mtime),
131131
key: Default::default(),
132-
secret: Arc::new(secret),
132+
secret: Mutex::new(Arc::new(secret)),
133133
})
134134
}
135135

@@ -147,7 +147,7 @@ impl Keyring {
147147
path: path.as_ref().to_path_buf(),
148148
mtime: Default::default(),
149149
key: Default::default(),
150-
secret: Arc::new(secret),
150+
secret: Mutex::new(Arc::new(secret)),
151151
}),
152152
Err(Error::VersionMismatch(Some(version)))
153153
if version[0] == api::LEGACY_MAJOR_VERSION =>
@@ -169,7 +169,7 @@ impl Keyring {
169169
path: path.as_ref().to_path_buf(),
170170
mtime: Default::default(),
171171
key: Default::default(),
172-
secret: Arc::new(secret),
172+
secret: Mutex::new(Arc::new(secret)),
173173
})
174174
}
175175
Err(err) => Err(err),
@@ -205,7 +205,7 @@ impl Keyring {
205205
path: v1_path,
206206
mtime: Default::default(),
207207
key: Default::default(),
208-
secret: Arc::new(secret),
208+
secret: Mutex::new(Arc::new(secret)),
209209
})
210210
}
211211
}
@@ -229,7 +229,7 @@ impl Keyring {
229229
.items
230230
.iter()
231231
.map(|e| {
232-
(*e).clone().decrypt(key).map_err(|err| {
232+
(*e).clone().decrypt(&key).map_err(|err| {
233233
InvalidItemError::new(
234234
err,
235235
e.hashed_attributes.keys().map(|x| x.to_string()).collect(),
@@ -243,22 +243,22 @@ impl Keyring {
243243
pub async fn search_items(&self, attributes: &impl AsAttributes) -> Result<Vec<Item>, Error> {
244244
let key = self.derive_key().await;
245245
let keyring = self.keyring.read().await;
246-
keyring.search_items(attributes, key)
246+
keyring.search_items(attributes, &key)
247247
}
248248

249249
/// Find the first item matching the attributes.
250250
pub async fn lookup_item(&self, attributes: &impl AsAttributes) -> Result<Option<Item>, Error> {
251251
let key = self.derive_key().await;
252252
let keyring = self.keyring.read().await;
253-
keyring.lookup_item(attributes, key)
253+
keyring.lookup_item(attributes, &key)
254254
}
255255

256256
/// Delete an item.
257257
pub async fn delete(&self, attributes: &impl AsAttributes) -> Result<(), Error> {
258258
{
259259
let key = self.derive_key().await;
260260
let mut keyring = self.keyring.write().await;
261-
keyring.remove_items(attributes, key)?;
261+
keyring.remove_items(attributes, &key)?;
262262
};
263263
self.write().await
264264
}
@@ -284,10 +284,10 @@ impl Keyring {
284284
let key = self.derive_key().await;
285285
let mut keyring = self.keyring.write().await;
286286
if replace {
287-
keyring.remove_items(attributes, key)?;
287+
keyring.remove_items(attributes, &key)?;
288288
}
289289
let item = Item::new(label, attributes, secret);
290-
let encrypted_item = item.encrypt(key)?;
290+
let encrypted_item = item.encrypt(&key)?;
291291
keyring.items.push(encrypted_item);
292292
item
293293
};
@@ -308,7 +308,7 @@ impl Keyring {
308308
let mut keyring = self.keyring.write().await;
309309

310310
if let Some(item_store) = keyring.items.get_mut(index) {
311-
*item_store = item.encrypt(key)?;
311+
*item_store = item.encrypt(&key)?;
312312
} else {
313313
return Err(Error::InvalidItemIndex(index));
314314
}
@@ -340,10 +340,10 @@ impl Keyring {
340340
let mut keyring = self.keyring.write().await;
341341
for (label, attributes, secret, replace) in items {
342342
if replace {
343-
keyring.remove_items(&attributes, key)?;
343+
keyring.remove_items(&attributes, &key)?;
344344
}
345345
let item = Item::new(label, &attributes, &*secret);
346-
let encrypted_item = item.encrypt(key)?;
346+
let encrypted_item = item.encrypt(&key)?;
347347
keyring.items.push(encrypted_item);
348348
}
349349

@@ -374,12 +374,52 @@ impl Keyring {
374374
}
375375

376376
/// Return key, derive and store it first if not initialized
377-
async fn derive_key(&self) -> &Key {
378-
if self.key.get().is_none() {
377+
async fn derive_key(&self) -> Arc<Key> {
378+
if self.key.lock().await.is_none() {
379379
let key = self.keyring.read().await.derive_key(&self.secret);
380-
self.key.set(key).unwrap();
380+
*self.key.lock().await = Some(Arc::new(key));
381381
}
382-
self.key.get().unwrap()
382+
383+
Arc::clone(self.key.lock().await.as_ref().unwrap())
384+
}
385+
386+
/// Change keyring secret
387+
///
388+
/// # Arguments
389+
///
390+
/// * `secret` - The new secret to store.
391+
pub async fn change_secret(&self, secret: Secret) -> Result<(), Error> {
392+
#[cfg(feature = "tracing")]
393+
tracing::debug!("Changing keyring secret and key");
394+
395+
let keyring = self.keyring.read().await;
396+
let key = self.derive_key().await;
397+
398+
let mut items = Vec::with_capacity(keyring.items.len());
399+
for item in &keyring.items {
400+
items.push(item.clone().decrypt(&key)?);
401+
}
402+
drop(keyring);
403+
404+
let mut secret_lock = self.secret.lock().await;
405+
*secret_lock = Arc::new(secret);
406+
drop(secret_lock);
407+
408+
let mut key_lock = self.key.lock().await;
409+
// Unset the old key
410+
*key_lock = None;
411+
drop(key_lock);
412+
let key = self.derive_key().await;
413+
414+
let mut keyring = self.keyring.write().await;
415+
416+
for item in items {
417+
let encrypted_item = item.encrypt(&key)?;
418+
keyring.items.push(encrypted_item);
419+
}
420+
drop(keyring);
421+
422+
self.write().await
383423
}
384424
}
385425

@@ -609,4 +649,30 @@ mod tests {
609649

610650
Ok(())
611651
}
652+
653+
#[tokio::test]
654+
async fn change_secret() -> Result<(), Error> {
655+
let path = PathBuf::from("../../tests/test_rekeying.keyring");
656+
657+
let keyring = Keyring::load(&path, strong_key()).await?;
658+
let attributes = HashMap::from([("attr", "value")]);
659+
let item_before = keyring
660+
.create_item("test", &attributes, "password", false)
661+
.await?;
662+
663+
let new_secret = Secret::from(b"password".to_vec());
664+
keyring.change_secret(new_secret).await?;
665+
666+
let new_secret = Secret::from(b"password".to_vec());
667+
let keyring = Keyring::load(&path, new_secret).await?;
668+
let item_now = keyring.lookup_item(&attributes).await?.unwrap();
669+
670+
assert_eq!(item_before.label(), item_now.label());
671+
assert_eq!(item_before.secret(), item_now.secret());
672+
assert_eq!(item_before.attributes(), item_now.attributes());
673+
674+
fs::remove_file(path).await?;
675+
676+
Ok(())
677+
}
612678
}

0 commit comments

Comments
 (0)