~ireas/nitrokey-rs

d95355e3d76c0c0022629e635f36a2dc325c0af2 — Robin Krahl 2 years ago 83641ca
Revert "Store mutable reference to Device in PasswordSafe"

This reverts commit 13006c00dcbd570cf8347d89557834e320427377.
3 files changed, 45 insertions(+), 21 deletions(-)

M TODO.md
M src/pws.rs
M tests/device.rs
M TODO.md => TODO.md +1 -0
@@ 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`.


M src/pws.rs => src/pws.rs +12 -12
@@ 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> {

M tests/device.rs => tests/device.rs +32 -9
@@ 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));