~ireas/nitrokey-rs

13006c00dcbd570cf8347d89557834e320427377 — Robin Krahl 2 years ago 0972bbe
Store mutable reference to Device in PasswordSafe

The current implementation of PasswordSafe stored a normal reference to
the Device.  This patch changes the PasswordSafe struct to use a mutable
reference instead.  This allows the borrow checker to make sure that
there is only one PasswordSafe instance at a time.  While this is
currently not needed, it will become important once we can lock the PWS
on the Nitrokey when dropping the PasswordSafe instance.
3 files changed, 14 insertions(+), 13 deletions(-)

M CHANGELOG.md
M TODO.md
M src/pws.rs
M CHANGELOG.md => CHANGELOG.md +2 -0
@@ 40,6 40,8 @@ SPDX-License-Identifier: MIT
  - Require a mutable `Device` reference if a method changes the device state.
- Let `Admin` and `User` store a mutable reference to the `Device` instead of
  the `Device` value.
- Let `PasswordStore` store a mutable reference to the `Device` instead of a
  non-mutable reference.

# v0.3.4 (2019-01-20)
- Fix authentication methods that assumed that `char` is signed.

M TODO.md => TODO.md +0 -1
@@ 13,7 13,6 @@ 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,8 18,7 @@ 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.  Note that the device must live at least as long as the
/// password safe.
/// the [`GetPasswordSafe`][] trait.
///
/// 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.


@@ 58,21 57,17 @@ pub const SLOT_COUNT: u8 = 16;
/// [`GetPasswordSafe`]: trait.GetPasswordSafe.html
#[derive(Debug)]
pub struct PasswordSafe<'a> {
    _device: &'a dyn Device,
    device: &'a mut 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.
    ///
    /// 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
    /// 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


@@ 121,12 116,17 @@ pub trait GetPasswordSafe {
}

fn get_password_safe<'a>(
    device: &'a dyn Device,
    device: &'a mut dyn Device,
    user_pin: &str,
) -> Result<PasswordSafe<'a>, Error> {
    let user_pin_string = get_cstring(user_pin)?;
    get_command_result(unsafe { nitrokey_sys::NK_enable_password_safe(user_pin_string.as_ptr()) })
        .map(|_| PasswordSafe { _device: device })
    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),
    }
}

fn get_pws_result(s: String) -> Result<String, Error> {