summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO.md1
-rw-r--r--src/pws.rs24
-rw-r--r--tests/device.rs41
3 files changed, 45 insertions, 21 deletions
diff --git a/TODO.md b/TODO.md
index d6a3509..1ff723d 100644
--- a/TODO.md
+++ b/TODO.md
@@ -13,6 +13,7 @@ SPDX-License-Identifier: MIT
- Clear passwords from memory.
- Lock password safe in `PasswordSafe::drop()` (see [nitrokey-storage-firmware
issue 65][]).
+- Disable creation of multiple password safes at the same time.
- Check timing in Storage tests.
- Consider restructuring `device::StorageStatus`.
diff --git a/src/pws.rs b/src/pws.rs
index a5b9d33..371de6e 100644
--- a/src/pws.rs
+++ b/src/pws.rs
@@ -18,7 +18,8 @@ pub const SLOT_COUNT: u8 = 16;
/// The password safe stores a tuple consisting of a name, a login and a password on a slot. The
/// number of available slots is [`SLOT_COUNT`][]. The slots are addressed starting with zero. To
/// retrieve a password safe from a Nitrokey device, use the [`get_password_safe`][] method from
-/// the [`GetPasswordSafe`][] trait.
+/// the [`GetPasswordSafe`][] trait. Note that the device must live at least as long as the
+/// password safe.
///
/// Once the password safe has been unlocked, it can be accessed without a password. Therefore it
/// is mandatory to call [`lock`][] on the corresponding device after the password store is used.
@@ -57,17 +58,21 @@ pub const SLOT_COUNT: u8 = 16;
/// [`GetPasswordSafe`]: trait.GetPasswordSafe.html
#[derive(Debug)]
pub struct PasswordSafe<'a> {
- device: &'a mut dyn Device,
+ _device: &'a dyn Device,
}
/// Provides access to a [`PasswordSafe`][].
///
+/// The device that implements this trait must always live at least as long as a password safe
+/// retrieved from it.
+///
/// [`PasswordSafe`]: struct.PasswordSafe.html
pub trait GetPasswordSafe {
/// Enables and returns the password safe.
///
- /// It is mandatory to lock the underlying device using [`lock`][] after the password safe has
- /// been used. Otherwise, other applications can access the password store without
+ /// The underlying device must always live at least as long as a password safe retrieved from
+ /// it. It is mandatory to lock the underlying device using [`lock`][] after the password safe
+ /// has been used. Otherwise, other applications can access the password store without
/// authentication.
///
/// If this method returns an `AesDecryptionFailed` (Nitrokey Pro) or `Unknown` (Nitrokey
@@ -116,17 +121,12 @@ pub trait GetPasswordSafe {
}
fn get_password_safe<'a>(
- device: &'a mut dyn Device,
+ device: &'a dyn Device,
user_pin: &str,
) -> Result<PasswordSafe<'a>, Error> {
let user_pin_string = get_cstring(user_pin)?;
- let result = get_command_result(unsafe {
- nitrokey_sys::NK_enable_password_safe(user_pin_string.as_ptr())
- });
- match result {
- Ok(()) => Ok(PasswordSafe { device }),
- Err(err) => Err(err),
- }
+ get_command_result(unsafe { nitrokey_sys::NK_enable_password_safe(user_pin_string.as_ptr()) })
+ .map(|_| PasswordSafe { _device: device })
}
fn get_pws_result(s: String) -> Result<String, Error> {
diff --git a/tests/device.rs b/tests/device.rs
index 6a3683b..5c52024 100644
--- a/tests/device.rs
+++ b/tests/device.rs
@@ -156,7 +156,10 @@ fn change_user_pin(device: DeviceWrapper) {
let device = device.authenticate_user(USER_NEW_PASSWORD).unwrap_err().0;
let mut device = device;
- assert_ok!((), device.change_user_pin(DEFAULT_USER_PIN, USER_NEW_PASSWORD));
+ assert_ok!(
+ (),
+ device.change_user_pin(DEFAULT_USER_PIN, USER_NEW_PASSWORD)
+ );
let device = device.authenticate_user(DEFAULT_USER_PIN).unwrap_err().0;
let device = device
@@ -179,7 +182,10 @@ fn change_user_pin(device: DeviceWrapper) {
#[test_device]
fn change_admin_pin(device: DeviceWrapper) {
- let device = device.authenticate_admin(DEFAULT_ADMIN_PIN).unwrap().device();
+ let device = device
+ .authenticate_admin(DEFAULT_ADMIN_PIN)
+ .unwrap()
+ .device();
let mut device = device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err().0;
assert_ok!(
@@ -203,7 +209,10 @@ fn change_admin_pin(device: DeviceWrapper) {
device.change_admin_pin(ADMIN_NEW_PASSWORD, DEFAULT_ADMIN_PIN)
);
- let device = device.authenticate_admin(DEFAULT_ADMIN_PIN).unwrap().device();
+ let device = device
+ .authenticate_admin(DEFAULT_ADMIN_PIN)
+ .unwrap()
+ .device();
device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err();
}
@@ -225,7 +234,10 @@ where
#[test_device]
fn unlock_user_pin(device: DeviceWrapper) {
let mut device = device.authenticate_user(DEFAULT_USER_PIN).unwrap().device();
- assert_ok!((), device.unlock_user_pin(DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN));
+ assert_ok!(
+ (),
+ device.unlock_user_pin(DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN)
+ );
assert_cmd_err!(
CommandError::WrongPassword,
device.unlock_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN)
@@ -236,21 +248,26 @@ fn unlock_user_pin(device: DeviceWrapper) {
let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword);
let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword);
let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword);
- let mut device = require_failed_user_login(device, DEFAULT_USER_PIN, CommandError::WrongPassword);
+ let mut device =
+ require_failed_user_login(device, DEFAULT_USER_PIN, CommandError::WrongPassword);
// unblock with current PIN
assert_cmd_err!(
CommandError::WrongPassword,
device.unlock_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN)
);
- assert_ok!((), device.unlock_user_pin(DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN));
+ assert_ok!(
+ (),
+ device.unlock_user_pin(DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN)
+ );
let device = device.authenticate_user(DEFAULT_USER_PIN).unwrap().device();
// block user PIN
let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword);
let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword);
let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword);
- let mut device = require_failed_user_login(device, DEFAULT_USER_PIN, CommandError::WrongPassword);
+ let mut device =
+ require_failed_user_login(device, DEFAULT_USER_PIN, CommandError::WrongPassword);
// unblock with new PIN
assert_cmd_err!(
@@ -307,7 +324,10 @@ fn factory_reset(device: DeviceWrapper) {
);
assert_ok!((), device.factory_reset(ADMIN_NEW_PASSWORD));
- let device = device.authenticate_admin(DEFAULT_ADMIN_PIN).unwrap().device();
+ let device = device
+ .authenticate_admin(DEFAULT_ADMIN_PIN)
+ .unwrap()
+ .device();
let user = unwrap_ok!(device.authenticate_user(DEFAULT_USER_PIN));
assert_cmd_err!(CommandError::SlotNotProgrammed, user.get_totp_slot_name(1));
@@ -335,7 +355,10 @@ fn build_aes_key(device: DeviceWrapper) {
);
assert_ok!((), device.build_aes_key(DEFAULT_ADMIN_PIN));
- let mut device = device.authenticate_admin(DEFAULT_ADMIN_PIN).unwrap().device();
+ let mut device = device
+ .authenticate_admin(DEFAULT_ADMIN_PIN)
+ .unwrap()
+ .device();
let pws = unwrap_ok!(device.get_password_safe(DEFAULT_USER_PIN));
assert_utf8_err_or_ne("test", pws.get_slot_name(0));