diff options
Diffstat (limited to 'nitrokey')
| -rw-r--r-- | nitrokey/.builds/archlinux-use-system-lib.yml (renamed from nitrokey/.builds/archlinux-use-system-lib.yaml) | 0 | ||||
| -rw-r--r-- | nitrokey/CHANGELOG.md | 7 | ||||
| -rw-r--r-- | nitrokey/Cargo.toml | 7 | ||||
| -rw-r--r-- | nitrokey/README.md | 3 | ||||
| -rw-r--r-- | nitrokey/src/auth.rs | 38 | ||||
| -rw-r--r-- | nitrokey/src/device.rs | 242 | ||||
| -rw-r--r-- | nitrokey/src/lib.rs | 10 | ||||
| -rw-r--r-- | nitrokey/src/otp.rs | 54 | ||||
| -rw-r--r-- | nitrokey/src/pws.rs | 39 | ||||
| -rw-r--r-- | nitrokey/src/util.rs | 4 | ||||
| -rw-r--r-- | nitrokey/tests/device.rs | 266 | ||||
| -rw-r--r-- | nitrokey/tests/lib.rs | 4 | ||||
| -rw-r--r-- | nitrokey/tests/otp.rs | 116 | ||||
| -rw-r--r-- | nitrokey/tests/pws.rs | 54 | ||||
| -rw-r--r-- | nitrokey/tests/util/mod.rs | 31 | 
15 files changed, 525 insertions, 350 deletions
diff --git a/nitrokey/.builds/archlinux-use-system-lib.yaml b/nitrokey/.builds/archlinux-use-system-lib.yml index ac0fc0f..ac0fc0f 100644 --- a/nitrokey/.builds/archlinux-use-system-lib.yaml +++ b/nitrokey/.builds/archlinux-use-system-lib.yml diff --git a/nitrokey/CHANGELOG.md b/nitrokey/CHANGELOG.md index 24c79af..e98e857 100644 --- a/nitrokey/CHANGELOG.md +++ b/nitrokey/CHANGELOG.md @@ -31,6 +31,13 @@ SPDX-License-Identifier: MIT    - Return `Error::Utf8Error` if libnitrokey returns an invalid UTF-8 string.  - Implement `From<(T: Device, Error)>` for `Error`.  - Fix timing issues with the `totp_no_pin` and `totp_pin` test cases. +- Always return a `Result` in functions that communicate with a device. +- Combine `get_{major,minor}_firmware_version` into `get_firmware_version`. +- Add `set_encrypted_volume_mode` to `Storage`. +- Use mutability to represent changes to the device status: +  - Implement `DerefMut` for `User<T>` and `Admin<T>`. +  - Add `device_mut` method to `DeviceWrapper`. +  - Require a mutable `Device` reference if a method changes the device state.  # v0.3.4 (2019-01-20)  - Fix authentication methods that assumed that `char` is signed. diff --git a/nitrokey/Cargo.toml b/nitrokey/Cargo.toml index 084bcea..fd6fef7 100644 --- a/nitrokey/Cargo.toml +++ b/nitrokey/Cargo.toml @@ -3,7 +3,7 @@  [package]  name = "nitrokey" -version = "0.4.0-alpha.0" +version = "0.4.0-alpha.2"  authors = ["Robin Krahl <robin.krahl@ireas.org>"]  edition = "2018"  homepage = "https://code.ireas.org/nitrokey-rs/" @@ -14,12 +14,13 @@ keywords = ["nitrokey", "otp"]  categories = ["api-bindings"]  readme = "README.md"  license = "MIT" +exclude = [".builds/*"]  [dependencies]  libc = "0.2" -nitrokey-sys = "3.4" +nitrokey-sys = "~3.4"  rand_core = {version = "0.3", default-features = false, features = ["std"] }  rand_os = {version = "0.1"}  [dev-dependencies] -nitrokey-test = {version = "0.2"} +nitrokey-test = {version = "=0.2.0"} diff --git a/nitrokey/README.md b/nitrokey/README.md index 069fed1..8c596eb 100644 --- a/nitrokey/README.md +++ b/nitrokey/README.md @@ -38,8 +38,7 @@ supported by `nitrokey-rs`:  - `NK_is_AES_supported`.  This method is no longer needed for Nitrokey devices    with a recent firmware version.  - `NK_set_unencrypted_volume_rorw_pin_type_user`, -  `NK_set_unencrypted_read_only`, `NK_set_unencrypted_read_write`, -  `NK_set_encrypted_read_only` and `NK_set_encrypted_read_write`.  These +  `NK_set_unencrypted_read_only`, `NK_set_unencrypted_read_write`.  These    methods are only relevant for older firmware versions (pre-v0.51).  As the    Nitrokey Storage firmware can be updated easily, we do not support these    outdated versions. diff --git a/nitrokey/src/auth.rs b/nitrokey/src/auth.rs index 18b6572..f9f50fa 100644 --- a/nitrokey/src/auth.rs +++ b/nitrokey/src/auth.rs @@ -1,7 +1,7 @@  // Copyright (C) 2018-2019 Robin Krahl <robin.krahl@ireas.org>  // SPDX-License-Identifier: MIT -use std::ops::Deref; +use std::ops;  use std::os::raw::c_char;  use std::os::raw::c_int; @@ -49,7 +49,7 @@ pub trait Authenticate {      ///         user.device()      ///     },      ///     Err((device, err)) => { -    ///         println!("Could not authenticate as user: {}", err); +    ///         eprintln!("Could not authenticate as user: {}", err);      ///         device      ///     },      /// }; @@ -95,7 +95,7 @@ pub trait Authenticate {      ///         admin.device()      ///     },      ///     Err((device, err)) => { -    ///         println!("Could not authenticate as admin: {}", err); +    ///         eprintln!("Could not authenticate as admin: {}", err);      ///         device      ///     },      /// }; @@ -211,7 +211,7 @@ impl<T: Device> User<T> {      }  } -impl<T: Device> Deref for User<T> { +impl<T: Device> ops::Deref for User<T> {      type Target = T;      fn deref(&self) -> &Self::Target { @@ -219,8 +219,14 @@ impl<T: Device> Deref for User<T> {      }  } +impl<T: Device> ops::DerefMut for User<T> { +    fn deref_mut(&mut self) -> &mut T { +        &mut self.device +    } +} +  impl<T: Device> GenerateOtp for User<T> { -    fn get_hotp_code(&self, slot: u8) -> Result<String, Error> { +    fn get_hotp_code(&mut self, slot: u8) -> Result<String, Error> {          result_from_string(unsafe {              nitrokey_sys::NK_get_hotp_code_PIN(slot, self.temp_password_ptr())          }) @@ -246,7 +252,7 @@ impl<T: Device> AuthenticatedDevice<T> for User<T> {      }  } -impl<T: Device> Deref for Admin<T> { +impl<T: Device> ops::Deref for Admin<T> {      type Target = T;      fn deref(&self) -> &Self::Target { @@ -254,6 +260,12 @@ impl<T: Device> Deref for Admin<T> {      }  } +impl<T: Device> ops::DerefMut for Admin<T> { +    fn deref_mut(&mut self) -> &mut T { +        &mut self.device +    } +} +  impl<T: Device> Admin<T> {      /// Forgets the user authentication and returns an unauthenticated device.  This method      /// consumes the authenticated device.  It does not perform any actual commands on the @@ -278,18 +290,18 @@ impl<T: Device> Admin<T> {      /// let device = nitrokey::connect()?;      /// let config = Config::new(None, None, None, false);      /// match device.authenticate_admin("12345678") { -    ///     Ok(admin) => { +    ///     Ok(mut admin) => {      ///         admin.write_config(config);      ///         ()      ///     }, -    ///     Err((_, err)) => println!("Could not authenticate as admin: {}", err), +    ///     Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err),      /// };      /// #     Ok(())      /// # }      /// ```      ///      /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot -    pub fn write_config(&self, config: Config) -> Result<(), Error> { +    pub fn write_config(&mut self, config: Config) -> Result<(), Error> {          let raw_config = RawConfig::try_from(config)?;          get_command_result(unsafe {              nitrokey_sys::NK_write_config( @@ -305,7 +317,7 @@ impl<T: Device> Admin<T> {  }  impl<T: Device> ConfigureOtp for Admin<T> { -    fn write_hotp_slot(&self, data: OtpSlotData, counter: u64) -> Result<(), Error> { +    fn write_hotp_slot(&mut self, data: OtpSlotData, counter: u64) -> Result<(), Error> {          let raw_data = RawOtpSlotData::new(data)?;          get_command_result(unsafe {              nitrokey_sys::NK_write_hotp_slot( @@ -322,7 +334,7 @@ impl<T: Device> ConfigureOtp for Admin<T> {          })      } -    fn write_totp_slot(&self, data: OtpSlotData, time_window: u16) -> Result<(), Error> { +    fn write_totp_slot(&mut self, data: OtpSlotData, time_window: u16) -> Result<(), Error> {          let raw_data = RawOtpSlotData::new(data)?;          get_command_result(unsafe {              nitrokey_sys::NK_write_totp_slot( @@ -339,13 +351,13 @@ impl<T: Device> ConfigureOtp for Admin<T> {          })      } -    fn erase_hotp_slot(&self, slot: u8) -> Result<(), Error> { +    fn erase_hotp_slot(&mut self, slot: u8) -> Result<(), Error> {          get_command_result(unsafe {              nitrokey_sys::NK_erase_hotp_slot(slot, self.temp_password_ptr())          })      } -    fn erase_totp_slot(&self, slot: u8) -> Result<(), Error> { +    fn erase_totp_slot(&mut self, slot: u8) -> Result<(), Error> {          get_command_result(unsafe {              nitrokey_sys::NK_erase_totp_slot(slot, self.temp_password_ptr())          }) diff --git a/nitrokey/src/device.rs b/nitrokey/src/device.rs index 386ce94..f6492cd 100644 --- a/nitrokey/src/device.rs +++ b/nitrokey/src/device.rs @@ -12,7 +12,9 @@ use crate::config::{Config, RawConfig};  use crate::error::{CommunicationError, Error};  use crate::otp::GenerateOtp;  use crate::pws::GetPasswordSafe; -use crate::util::{get_command_result, get_cstring, get_last_error, result_from_string}; +use crate::util::{ +    get_command_result, get_cstring, get_last_error, result_from_string, result_or_error, +};  /// Available Nitrokey models.  #[derive(Clone, Copy, Debug, PartialEq)] @@ -76,7 +78,7 @@ impl fmt::Display for VolumeMode {  ///         user.device()  ///     },  ///     Err((device, err)) => { -///         println!("Could not authenticate as user: {}", err); +///         eprintln!("Could not authenticate as user: {}", err);  ///         device  ///     },  /// }; @@ -140,7 +142,7 @@ pub enum DeviceWrapper {  ///         user.device()  ///     },  ///     Err((device, err)) => { -///         println!("Could not authenticate as user: {}", err); +///         eprintln!("Could not authenticate as user: {}", err);  ///         device  ///     },  /// }; @@ -186,7 +188,7 @@ pub struct Pro {  ///         user.device()  ///     },  ///     Err((device, err)) => { -///         println!("Could not authenticate as user: {}", err); +///         eprintln!("Could not authenticate as user: {}", err);  ///         device  ///     },  /// }; @@ -323,7 +325,7 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {      /// let device = nitrokey::connect()?;      /// match device.get_serial_number() {      ///     Ok(number) => println!("serial no: {}", number), -    ///     Err(err) => println!("Could not get serial number: {}", err), +    ///     Err(err) => eprintln!("Could not get serial number: {}", err),      /// };      /// #     Ok(())      /// # } @@ -343,13 +345,15 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {      ///      /// # fn try_main() -> Result<(), Error> {      /// let device = nitrokey::connect()?; -    /// let count = device.get_user_retry_count(); -    /// println!("{} remaining authentication attempts (user)", count); +    /// match device.get_user_retry_count() { +    ///     Ok(count) => println!("{} remaining authentication attempts (user)", count), +    ///     Err(err) => eprintln!("Could not get user retry count: {}", err), +    /// }      /// #     Ok(())      /// # }      /// ``` -    fn get_user_retry_count(&self) -> u8 { -        unsafe { nitrokey_sys::NK_get_user_retry_count() } +    fn get_user_retry_count(&self) -> Result<u8, Error> { +        result_or_error(unsafe { nitrokey_sys::NK_get_user_retry_count() })      }      /// Returns the number of remaining authentication attempts for the admin.  The total number of @@ -364,15 +368,18 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {      /// # fn try_main() -> Result<(), Error> {      /// let device = nitrokey::connect()?;      /// let count = device.get_admin_retry_count(); -    /// println!("{} remaining authentication attempts (admin)", count); +    /// match device.get_admin_retry_count() { +    ///     Ok(count) => println!("{} remaining authentication attempts (admin)", count), +    ///     Err(err) => eprintln!("Could not get admin retry count: {}", err), +    /// }      /// #     Ok(())      /// # }      /// ``` -    fn get_admin_retry_count(&self) -> u8 { -        unsafe { nitrokey_sys::NK_get_admin_retry_count() } +    fn get_admin_retry_count(&self) -> Result<u8, Error> { +        result_or_error(unsafe { nitrokey_sys::NK_get_admin_retry_count() })      } -    /// Returns the major part of the firmware version (should be zero). +    /// Returns the firmware version.      ///      /// # Example      /// @@ -382,37 +389,24 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {      ///      /// # fn try_main() -> Result<(), Error> {      /// let device = nitrokey::connect()?; -    /// println!( -    ///     "Firmware version: {}.{}", -    ///     device.get_major_firmware_version(), -    ///     device.get_minor_firmware_version(), -    /// ); +    /// match device.get_firmware_version() { +    ///     Ok(version) => println!("Firmware version: {}", version), +    ///     Err(err) => eprintln!("Could not access firmware version: {}", err), +    /// };      /// #     Ok(())      /// # }      /// ``` -    fn get_major_firmware_version(&self) -> i32 { -        unsafe { nitrokey_sys::NK_get_major_firmware_version() } -    } - -    /// Returns the minor part of the firmware version (for example 8 for version 0.8). -    /// -    /// # Example -    /// -    /// ```no_run -    /// use nitrokey::Device; -    /// # use nitrokey::Error; -    /// -    /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; -    /// println!( -    ///     "Firmware version: {}.{}", -    ///     device.get_major_firmware_version(), -    ///     device.get_minor_firmware_version(), -    /// ); -    /// #     Ok(()) -    /// # } -    fn get_minor_firmware_version(&self) -> i32 { -        unsafe { nitrokey_sys::NK_get_minor_firmware_version() } +    fn get_firmware_version(&self) -> Result<FirmwareVersion, Error> { +        let major = result_or_error(unsafe { nitrokey_sys::NK_get_major_firmware_version() })?; +        let minor = result_or_error(unsafe { nitrokey_sys::NK_get_minor_firmware_version() })?; +        let max = i32::from(u8::max_value()); +        if major < 0 || minor < 0 || major > max || minor > max { +            return Err(Error::UnexpectedError); +        } +        Ok(FirmwareVersion { +            major: major as u8, +            minor: minor as u8, +        })      }      /// Returns the current configuration of the Nitrokey device. @@ -458,10 +452,10 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// match device.change_admin_pin("12345678", "12345679") {      ///     Ok(()) => println!("Updated admin PIN."), -    ///     Err(err) => println!("Failed to update admin PIN: {}", err), +    ///     Err(err) => eprintln!("Failed to update admin PIN: {}", err),      /// };      /// #     Ok(())      /// # } @@ -469,7 +463,7 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {      ///      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword -    fn change_admin_pin(&self, current: &str, new: &str) -> Result<(), Error> { +    fn change_admin_pin(&mut self, current: &str, new: &str) -> Result<(), Error> {          let current_string = get_cstring(current)?;          let new_string = get_cstring(new)?;          get_command_result(unsafe { @@ -491,10 +485,10 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// match device.change_user_pin("123456", "123457") {      ///     Ok(()) => println!("Updated admin PIN."), -    ///     Err(err) => println!("Failed to update admin PIN: {}", err), +    ///     Err(err) => eprintln!("Failed to update admin PIN: {}", err),      /// };      /// #     Ok(())      /// # } @@ -502,7 +496,7 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {      ///      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword -    fn change_user_pin(&self, current: &str, new: &str) -> Result<(), Error> { +    fn change_user_pin(&mut self, current: &str, new: &str) -> Result<(), Error> {          let current_string = get_cstring(current)?;          let new_string = get_cstring(new)?;          get_command_result(unsafe { @@ -524,10 +518,10 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// match device.unlock_user_pin("12345678", "123456") {      ///     Ok(()) => println!("Unlocked user PIN."), -    ///     Err(err) => println!("Failed to unlock user PIN: {}", err), +    ///     Err(err) => eprintln!("Failed to unlock user PIN: {}", err),      /// };      /// #     Ok(())      /// # } @@ -535,7 +529,7 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {      ///      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword -    fn unlock_user_pin(&self, admin_pin: &str, user_pin: &str) -> Result<(), Error> { +    fn unlock_user_pin(&mut self, admin_pin: &str, user_pin: &str) -> Result<(), Error> {          let admin_pin_string = get_cstring(admin_pin)?;          let user_pin_string = get_cstring(user_pin)?;          get_command_result(unsafe { @@ -558,15 +552,15 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// match device.lock() {      ///     Ok(()) => println!("Locked the Nitrokey device."), -    ///     Err(err) => println!("Could not lock the Nitrokey device: {}", err), +    ///     Err(err) => eprintln!("Could not lock the Nitrokey device: {}", err),      /// };      /// #     Ok(())      /// # }      /// ``` -    fn lock(&self) -> Result<(), Error> { +    fn lock(&mut self) -> Result<(), Error> {          get_command_result(unsafe { nitrokey_sys::NK_lock_device() })      } @@ -589,17 +583,17 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// match device.factory_reset("12345678") {      ///     Ok(()) => println!("Performed a factory reset."), -    ///     Err(err) => println!("Could not perform a factory reset: {}", err), +    ///     Err(err) => eprintln!("Could not perform a factory reset: {}", err),      /// };      /// #     Ok(())      /// # }      /// ```      ///      /// [`build_aes_key`]: #method.build_aes_key -    fn factory_reset(&self, admin_pin: &str) -> Result<(), Error> { +    fn factory_reset(&mut self, admin_pin: &str) -> Result<(), Error> {          let admin_pin_string = get_cstring(admin_pin)?;          get_command_result(unsafe { nitrokey_sys::NK_factory_reset(admin_pin_string.as_ptr()) })      } @@ -623,17 +617,17 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// match device.build_aes_key("12345678") {      ///     Ok(()) => println!("New AES keys have been built."), -    ///     Err(err) => println!("Could not build new AES keys: {}", err), +    ///     Err(err) => eprintln!("Could not build new AES keys: {}", err),      /// };      /// #     Ok(())      /// # }      /// ```      ///      /// [`factory_reset`]: #method.factory_reset -    fn build_aes_key(&self, admin_pin: &str) -> Result<(), Error> { +    fn build_aes_key(&mut self, admin_pin: &str) -> Result<(), Error> {          let admin_pin_string = get_cstring(admin_pin)?;          get_command_result(unsafe { nitrokey_sys::NK_build_aes_key(admin_pin_string.as_ptr()) })      } @@ -655,7 +649,7 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {  ///  /// match nitrokey::connect() {  ///     Ok(device) => do_something(device), -///     Err(err) => println!("Could not connect to a Nitrokey: {}", err), +///     Err(err) => eprintln!("Could not connect to a Nitrokey: {}", err),  /// }  /// ```  /// @@ -687,7 +681,7 @@ pub fn connect() -> Result<DeviceWrapper, Error> {  ///  /// match nitrokey::connect_model(Model::Pro) {  ///     Ok(device) => do_something(device), -///     Err(err) => println!("Could not connect to a Nitrokey Pro: {}", err), +///     Err(err) => eprintln!("Could not connect to a Nitrokey Pro: {}", err),  /// }  /// ```  /// @@ -734,6 +728,13 @@ impl DeviceWrapper {              DeviceWrapper::Pro(ref pro) => pro,          }      } + +    fn device_mut(&mut self) -> &mut dyn Device { +        match *self { +            DeviceWrapper::Storage(ref mut storage) => storage, +            DeviceWrapper::Pro(ref mut pro) => pro, +        } +    }  }  impl From<Pro> for DeviceWrapper { @@ -757,8 +758,8 @@ impl GenerateOtp for DeviceWrapper {          self.device().get_totp_slot_name(slot)      } -    fn get_hotp_code(&self, slot: u8) -> Result<String, Error> { -        self.device().get_hotp_code(slot) +    fn get_hotp_code(&mut self, slot: u8) -> Result<String, Error> { +        self.device_mut().get_hotp_code(slot)      }      fn get_totp_code(&self, slot: u8) -> Result<String, Error> { @@ -791,7 +792,7 @@ impl Pro {      ///      /// match nitrokey::Pro::connect() {      ///     Ok(device) => use_pro(device), -    ///     Err(err) => println!("Could not connect to the Nitrokey Pro: {}", err), +    ///     Err(err) => eprintln!("Could not connect to the Nitrokey Pro: {}", err),      /// }      /// ```      /// @@ -844,7 +845,7 @@ impl Storage {      ///      /// match nitrokey::Storage::connect() {      ///     Ok(device) => use_storage(device), -    ///     Err(err) => println!("Could not connect to the Nitrokey Storage: {}", err), +    ///     Err(err) => eprintln!("Could not connect to the Nitrokey Storage: {}", err),      /// }      /// ```      /// @@ -881,10 +882,10 @@ impl Storage {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::Storage::connect()?; +    /// let mut device = nitrokey::Storage::connect()?;      /// match device.change_update_pin("12345678", "87654321") {      ///     Ok(()) => println!("Updated update PIN."), -    ///     Err(err) => println!("Failed to update update PIN: {}", err), +    ///     Err(err) => eprintln!("Failed to update update PIN: {}", err),      /// };      /// #     Ok(())      /// # } @@ -892,7 +893,7 @@ impl Storage {      ///      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword -    pub fn change_update_pin(&self, current: &str, new: &str) -> Result<(), Error> { +    pub fn change_update_pin(&mut self, current: &str, new: &str) -> Result<(), Error> {          let current_string = get_cstring(current)?;          let new_string = get_cstring(new)?;          get_command_result(unsafe { @@ -918,10 +919,10 @@ impl Storage {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::Storage::connect()?; +    /// let mut device = nitrokey::Storage::connect()?;      /// match device.enable_firmware_update("12345678") {      ///     Ok(()) => println!("Nitrokey entered update mode."), -    ///     Err(err) => println!("Could not enter update mode: {}", err), +    ///     Err(err) => eprintln!("Could not enter update mode: {}", err),      /// };      /// #     Ok(())      /// # } @@ -929,7 +930,7 @@ impl Storage {      ///      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword -    pub fn enable_firmware_update(&self, update_pin: &str) -> Result<(), Error> { +    pub fn enable_firmware_update(&mut self, update_pin: &str) -> Result<(), Error> {          let update_pin_string = get_cstring(update_pin)?;          get_command_result(unsafe {              nitrokey_sys::NK_enable_firmware_update(update_pin_string.as_ptr()) @@ -952,10 +953,10 @@ impl Storage {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::Storage::connect()?; +    /// let mut device = nitrokey::Storage::connect()?;      /// match device.enable_encrypted_volume("123456") {      ///     Ok(()) => println!("Enabled the encrypted volume."), -    ///     Err(err) => println!("Could not enable the encrypted volume: {}", err), +    ///     Err(err) => eprintln!("Could not enable the encrypted volume: {}", err),      /// };      /// #     Ok(())      /// # } @@ -963,7 +964,7 @@ impl Storage {      ///      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword -    pub fn enable_encrypted_volume(&self, user_pin: &str) -> Result<(), Error> { +    pub fn enable_encrypted_volume(&mut self, user_pin: &str) -> Result<(), Error> {          let user_pin = get_cstring(user_pin)?;          get_command_result(unsafe { nitrokey_sys::NK_unlock_encrypted_volume(user_pin.as_ptr()) })      } @@ -981,7 +982,7 @@ impl Storage {      /// fn use_volume() {}      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::Storage::connect()?; +    /// let mut device = nitrokey::Storage::connect()?;      /// match device.enable_encrypted_volume("123456") {      ///     Ok(()) => {      ///         println!("Enabled the encrypted volume."); @@ -989,16 +990,16 @@ impl Storage {      ///         match device.disable_encrypted_volume() {      ///             Ok(()) => println!("Disabled the encrypted volume."),      ///             Err(err) => { -    ///                 println!("Could not disable the encrypted volume: {}", err); +    ///                 eprintln!("Could not disable the encrypted volume: {}", err);      ///             },      ///         };      ///     }, -    ///     Err(err) => println!("Could not enable the encrypted volume: {}", err), +    ///     Err(err) => eprintln!("Could not enable the encrypted volume: {}", err),      /// };      /// #     Ok(())      /// # }      /// ``` -    pub fn disable_encrypted_volume(&self) -> Result<(), Error> { +    pub fn disable_encrypted_volume(&mut self) -> Result<(), Error> {          get_command_result(unsafe { nitrokey_sys::NK_lock_encrypted_volume() })      } @@ -1027,11 +1028,11 @@ impl Storage {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::Storage::connect()?; +    /// let mut device = nitrokey::Storage::connect()?;      /// device.enable_encrypted_volume("123445")?;      /// match device.enable_hidden_volume("hidden-pw") {      ///     Ok(()) => println!("Enabled a hidden volume."), -    ///     Err(err) => println!("Could not enable the hidden volume: {}", err), +    ///     Err(err) => eprintln!("Could not enable the hidden volume: {}", err),      /// };      /// #     Ok(())      /// # } @@ -1040,7 +1041,7 @@ impl Storage {      /// [`enable_encrypted_volume`]: #method.enable_encrypted_volume      /// [`AesDecryptionFailed`]: enum.CommandError.html#variant.AesDecryptionFailed      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString -    pub fn enable_hidden_volume(&self, volume_password: &str) -> Result<(), Error> { +    pub fn enable_hidden_volume(&mut self, volume_password: &str) -> Result<(), Error> {          let volume_password = get_cstring(volume_password)?;          get_command_result(unsafe {              nitrokey_sys::NK_unlock_hidden_volume(volume_password.as_ptr()) @@ -1060,7 +1061,7 @@ impl Storage {      /// fn use_volume() {}      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::Storage::connect()?; +    /// let mut device = nitrokey::Storage::connect()?;      /// device.enable_encrypted_volume("123445")?;      /// match device.enable_hidden_volume("hidden-pw") {      ///     Ok(()) => { @@ -1069,16 +1070,16 @@ impl Storage {      ///         match device.disable_hidden_volume() {      ///             Ok(()) => println!("Disabled the hidden volume."),      ///             Err(err) => { -    ///                 println!("Could not disable the hidden volume: {}", err); +    ///                 eprintln!("Could not disable the hidden volume: {}", err);      ///             },      ///         };      ///     }, -    ///     Err(err) => println!("Could not enable the hidden volume: {}", err), +    ///     Err(err) => eprintln!("Could not enable the hidden volume: {}", err),      /// };      /// #     Ok(())      /// # }      /// ``` -    pub fn disable_hidden_volume(&self) -> Result<(), Error> { +    pub fn disable_hidden_volume(&mut self) -> Result<(), Error> {          get_command_result(unsafe { nitrokey_sys::NK_lock_hidden_volume() })      } @@ -1107,7 +1108,7 @@ impl Storage {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::Storage::connect()?; +    /// let mut device = nitrokey::Storage::connect()?;      /// device.enable_encrypted_volume("123445")?;      /// device.create_hidden_volume(0, 0, 100, "hidden-pw")?;      /// #     Ok(()) @@ -1117,7 +1118,7 @@ impl Storage {      /// [`AesDecryptionFailed`]: enum.CommandError.html#variant.AesDecryptionFailed      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      pub fn create_hidden_volume( -        &self, +        &mut self,          slot: u8,          start: u8,          end: u8, @@ -1147,10 +1148,10 @@ impl Storage {      /// use nitrokey::VolumeMode;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::Storage::connect()?; -    /// match device.set_unencrypted_volume_mode("123456", VolumeMode::ReadWrite) { +    /// let mut device = nitrokey::Storage::connect()?; +    /// match device.set_unencrypted_volume_mode("12345678", VolumeMode::ReadWrite) {      ///     Ok(()) => println!("Set the unencrypted volume to read-write mode."), -    ///     Err(err) => println!("Could not set the unencrypted volume to read-write mode: {}", err), +    ///     Err(err) => eprintln!("Could not set the unencrypted volume to read-write mode: {}", err),      /// };      /// #     Ok(())      /// # } @@ -1159,7 +1160,7 @@ impl Storage {      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword      pub fn set_unencrypted_volume_mode( -        &self, +        &mut self,          admin_pin: &str,          mode: VolumeMode,      ) -> Result<(), Error> { @@ -1175,6 +1176,51 @@ impl Storage {          get_command_result(result)      } +    /// Sets the access mode of the encrypted volume. +    /// +    /// This command will reconnect the encrypted volume so buffers should be flushed before +    /// calling it.  It is only available in firmware version 0.49. +    /// +    /// # Errors +    /// +    /// - [`InvalidString`][] if the provided password contains a null byte +    /// - [`WrongPassword`][] if the provided admin password is wrong +    /// +    /// # Example +    /// +    /// ```no_run +    /// # use nitrokey::Error; +    /// use nitrokey::VolumeMode; +    /// +    /// # fn try_main() -> Result<(), Error> { +    /// let mut device = nitrokey::Storage::connect()?; +    /// match device.set_encrypted_volume_mode("12345678", VolumeMode::ReadWrite) { +    ///     Ok(()) => println!("Set the encrypted volume to read-write mode."), +    ///     Err(err) => eprintln!("Could not set the encrypted volume to read-write mode: {}", err), +    /// }; +    /// #     Ok(()) +    /// # } +    /// ``` +    /// +    /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString +    /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword +    pub fn set_encrypted_volume_mode( +        &mut self, +        admin_pin: &str, +        mode: VolumeMode, +    ) -> Result<(), Error> { +        let admin_pin = get_cstring(admin_pin)?; +        let result = match mode { +            VolumeMode::ReadOnly => unsafe { +                nitrokey_sys::NK_set_encrypted_read_only(admin_pin.as_ptr()) +            }, +            VolumeMode::ReadWrite => unsafe { +                nitrokey_sys::NK_set_encrypted_read_write(admin_pin.as_ptr()) +            }, +        }; +        get_command_result(result) +    } +      /// Returns the status of the connected storage device.      ///      /// # Example @@ -1190,7 +1236,7 @@ impl Storage {      ///     Ok(status) => {      ///         println!("SD card ID: {:#x}", status.serial_number_sd_card);      ///     }, -    ///     Err(err) => println!("Could not get Storage status: {}", err), +    ///     Err(err) => eprintln!("Could not get Storage status: {}", err),      /// };      /// #     Ok(())      /// # } @@ -1234,7 +1280,7 @@ impl Storage {      ///         println!("SD card ID:   {:#x}", data.sd_card.serial_number);      ///         println!("SD card size: {} GB", data.sd_card.size);      ///     }, -    ///     Err(err) => println!("Could not get Storage production info: {}", err), +    ///     Err(err) => eprintln!("Could not get Storage production info: {}", err),      /// };      /// #     Ok(())      /// # } @@ -1276,10 +1322,10 @@ impl Storage {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::Storage::connect()?; +    /// let mut device = nitrokey::Storage::connect()?;      /// match device.clear_new_sd_card_warning("12345678") {      ///     Ok(()) => println!("Cleared the new SD card warning."), -    ///     Err(err) => println!("Could not set the clear the new SD card warning: {}", err), +    ///     Err(err) => eprintln!("Could not set the clear the new SD card warning: {}", err),      /// };      /// #     Ok(())      /// # } @@ -1287,7 +1333,7 @@ impl Storage {      ///      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword -    pub fn clear_new_sd_card_warning(&self, admin_pin: &str) -> Result<(), Error> { +    pub fn clear_new_sd_card_warning(&mut self, admin_pin: &str) -> Result<(), Error> {          let admin_pin = get_cstring(admin_pin)?;          get_command_result(unsafe {              nitrokey_sys::NK_clear_new_sd_card_warning(admin_pin.as_ptr()) @@ -1295,7 +1341,7 @@ impl Storage {      }      /// Blinks the red and green LED alternatively and infinitely until the device is reconnected. -    pub fn wink(&self) -> Result<(), Error> { +    pub fn wink(&mut self) -> Result<(), Error> {          get_command_result(unsafe { nitrokey_sys::NK_wink() })      } @@ -1315,7 +1361,7 @@ impl Storage {      ///      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword -    pub fn export_firmware(&self, admin_pin: &str) -> Result<(), Error> { +    pub fn export_firmware(&mut self, admin_pin: &str) -> Result<(), Error> {          let admin_pin_string = get_cstring(admin_pin)?;          get_command_result(unsafe { nitrokey_sys::NK_export_firmware(admin_pin_string.as_ptr()) })      } diff --git a/nitrokey/src/lib.rs b/nitrokey/src/lib.rs index f2d524e..c35829c 100644 --- a/nitrokey/src/lib.rs +++ b/nitrokey/src/lib.rs @@ -47,13 +47,13 @@  //! let device = nitrokey::connect()?;  //! let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::SixDigits);  //! match device.authenticate_admin("12345678") { -//!     Ok(admin) => { +//!     Ok(mut admin) => {  //!         match admin.write_hotp_slot(slot_data, 0) {  //!             Ok(()) => println!("Successfully wrote slot."), -//!             Err(err) => println!("Could not write slot: {}", err), +//!             Err(err) => eprintln!("Could not write slot: {}", err),  //!         }  //!     }, -//!     Err((_, err)) => println!("Could not authenticate as admin: {}", err), +//!     Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err),  //! }  //! #     Ok(())  //! # } @@ -66,10 +66,10 @@  //! # use nitrokey::Error;  //!  //! # fn try_main() -> Result<(), Error> { -//! let device = nitrokey::connect()?; +//! let mut device = nitrokey::connect()?;  //! match device.get_hotp_code(1) {  //!     Ok(code) => println!("Generated HOTP code: {}", code), -//!     Err(err) => println!("Could not generate HOTP code: {}", err), +//!     Err(err) => eprintln!("Could not generate HOTP code: {}", err),  //! }  //! #     Ok(())  //! # } diff --git a/nitrokey/src/otp.rs b/nitrokey/src/otp.rs index 6e0379b..ee142c7 100644 --- a/nitrokey/src/otp.rs +++ b/nitrokey/src/otp.rs @@ -38,13 +38,13 @@ pub trait ConfigureOtp {      /// let device = nitrokey::connect()?;      /// let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::SixDigits);      /// match device.authenticate_admin("12345678") { -    ///     Ok(admin) => { +    ///     Ok(mut admin) => {      ///         match admin.write_hotp_slot(slot_data, 0) {      ///             Ok(()) => println!("Successfully wrote slot."), -    ///             Err(err) => println!("Could not write slot: {}", err), +    ///             Err(err) => eprintln!("Could not write slot: {}", err),      ///         }      ///     }, -    ///     Err((_, err)) => println!("Could not authenticate as admin: {}", err), +    ///     Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err),      /// }      /// #     Ok(())      /// # } @@ -53,7 +53,7 @@ pub trait ConfigureOtp {      /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      /// [`NoName`]: enum.CommandError.html#variant.NoName -    fn write_hotp_slot(&self, data: OtpSlotData, counter: u64) -> Result<(), Error>; +    fn write_hotp_slot(&mut self, data: OtpSlotData, counter: u64) -> Result<(), Error>;      /// Configure a TOTP slot with the given data and set the TOTP time window to the given value      /// (default 30). @@ -74,13 +74,13 @@ pub trait ConfigureOtp {      /// let device = nitrokey::connect()?;      /// let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::EightDigits);      /// match device.authenticate_admin("12345678") { -    ///     Ok(admin) => { +    ///     Ok(mut admin) => {      ///         match admin.write_totp_slot(slot_data, 30) {      ///             Ok(()) => println!("Successfully wrote slot."), -    ///             Err(err) => println!("Could not write slot: {}", err), +    ///             Err(err) => eprintln!("Could not write slot: {}", err),      ///         }      ///     }, -    ///     Err((_, err)) => println!("Could not authenticate as admin: {}", err), +    ///     Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err),      /// }      /// #     Ok(())      /// # } @@ -89,7 +89,7 @@ pub trait ConfigureOtp {      /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      /// [`NoName`]: enum.CommandError.html#variant.NoName -    fn write_totp_slot(&self, data: OtpSlotData, time_window: u16) -> Result<(), Error>; +    fn write_totp_slot(&mut self, data: OtpSlotData, time_window: u16) -> Result<(), Error>;      /// Erases an HOTP slot.      /// @@ -106,20 +106,20 @@ pub trait ConfigureOtp {      /// # fn try_main() -> Result<(), Error> {      /// let device = nitrokey::connect()?;      /// match device.authenticate_admin("12345678") { -    ///     Ok(admin) => { +    ///     Ok(mut admin) => {      ///         match admin.erase_hotp_slot(1) {      ///             Ok(()) => println!("Successfully erased slot."), -    ///             Err(err) => println!("Could not erase slot: {}", err), +    ///             Err(err) => eprintln!("Could not erase slot: {}", err),      ///         }      ///     }, -    ///     Err((_, err)) => println!("Could not authenticate as admin: {}", err), +    ///     Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err),      /// }      /// #     Ok(())      /// # }      /// ```      ///      /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot -    fn erase_hotp_slot(&self, slot: u8) -> Result<(), Error>; +    fn erase_hotp_slot(&mut self, slot: u8) -> Result<(), Error>;      /// Erases a TOTP slot.      /// @@ -136,20 +136,20 @@ pub trait ConfigureOtp {      /// # fn try_main() -> Result<(), Error> {      /// let device = nitrokey::connect()?;      /// match device.authenticate_admin("12345678") { -    ///     Ok(admin) => { +    ///     Ok(mut admin) => {      ///         match admin.erase_totp_slot(1) {      ///             Ok(()) => println!("Successfully erased slot."), -    ///             Err(err) => println!("Could not erase slot: {}", err), +    ///             Err(err) => eprintln!("Could not erase slot: {}", err),      ///         }      ///     }, -    ///     Err((_, err)) => println!("Could not authenticate as admin: {}", err), +    ///     Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err),      /// }      /// #     Ok(())      /// # }      /// ```      ///      /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot -    fn erase_totp_slot(&self, slot: u8) -> Result<(), Error>; +    fn erase_totp_slot(&mut self, slot: u8) -> Result<(), Error>;  }  /// Provides methods to generate OTP codes and to query OTP slots on a Nitrokey @@ -171,11 +171,11 @@ pub trait GenerateOtp {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH);      /// match time {      ///     Ok(time) => device.set_time(time.as_secs(), false)?, -    ///     Err(_) => println!("The system time is before the Unix epoch!"), +    ///     Err(_) => eprintln!("The system time is before the Unix epoch!"),      /// }      /// #     Ok(())      /// # } @@ -187,7 +187,7 @@ pub trait GenerateOtp {      ///      /// [`get_totp_code`]: #method.get_totp_code      /// [`Timestamp`]: enum.CommandError.html#variant.Timestamp -    fn set_time(&self, time: u64, force: bool) -> Result<(), Error> { +    fn set_time(&mut self, time: u64, force: bool) -> Result<(), Error> {          let result = if force {              unsafe { nitrokey_sys::NK_totp_set_time(time) }          } else { @@ -212,8 +212,8 @@ pub trait GenerateOtp {      /// let device = nitrokey::connect()?;      /// match device.get_hotp_slot_name(1) {      ///     Ok(name) => println!("HOTP slot 1: {}", name), -    ///     Err(Error::CommandError(CommandError::SlotNotProgrammed)) => println!("HOTP slot 1 not programmed"), -    ///     Err(err) => println!("Could not get slot name: {}", err), +    ///     Err(Error::CommandError(CommandError::SlotNotProgrammed)) => eprintln!("HOTP slot 1 not programmed"), +    ///     Err(err) => eprintln!("Could not get slot name: {}", err),      /// };      /// #     Ok(())      /// # } @@ -241,8 +241,8 @@ pub trait GenerateOtp {      /// let device = nitrokey::connect()?;      /// match device.get_totp_slot_name(1) {      ///     Ok(name) => println!("TOTP slot 1: {}", name), -    ///     Err(Error::CommandError(CommandError::SlotNotProgrammed)) => println!("TOTP slot 1 not programmed"), -    ///     Err(err) => println!("Could not get slot name: {}", err), +    ///     Err(Error::CommandError(CommandError::SlotNotProgrammed)) => eprintln!("TOTP slot 1 not programmed"), +    ///     Err(err) => eprintln!("Could not get slot name: {}", err),      /// };      /// #     Ok(())      /// # } @@ -270,7 +270,7 @@ pub trait GenerateOtp {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// let code = device.get_hotp_code(1)?;      /// println!("Generated HOTP code on slot 1: {}", code);      /// #     Ok(()) @@ -281,7 +281,7 @@ pub trait GenerateOtp {      /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot      /// [`NotAuthorized`]: enum.CommandError.html#variant.NotAuthorized      /// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed -    fn get_hotp_code(&self, slot: u8) -> Result<String, Error> { +    fn get_hotp_code(&mut self, slot: u8) -> Result<String, Error> {          result_from_string(unsafe { nitrokey_sys::NK_get_hotp_code(slot) })      } @@ -305,7 +305,7 @@ pub trait GenerateOtp {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH);      /// match time {      ///     Ok(time) => { @@ -313,7 +313,7 @@ pub trait GenerateOtp {      ///         let code = device.get_totp_code(1)?;      ///         println!("Generated TOTP code on slot 1: {}", code);      ///     }, -    ///     Err(_) => println!("Timestamps before 1970-01-01 are not supported!"), +    ///     Err(_) => eprintln!("Timestamps before 1970-01-01 are not supported!"),      /// }      /// #     Ok(())      /// # } diff --git a/nitrokey/src/pws.rs b/nitrokey/src/pws.rs index fcf057b..371de6e 100644 --- a/nitrokey/src/pws.rs +++ b/nitrokey/src/pws.rs @@ -43,9 +43,10 @@ pub const SLOT_COUNT: u8 = 16;  /// }  ///  /// # fn try_main() -> Result<(), Error> { -/// let device = nitrokey::connect()?; +/// let mut device = nitrokey::connect()?;  /// let pws = device.get_password_safe("123456")?;  /// use_password_safe(&pws); +/// drop(pws);  /// device.lock()?;  /// #     Ok(())  /// # } @@ -97,14 +98,14 @@ pub trait GetPasswordSafe {      /// fn use_password_safe(pws: &PasswordSafe) {}      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// match device.get_password_safe("123456") {      ///     Ok(pws) => {      ///         use_password_safe(&pws); -    ///         device.lock()?;      ///     }, -    ///     Err(err) => println!("Could not open the password safe: {}", err), +    ///     Err(err) => eprintln!("Could not open the password safe: {}", err),      /// }; +    /// device.lock()?;      /// #     Ok(())      /// # }      /// ``` @@ -116,7 +117,7 @@ pub trait GetPasswordSafe {      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      /// [`Unknown`]: enum.CommandError.html#variant.Unknown      /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword -    fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, Error>; +    fn get_password_safe(&mut self, user_pin: &str) -> Result<PasswordSafe<'_>, Error>;  }  fn get_password_safe<'a>( @@ -148,7 +149,7 @@ impl<'a> PasswordSafe<'a> {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// let pws = device.get_password_safe("123456")?;      /// pws.get_slot_status()?.iter().enumerate().for_each(|(slot, programmed)| {      ///     let status = match *programmed { @@ -193,7 +194,7 @@ impl<'a> PasswordSafe<'a> {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// match device.get_password_safe("123456") {      ///     Ok(pws) => {      ///         let name = pws.get_slot_name(0)?; @@ -201,7 +202,7 @@ impl<'a> PasswordSafe<'a> {      ///         let password = pws.get_slot_login(0)?;      ///         println!("Credentials for {}: login {}, password {}", name, login, password);      ///     }, -    ///     Err(err) => println!("Could not open the password safe: {}", err), +    ///     Err(err) => eprintln!("Could not open the password safe: {}", err),      /// };      /// #     Ok(())      /// # } @@ -230,7 +231,7 @@ impl<'a> PasswordSafe<'a> {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// let pws = device.get_password_safe("123456")?;      /// let name = pws.get_slot_name(0)?;      /// let login = pws.get_slot_login(0)?; @@ -263,7 +264,7 @@ impl<'a> PasswordSafe<'a> {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// let pws = device.get_password_safe("123456")?;      /// let name = pws.get_slot_name(0)?;      /// let login = pws.get_slot_login(0)?; @@ -294,7 +295,7 @@ impl<'a> PasswordSafe<'a> {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// let pws = device.get_password_safe("123456")?;      /// let name = pws.get_slot_name(0)?;      /// let login = pws.get_slot_login(0)?; @@ -307,7 +308,7 @@ impl<'a> PasswordSafe<'a> {      /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot      /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString      pub fn write_slot( -        &self, +        &mut self,          slot: u8,          name: &str,          login: &str, @@ -340,18 +341,18 @@ impl<'a> PasswordSafe<'a> {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; -    /// let pws = device.get_password_safe("123456")?; +    /// let mut device = nitrokey::connect()?; +    /// let mut pws = device.get_password_safe("123456")?;      /// match pws.erase_slot(0) {      ///     Ok(()) => println!("Erased slot 0."), -    ///     Err(err) => println!("Could not erase slot 0: {}", err), +    ///     Err(err) => eprintln!("Could not erase slot 0: {}", err),      /// };      /// #     Ok(())      /// # }      /// ```      ///      /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot -    pub fn erase_slot(&self, slot: u8) -> Result<(), Error> { +    pub fn erase_slot(&mut self, slot: u8) -> Result<(), Error> {          get_command_result(unsafe { nitrokey_sys::NK_erase_password_safe_slot(slot) })      }  } @@ -364,19 +365,19 @@ impl<'a> Drop for PasswordSafe<'a> {  }  impl GetPasswordSafe for Pro { -    fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, Error> { +    fn get_password_safe(&mut self, user_pin: &str) -> Result<PasswordSafe<'_>, Error> {          get_password_safe(self, user_pin)      }  }  impl GetPasswordSafe for Storage { -    fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, Error> { +    fn get_password_safe(&mut self, user_pin: &str) -> Result<PasswordSafe<'_>, Error> {          get_password_safe(self, user_pin)      }  }  impl GetPasswordSafe for DeviceWrapper { -    fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, Error> { +    fn get_password_safe(&mut self, user_pin: &str) -> Result<PasswordSafe<'_>, Error> {          get_password_safe(self, user_pin)      }  } diff --git a/nitrokey/src/util.rs b/nitrokey/src/util.rs index b7e8cd3..fdb73c3 100644 --- a/nitrokey/src/util.rs +++ b/nitrokey/src/util.rs @@ -53,6 +53,10 @@ pub fn result_from_string(ptr: *const c_char) -> Result<String, Error> {      }  } +pub fn result_or_error<T>(value: T) -> Result<T, Error> { +    get_last_result().and(Ok(value)) +} +  pub fn get_command_result(value: c_int) -> Result<(), Error> {      if value == 0 {          Ok(()) diff --git a/nitrokey/tests/device.rs b/nitrokey/tests/device.rs index c790049..5c52024 100644 --- a/nitrokey/tests/device.rs +++ b/nitrokey/tests/device.rs @@ -10,11 +10,10 @@ use std::{thread, time};  use nitrokey::{      Authenticate, CommandError, CommunicationError, Config, ConfigureOtp, Device, Error,      GenerateOtp, GetPasswordSafe, LibraryError, OtpMode, OtpSlotData, Storage, VolumeMode, +    DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN,  };  use nitrokey_test::test as test_device; -use crate::util::{ADMIN_PASSWORD, USER_PASSWORD}; -  static ADMIN_NEW_PASSWORD: &str = "1234567890";  static UPDATE_PIN: &str = "12345678";  static UPDATE_NEW_PIN: &str = "87654321"; @@ -55,9 +54,9 @@ fn connect_pro(device: Pro) {      assert_eq!(device.get_model(), nitrokey::Model::Pro);      drop(device); -    assert!(nitrokey::connect().is_ok()); -    assert!(nitrokey::connect_model(nitrokey::Model::Pro).is_ok()); -    assert!(nitrokey::Pro::connect().is_ok()); +    assert_any_ok!(nitrokey::connect()); +    assert_any_ok!(nitrokey::connect_model(nitrokey::Model::Pro)); +    assert_any_ok!(nitrokey::Pro::connect());  }  #[test_device] @@ -65,9 +64,9 @@ fn connect_storage(device: Storage) {      assert_eq!(device.get_model(), nitrokey::Model::Storage);      drop(device); -    assert!(nitrokey::connect().is_ok()); -    assert!(nitrokey::connect_model(nitrokey::Model::Storage).is_ok()); -    assert!(nitrokey::Storage::connect().is_ok()); +    assert_any_ok!(nitrokey::connect()); +    assert_any_ok!(nitrokey::connect_model(nitrokey::Model::Storage)); +    assert_any_ok!(nitrokey::Storage::connect());  }  fn assert_empty_serial_number() { @@ -87,36 +86,34 @@ fn disconnect(device: DeviceWrapper) {  #[test_device]  fn get_serial_number(device: DeviceWrapper) { -    let result = device.get_serial_number(); -    assert!(result.is_ok()); -    let serial_number = result.unwrap(); +    let serial_number = unwrap_ok!(device.get_serial_number());      assert!(serial_number.is_ascii());      assert!(serial_number.chars().all(|c| c.is_ascii_hexdigit()));  }  #[test_device]  fn get_firmware_version(device: Pro) { -    assert_eq!(0, device.get_major_firmware_version()); -    let minor = device.get_minor_firmware_version(); -    assert!(minor > 0); +    let version = unwrap_ok!(device.get_firmware_version()); +    assert_eq!(0, version.major); +    assert!(version.minor > 0);  }  fn admin_retry<T: Authenticate + Device>(device: T, suffix: &str, count: u8) -> T { -    let result = device.authenticate_admin(&(ADMIN_PASSWORD.to_owned() + suffix)); +    let result = device.authenticate_admin(&(DEFAULT_ADMIN_PIN.to_owned() + suffix));      let device = match result {          Ok(admin) => admin.device(),          Err((device, _)) => device,      }; -    assert_eq!(count, device.get_admin_retry_count()); +    assert_ok!(count, device.get_admin_retry_count());      return device;  }  fn user_retry<T: Authenticate + Device>(device: T, suffix: &str, count: u8) -> T { -    let result = device.authenticate_user(&(USER_PASSWORD.to_owned() + suffix)); +    let result = device.authenticate_user(&(DEFAULT_USER_PIN.to_owned() + suffix));      let device = match result {          Ok(admin) => admin.device(),          Err((device, _)) => device,      }; -    assert_eq!(count, device.get_user_retry_count()); +    assert_ok!(count, device.get_user_retry_count());      return device;  } @@ -135,7 +132,7 @@ fn get_retry_count(device: DeviceWrapper) {  #[test_device]  fn config(device: DeviceWrapper) { -    let admin = device.authenticate_admin(ADMIN_PASSWORD).unwrap(); +    let mut admin = unwrap_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN));      let config = Config::new(None, None, None, true);      assert_ok!((), admin.write_config(config)); @@ -155,53 +152,67 @@ fn config(device: DeviceWrapper) {  #[test_device]  fn change_user_pin(device: DeviceWrapper) { -    let device = device.authenticate_user(USER_PASSWORD).unwrap().device(); +    let device = device.authenticate_user(DEFAULT_USER_PIN).unwrap().device();      let device = device.authenticate_user(USER_NEW_PASSWORD).unwrap_err().0; -    assert_ok!((), device.change_user_pin(USER_PASSWORD, USER_NEW_PASSWORD)); +    let mut device = device; +    assert_ok!( +        (), +        device.change_user_pin(DEFAULT_USER_PIN, USER_NEW_PASSWORD) +    ); -    let device = device.authenticate_user(USER_PASSWORD).unwrap_err().0; +    let device = device.authenticate_user(DEFAULT_USER_PIN).unwrap_err().0;      let device = device          .authenticate_user(USER_NEW_PASSWORD)          .unwrap()          .device(); -    let result = device.change_user_pin(USER_PASSWORD, USER_PASSWORD); +    let mut device = device; +    let result = device.change_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN);      assert_cmd_err!(CommandError::WrongPassword, result); -    assert_ok!((), device.change_user_pin(USER_NEW_PASSWORD, USER_PASSWORD)); +    assert_ok!( +        (), +        device.change_user_pin(USER_NEW_PASSWORD, DEFAULT_USER_PIN) +    ); -    let device = device.authenticate_user(USER_PASSWORD).unwrap().device(); +    let device = device.authenticate_user(DEFAULT_USER_PIN).unwrap().device();      assert!(device.authenticate_user(USER_NEW_PASSWORD).is_err());  }  #[test_device]  fn change_admin_pin(device: DeviceWrapper) { -    let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device(); -    let device = device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err().0; +    let device = device +        .authenticate_admin(DEFAULT_ADMIN_PIN) +        .unwrap() +        .device(); +    let mut device = device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err().0;      assert_ok!(          (), -        device.change_admin_pin(ADMIN_PASSWORD, ADMIN_NEW_PASSWORD) +        device.change_admin_pin(DEFAULT_ADMIN_PIN, ADMIN_NEW_PASSWORD)      ); -    let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap_err().0; -    let device = device +    let device = device.authenticate_admin(DEFAULT_ADMIN_PIN).unwrap_err().0; +    let mut device = device          .authenticate_admin(ADMIN_NEW_PASSWORD)          .unwrap()          .device();      assert_cmd_err!(          CommandError::WrongPassword, -        device.change_admin_pin(ADMIN_PASSWORD, ADMIN_PASSWORD) +        device.change_admin_pin(DEFAULT_ADMIN_PIN, DEFAULT_ADMIN_PIN)      );      assert_ok!(          (), -        device.change_admin_pin(ADMIN_NEW_PASSWORD, ADMIN_PASSWORD) +        device.change_admin_pin(ADMIN_NEW_PASSWORD, DEFAULT_ADMIN_PIN)      ); -    let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device(); +    let device = device +        .authenticate_admin(DEFAULT_ADMIN_PIN) +        .unwrap() +        .device();      device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err();  } @@ -222,63 +233,85 @@ where  #[test_device]  fn unlock_user_pin(device: DeviceWrapper) { -    let device = device.authenticate_user(USER_PASSWORD).unwrap().device(); -    assert_ok!((), device.unlock_user_pin(ADMIN_PASSWORD, USER_PASSWORD)); +    let mut device = device.authenticate_user(DEFAULT_USER_PIN).unwrap().device(); +    assert_ok!( +        (), +        device.unlock_user_pin(DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN) +    );      assert_cmd_err!(          CommandError::WrongPassword, -        device.unlock_user_pin(USER_PASSWORD, USER_PASSWORD) +        device.unlock_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN)      );      // block user PIN -    let wrong_password = USER_PASSWORD.to_owned() + "foo"; +    let wrong_password = DEFAULT_USER_PIN.to_owned() + "foo";      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 device = require_failed_user_login(device, USER_PASSWORD, 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(USER_PASSWORD, USER_PASSWORD) +        device.unlock_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN)      ); -    assert_ok!((), device.unlock_user_pin(ADMIN_PASSWORD, USER_PASSWORD)); -    let device = device.authenticate_user(USER_PASSWORD).unwrap().device(); +    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 device = require_failed_user_login(device, USER_PASSWORD, CommandError::WrongPassword); +    let mut device = +        require_failed_user_login(device, DEFAULT_USER_PIN, CommandError::WrongPassword);      // unblock with new PIN      assert_cmd_err!(          CommandError::WrongPassword, -        device.unlock_user_pin(USER_PASSWORD, USER_PASSWORD) +        device.unlock_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN)      );      assert_ok!(          (), -        device.unlock_user_pin(ADMIN_PASSWORD, USER_NEW_PASSWORD) +        device.unlock_user_pin(DEFAULT_ADMIN_PIN, USER_NEW_PASSWORD)      );      // reset user PIN -    assert_ok!((), device.change_user_pin(USER_NEW_PASSWORD, USER_PASSWORD)); +    assert_ok!( +        (), +        device.change_user_pin(USER_NEW_PASSWORD, DEFAULT_USER_PIN) +    ); +} + +fn assert_utf8_err_or_ne(left: &str, right: Result<String, Error>) { +    match right { +        Ok(s) => assert_ne!(left.to_string(), s), +        Err(Error::Utf8Error(_)) => {} +        Err(err) => panic!("Expected Utf8Error, got {}!", err), +    }  }  #[test_device]  fn factory_reset(device: DeviceWrapper) { -    let admin = device.authenticate_admin(ADMIN_PASSWORD).unwrap(); +    let mut admin = unwrap_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN));      let otp_data = OtpSlotData::new(1, "test", "0123468790", OtpMode::SixDigits);      assert_ok!((), admin.write_totp_slot(otp_data, 30)); -    let device = admin.device(); -    let pws = device.get_password_safe(USER_PASSWORD).unwrap(); +    let mut device = admin.device(); +    let mut pws = unwrap_ok!(device.get_password_safe(DEFAULT_USER_PIN));      assert_ok!((), pws.write_slot(0, "test", "testlogin", "testpw"));      drop(pws); -    assert_ok!((), device.change_user_pin(USER_PASSWORD, USER_NEW_PASSWORD));      assert_ok!(          (), -        device.change_admin_pin(ADMIN_PASSWORD, ADMIN_NEW_PASSWORD) +        device.change_user_pin(DEFAULT_USER_PIN, USER_NEW_PASSWORD) +    ); +    assert_ok!( +        (), +        device.change_admin_pin(DEFAULT_ADMIN_PIN, ADMIN_NEW_PASSWORD)      );      assert_cmd_err!( @@ -287,46 +320,55 @@ fn factory_reset(device: DeviceWrapper) {      );      assert_cmd_err!(          CommandError::WrongPassword, -        device.factory_reset(ADMIN_PASSWORD) +        device.factory_reset(DEFAULT_ADMIN_PIN)      );      assert_ok!((), device.factory_reset(ADMIN_NEW_PASSWORD)); -    let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device(); +    let device = device +        .authenticate_admin(DEFAULT_ADMIN_PIN) +        .unwrap() +        .device(); -    let user = device.authenticate_user(USER_PASSWORD).unwrap(); +    let user = unwrap_ok!(device.authenticate_user(DEFAULT_USER_PIN));      assert_cmd_err!(CommandError::SlotNotProgrammed, user.get_totp_slot_name(1)); -    let device = user.device(); -    let pws = device.get_password_safe(USER_PASSWORD).unwrap(); -    assert_ne!("test".to_string(), pws.get_slot_name(0).unwrap()); -    assert_ne!("testlogin".to_string(), pws.get_slot_login(0).unwrap()); -    assert_ne!("testpw".to_string(), pws.get_slot_password(0).unwrap()); +    let mut device = user.device(); +    let pws = unwrap_ok!(device.get_password_safe(DEFAULT_USER_PIN)); +    assert_utf8_err_or_ne("test", pws.get_slot_name(0)); +    assert_utf8_err_or_ne("testlogin", pws.get_slot_login(0)); +    assert_utf8_err_or_ne("testpw", pws.get_slot_password(0)); +    drop(pws); -    assert_ok!((), device.build_aes_key(ADMIN_PASSWORD)); +    assert_ok!((), device.build_aes_key(DEFAULT_ADMIN_PIN));  }  #[test_device]  fn build_aes_key(device: DeviceWrapper) { -    let pws = device.get_password_safe(USER_PASSWORD).unwrap(); +    let mut device = device; +    let mut pws = unwrap_ok!(device.get_password_safe(DEFAULT_USER_PIN));      assert_ok!((), pws.write_slot(0, "test", "testlogin", "testpw"));      drop(pws);      assert_cmd_err!(          CommandError::WrongPassword, -        device.build_aes_key(USER_PASSWORD) +        device.build_aes_key(DEFAULT_USER_PIN)      ); -    assert_ok!((), device.build_aes_key(ADMIN_PASSWORD)); +    assert_ok!((), device.build_aes_key(DEFAULT_ADMIN_PIN)); -    let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device(); +    let mut device = device +        .authenticate_admin(DEFAULT_ADMIN_PIN) +        .unwrap() +        .device(); -    let pws = device.get_password_safe(USER_PASSWORD).unwrap(); -    assert_ne!("test".to_string(), pws.get_slot_name(0).unwrap()); -    assert_ne!("testlogin".to_string(), pws.get_slot_login(0).unwrap()); -    assert_ne!("testpw".to_string(), pws.get_slot_password(0).unwrap()); +    let pws = unwrap_ok!(device.get_password_safe(DEFAULT_USER_PIN)); +    assert_utf8_err_or_ne("test", pws.get_slot_name(0)); +    assert_utf8_err_or_ne("testlogin", pws.get_slot_login(0)); +    assert_utf8_err_or_ne("testpw", pws.get_slot_password(0));  }  #[test_device]  fn change_update_pin(device: Storage) { +    let mut device = device;      assert_cmd_err!(          CommandError::WrongPassword,          device.change_update_pin(UPDATE_NEW_PIN, UPDATE_PIN) @@ -337,6 +379,7 @@ fn change_update_pin(device: Storage) {  #[test_device]  fn encrypted_volume(device: Storage) { +    let mut device = device;      assert_ok!((), device.lock());      assert_eq!(1, count_nitrokey_block_devices()); @@ -347,7 +390,7 @@ fn encrypted_volume(device: Storage) {          device.enable_encrypted_volume("123")      );      assert_eq!(1, count_nitrokey_block_devices()); -    assert_ok!((), device.enable_encrypted_volume(USER_PASSWORD)); +    assert_ok!((), device.enable_encrypted_volume(DEFAULT_USER_PIN));      assert_eq!(2, count_nitrokey_block_devices());      assert_ok!((), device.disable_encrypted_volume());      assert_eq!(1, count_nitrokey_block_devices()); @@ -355,13 +398,14 @@ fn encrypted_volume(device: Storage) {  #[test_device]  fn hidden_volume(device: Storage) { +    let mut device = device;      assert_ok!((), device.lock());      assert_eq!(1, count_nitrokey_block_devices());      assert_ok!((), device.disable_hidden_volume());      assert_eq!(1, count_nitrokey_block_devices()); -    assert_ok!((), device.enable_encrypted_volume(USER_PASSWORD)); +    assert_ok!((), device.enable_encrypted_volume(DEFAULT_USER_PIN));      assert_eq!(2, count_nitrokey_block_devices());      // TODO: why this error code? @@ -390,51 +434,85 @@ fn hidden_volume(device: Storage) {  #[test_device]  fn lock(device: Storage) { -    assert_ok!((), device.enable_encrypted_volume(USER_PASSWORD)); +    let mut device = device; +    assert_ok!((), device.enable_encrypted_volume(DEFAULT_USER_PIN));      assert_ok!((), device.lock());      assert_eq!(1, count_nitrokey_block_devices());  }  #[test_device] +fn set_encrypted_volume_mode(device: Storage) { +    // This test case does not check the device status as the command only works with firmware +    // version 0.49.  For later versions, it does not do anything and always returns Ok(()). +    let mut device = device; + +    assert_ok!( +        (), +        device.set_encrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadOnly) +    ); + +    // TODO: re-enable once the password is checked in the firmware +    // assert_cmd_err!( +    //     CommandError::WrongPassword, +    //     device.set_encrypted_volume_mode(DEFAULT_USER_PIN, VolumeMode::ReadOnly) +    // ); + +    assert_ok!( +        (), +        device.set_encrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadOnly) +    ); +    assert_ok!( +        (), +        device.set_encrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadWrite) +    ); +    assert_ok!( +        (), +        device.set_encrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadOnly) +    ); +} + +#[test_device]  fn set_unencrypted_volume_mode(device: Storage) {      fn assert_mode(device: &Storage, mode: VolumeMode) { -        let status = device.get_status(); -        assert!(status.is_ok()); +        let status = unwrap_ok!(device.get_status());          assert_eq!( -            status.unwrap().unencrypted_volume.read_only, +            status.unencrypted_volume.read_only,              mode == VolumeMode::ReadOnly          );      } -    fn assert_success(device: &Storage, mode: VolumeMode) { -        assert_ok!((), device.set_unencrypted_volume_mode(ADMIN_PASSWORD, mode)); +    fn assert_success(device: &mut Storage, mode: VolumeMode) { +        assert_ok!( +            (), +            device.set_unencrypted_volume_mode(DEFAULT_ADMIN_PIN, mode) +        );          assert_mode(&device, mode);      } -    assert_success(&device, VolumeMode::ReadOnly); +    let mut device = device; +    assert_success(&mut device, VolumeMode::ReadOnly);      assert_cmd_err!(          CommandError::WrongPassword, -        device.set_unencrypted_volume_mode(USER_PASSWORD, VolumeMode::ReadOnly) +        device.set_unencrypted_volume_mode(DEFAULT_USER_PIN, VolumeMode::ReadOnly)      );      assert_mode(&device, VolumeMode::ReadOnly); -    assert_success(&device, VolumeMode::ReadWrite); -    assert_success(&device, VolumeMode::ReadWrite); -    assert_success(&device, VolumeMode::ReadOnly); +    assert_success(&mut device, VolumeMode::ReadWrite); +    assert_success(&mut device, VolumeMode::ReadWrite); +    assert_success(&mut device, VolumeMode::ReadOnly);  }  #[test_device]  fn get_storage_status(device: Storage) { -    let status = device.get_status().unwrap(); - +    let status = unwrap_ok!(device.get_status());      assert!(status.serial_number_sd_card > 0);      assert!(status.serial_number_smart_card > 0);  }  #[test_device]  fn get_production_info(device: Storage) { -    let info = device.get_production_info().unwrap(); +    let info = unwrap_ok!(device.get_production_info());      assert_eq!(0, info.firmware_version.major);      assert!(info.firmware_version.minor != 0);      assert!(info.serial_number_cpu != 0); @@ -447,43 +525,45 @@ fn get_production_info(device: Storage) {      assert!(info.sd_card.oem != 0);      assert!(info.sd_card.manufacturer != 0); -    let status = device.get_status().unwrap(); +    let status = unwrap_ok!(device.get_status());      assert_eq!(status.firmware_version, info.firmware_version);      assert_eq!(status.serial_number_sd_card, info.sd_card.serial_number);  }  #[test_device]  fn clear_new_sd_card_warning(device: Storage) { -    assert_ok!((), device.factory_reset(ADMIN_PASSWORD)); +    let mut device = device; +    assert_ok!((), device.factory_reset(DEFAULT_ADMIN_PIN));      thread::sleep(time::Duration::from_secs(3)); -    assert_ok!((), device.build_aes_key(ADMIN_PASSWORD)); +    assert_ok!((), device.build_aes_key(DEFAULT_ADMIN_PIN));      // We have to perform an SD card operation to reset the new_sd_card_found field      assert_ok!((), device.lock()); -    let status = device.get_status().unwrap(); +    let status = unwrap_ok!(device.get_status());      assert!(status.new_sd_card_found); -    assert_ok!((), device.clear_new_sd_card_warning(ADMIN_PASSWORD)); +    assert_ok!((), device.clear_new_sd_card_warning(DEFAULT_ADMIN_PIN)); -    let status = device.get_status().unwrap(); +    let status = unwrap_ok!(device.get_status());      assert!(!status.new_sd_card_found);  }  #[test_device]  fn export_firmware(device: Storage) { +    let mut device = device;      assert_cmd_err!(          CommandError::WrongPassword,          device.export_firmware("someadminpn")      ); -    assert_ok!((), device.export_firmware(ADMIN_PASSWORD)); +    assert_ok!((), device.export_firmware(DEFAULT_ADMIN_PIN));      assert_ok!(          (), -        device.set_unencrypted_volume_mode(ADMIN_PASSWORD, VolumeMode::ReadWrite) +        device.set_unencrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadWrite)      ); -    assert_ok!((), device.export_firmware(ADMIN_PASSWORD)); +    assert_ok!((), device.export_firmware(DEFAULT_ADMIN_PIN));      assert_ok!(          (), -        device.set_unencrypted_volume_mode(ADMIN_PASSWORD, VolumeMode::ReadOnly) +        device.set_unencrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadOnly)      );  } diff --git a/nitrokey/tests/lib.rs b/nitrokey/tests/lib.rs index 697024d..8ab75f6 100644 --- a/nitrokey/tests/lib.rs +++ b/nitrokey/tests/lib.rs @@ -1,9 +1,11 @@  // Copyright (C) 2019 Robin Krahl <robin.krahl@ireas.org>  // SPDX-License-Identifier: MIT +mod util; +  #[test]  fn get_library_version() { -    let version = nitrokey::get_library_version().unwrap(); +    let version = unwrap_ok!(nitrokey::get_library_version());      assert!(version.git.is_empty() || version.git.starts_with("v"));      assert!(version.major > 0); diff --git a/nitrokey/tests/otp.rs b/nitrokey/tests/otp.rs index e424673..c0bbecf 100644 --- a/nitrokey/tests/otp.rs +++ b/nitrokey/tests/otp.rs @@ -4,16 +4,14 @@  mod util;  use std::fmt::Debug; -use std::ops::Deref; +use std::ops::DerefMut;  use nitrokey::{      Admin, Authenticate, CommandError, Config, ConfigureOtp, Device, GenerateOtp, LibraryError, -    OtpMode, OtpSlotData, +    OtpMode, OtpSlotData, DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN,  };  use nitrokey_test::test as test_device; -use crate::util::{ADMIN_PASSWORD, USER_PASSWORD}; -  // test suite according to RFC 4226, Appendix D  static HOTP_SECRET: &str = "3132333435363738393031323334353637383930";  static HOTP_CODES: &[&str] = &[ @@ -43,27 +41,25 @@ where      T: Device,      (T, nitrokey::Error): Debug,  { -    device -        .authenticate_admin(ADMIN_PASSWORD) -        .expect("Could not login as admin.") +    unwrap_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN))  } -fn configure_hotp(admin: &ConfigureOtp, counter: u8) { +fn configure_hotp(admin: &mut ConfigureOtp, counter: u8) {      let slot_data = OtpSlotData::new(1, "test-hotp", HOTP_SECRET, OtpMode::SixDigits);      assert_ok!((), admin.write_hotp_slot(slot_data, counter.into()));  } -fn check_hotp_codes(device: &GenerateOtp, offset: u8) { +fn check_hotp_codes(device: &mut GenerateOtp, offset: u8) {      HOTP_CODES.iter().enumerate().for_each(|(i, code)| {          if i >= offset as usize { -            let result = device.get_hotp_code(1); -            assert_eq!(code, &result.unwrap()); +            assert_ok!(code.to_string(), device.get_hotp_code(1));          }      });  }  #[test_device]  fn set_time(device: DeviceWrapper) { +    let mut device = device;      assert_ok!((), device.set_time(1546385382, true));      assert_ok!((), device.set_time(1546385392, false));      assert_cmd_err!(CommandError::Timestamp, device.set_time(1546385292, false)); @@ -72,49 +68,47 @@ fn set_time(device: DeviceWrapper) {  #[test_device]  fn hotp_no_pin(device: DeviceWrapper) { -    let admin = make_admin_test_device(device); +    let mut admin = make_admin_test_device(device);      let config = Config::new(None, None, None, false);      assert_ok!((), admin.write_config(config)); -    configure_hotp(&admin, 0); -    check_hotp_codes(admin.deref(), 0); +    configure_hotp(&mut admin, 0); +    check_hotp_codes(admin.deref_mut(), 0); -    configure_hotp(&admin, 5); -    check_hotp_codes(admin.deref(), 5); +    configure_hotp(&mut admin, 5); +    check_hotp_codes(admin.deref_mut(), 5); -    configure_hotp(&admin, 0); -    check_hotp_codes(&admin.device(), 0); +    configure_hotp(&mut admin, 0); +    check_hotp_codes(&mut admin.device(), 0);  }  #[test_device]  fn hotp_pin(device: DeviceWrapper) { -    let admin = make_admin_test_device(device); +    let mut admin = make_admin_test_device(device);      let config = Config::new(None, None, None, true);      assert_ok!((), admin.write_config(config)); -    configure_hotp(&admin, 0); -    let user = admin.device().authenticate_user(USER_PASSWORD).unwrap(); -    check_hotp_codes(&user, 0); +    configure_hotp(&mut admin, 0); +    let mut user = unwrap_ok!(admin.device().authenticate_user(DEFAULT_USER_PIN)); +    check_hotp_codes(&mut user, 0);      assert_cmd_err!(CommandError::NotAuthorized, user.device().get_hotp_code(1));  }  #[test_device]  fn hotp_slot_name(device: DeviceWrapper) { -    let admin = make_admin_test_device(device); +    let mut admin = make_admin_test_device(device);      let slot_data = OtpSlotData::new(1, "test-hotp", HOTP_SECRET, OtpMode::SixDigits);      assert_ok!((), admin.write_hotp_slot(slot_data, 0));      let device = admin.device(); -    let result = device.get_hotp_slot_name(1); -    assert_eq!("test-hotp", result.unwrap()); -    let result = device.get_hotp_slot_name(4); -    assert_lib_err!(LibraryError::InvalidSlot, result); +    assert_ok!("test-hotp".to_string(), device.get_hotp_slot_name(1)); +    assert_lib_err!(LibraryError::InvalidSlot, device.get_hotp_slot_name(4));  }  #[test_device]  fn hotp_error(device: DeviceWrapper) { -    let admin = make_admin_test_device(device); +    let mut admin = make_admin_test_device(device);      let slot_data = OtpSlotData::new(1, "", HOTP_SECRET, OtpMode::SixDigits);      assert_cmd_err!(CommandError::NoName, admin.write_hotp_slot(slot_data, 0));      let slot_data = OtpSlotData::new(4, "test", HOTP_SECRET, OtpMode::SixDigits); @@ -133,7 +127,7 @@ fn hotp_error(device: DeviceWrapper) {  #[test_device]  fn hotp_erase(device: DeviceWrapper) { -    let admin = make_admin_test_device(device); +    let mut admin = make_admin_test_device(device);      let config = Config::new(None, None, None, false);      assert_ok!((), admin.write_config(config));      let slot_data = OtpSlotData::new(1, "test1", HOTP_SECRET, OtpMode::SixDigits); @@ -143,22 +137,22 @@ fn hotp_erase(device: DeviceWrapper) {      assert_ok!((), admin.erase_hotp_slot(1)); -    let device = admin.device(); +    let mut device = admin.device();      let result = device.get_hotp_slot_name(1);      assert_cmd_err!(CommandError::SlotNotProgrammed, result);      let result = device.get_hotp_code(1);      assert_cmd_err!(CommandError::SlotNotProgrammed, result); -    assert_eq!("test2", device.get_hotp_slot_name(2).unwrap()); +    assert_ok!("test2".to_string(), device.get_hotp_slot_name(2));  } -fn configure_totp(admin: &ConfigureOtp, factor: u64) { +fn configure_totp(admin: &mut ConfigureOtp, factor: u64) {      let slot_data = OtpSlotData::new(1, "test-totp", TOTP_SECRET, OtpMode::EightDigits);      let time_window = 30u64.checked_mul(factor).unwrap();      assert_ok!((), admin.write_totp_slot(slot_data, time_window as u16));  } -fn check_totp_codes(device: &GenerateOtp, factor: u64, timestamp_size: TotpTimestampSize) { +fn check_totp_codes(device: &mut GenerateOtp, factor: u64, timestamp_size: TotpTimestampSize) {      for (base_time, codes) in TOTP_CODES {          let time = base_time.checked_mul(factor).unwrap();          let is_u64 = time > u32::max_value() as u64; @@ -167,7 +161,7 @@ fn check_totp_codes(device: &GenerateOtp, factor: u64, timestamp_size: TotpTimes          }          assert_ok!((), device.set_time(time, true)); -        let code = device.get_totp_code(1).unwrap(); +        let code = unwrap_ok!(device.get_totp_code(1));          assert!(              code.contains(&code),              "Generated TOTP code {} for {}, but expected one of {}", @@ -180,49 +174,47 @@ fn check_totp_codes(device: &GenerateOtp, factor: u64, timestamp_size: TotpTimes  #[test_device]  fn totp_no_pin(device: DeviceWrapper) { -    // TODO: this test may fail due to bad timing --> find solution -    let admin = make_admin_test_device(device); +    let mut admin = make_admin_test_device(device);      let config = Config::new(None, None, None, false);      assert_ok!((), admin.write_config(config)); -    configure_totp(&admin, 1); -    check_totp_codes(admin.deref(), 1, TotpTimestampSize::U32); +    configure_totp(&mut admin, 1); +    check_totp_codes(admin.deref_mut(), 1, TotpTimestampSize::U32); -    configure_totp(&admin, 2); -    check_totp_codes(admin.deref(), 2, TotpTimestampSize::U32); +    configure_totp(&mut admin, 2); +    check_totp_codes(admin.deref_mut(), 2, TotpTimestampSize::U32); -    configure_totp(&admin, 1); -    check_totp_codes(&admin.device(), 1, TotpTimestampSize::U32); +    configure_totp(&mut admin, 1); +    check_totp_codes(&mut admin.device(), 1, TotpTimestampSize::U32);  }  #[test_device]  // Nitrokey Storage does only support timestamps that fit in a 32-bit  // unsigned integer, so don't test with it.  fn totp_no_pin_64(device: Pro) { -    let admin = make_admin_test_device(device); +    let mut admin = make_admin_test_device(device);      let config = Config::new(None, None, None, false);      assert_ok!((), admin.write_config(config)); -    configure_totp(&admin, 1); -    check_totp_codes(admin.deref(), 1, TotpTimestampSize::U64); +    configure_totp(&mut admin, 1); +    check_totp_codes(admin.deref_mut(), 1, TotpTimestampSize::U64); -    configure_totp(&admin, 2); -    check_totp_codes(admin.deref(), 2, TotpTimestampSize::U64); +    configure_totp(&mut admin, 2); +    check_totp_codes(admin.deref_mut(), 2, TotpTimestampSize::U64); -    configure_totp(&admin, 1); -    check_totp_codes(&admin.device(), 1, TotpTimestampSize::U64); +    configure_totp(&mut admin, 1); +    check_totp_codes(&mut admin.device(), 1, TotpTimestampSize::U64);  }  #[test_device]  fn totp_pin(device: DeviceWrapper) { -    // TODO: this test may fail due to bad timing --> find solution -    let admin = make_admin_test_device(device); +    let mut admin = make_admin_test_device(device);      let config = Config::new(None, None, None, true);      assert_ok!((), admin.write_config(config)); -    configure_totp(&admin, 1); -    let user = admin.device().authenticate_user(USER_PASSWORD).unwrap(); -    check_totp_codes(&user, 1, TotpTimestampSize::U32); +    configure_totp(&mut admin, 1); +    let mut user = unwrap_ok!(admin.device().authenticate_user(DEFAULT_USER_PIN)); +    check_totp_codes(&mut user, 1, TotpTimestampSize::U32);      assert_cmd_err!(CommandError::NotAuthorized, user.device().get_totp_code(1));  } @@ -230,20 +222,20 @@ fn totp_pin(device: DeviceWrapper) {  #[test_device]  // See comment for totp_no_pin_64.  fn totp_pin_64(device: Pro) { -    let admin = make_admin_test_device(device); +    let mut admin = make_admin_test_device(device);      let config = Config::new(None, None, None, true);      assert_ok!((), admin.write_config(config)); -    configure_totp(&admin, 1); -    let user = admin.device().authenticate_user(USER_PASSWORD).unwrap(); -    check_totp_codes(&user, 1, TotpTimestampSize::U64); +    configure_totp(&mut admin, 1); +    let mut user = unwrap_ok!(admin.device().authenticate_user(DEFAULT_USER_PIN)); +    check_totp_codes(&mut user, 1, TotpTimestampSize::U64);      assert_cmd_err!(CommandError::NotAuthorized, user.device().get_totp_code(1));  }  #[test_device]  fn totp_slot_name(device: DeviceWrapper) { -    let admin = make_admin_test_device(device); +    let mut admin = make_admin_test_device(device);      let slot_data = OtpSlotData::new(1, "test-totp", TOTP_SECRET, OtpMode::EightDigits);      assert_ok!((), admin.write_totp_slot(slot_data, 0)); @@ -256,7 +248,7 @@ fn totp_slot_name(device: DeviceWrapper) {  #[test_device]  fn totp_error(device: DeviceWrapper) { -    let admin = make_admin_test_device(device); +    let mut admin = make_admin_test_device(device);      let slot_data = OtpSlotData::new(1, "", TOTP_SECRET, OtpMode::SixDigits);      assert_cmd_err!(CommandError::NoName, admin.write_totp_slot(slot_data, 0));      let slot_data = OtpSlotData::new(20, "test", TOTP_SECRET, OtpMode::SixDigits); @@ -275,7 +267,7 @@ fn totp_error(device: DeviceWrapper) {  #[test_device]  fn totp_erase(device: DeviceWrapper) { -    let admin = make_admin_test_device(device); +    let mut admin = make_admin_test_device(device);      let config = Config::new(None, None, None, false);      assert_ok!((), admin.write_config(config));      let slot_data = OtpSlotData::new(1, "test1", TOTP_SECRET, OtpMode::SixDigits); @@ -291,5 +283,5 @@ fn totp_erase(device: DeviceWrapper) {      let result = device.get_totp_code(1);      assert_cmd_err!(CommandError::SlotNotProgrammed, result); -    assert_eq!("test2", device.get_totp_slot_name(2).unwrap()); +    assert_ok!("test2".to_string(), device.get_totp_slot_name(2));  } diff --git a/nitrokey/tests/pws.rs b/nitrokey/tests/pws.rs index df99e1c..b0e5abe 100644 --- a/nitrokey/tests/pws.rs +++ b/nitrokey/tests/pws.rs @@ -7,13 +7,12 @@ use std::ffi::CStr;  use libc::{c_int, c_void, free};  use nitrokey::{ -    CommandError, Device, Error, GetPasswordSafe, LibraryError, PasswordSafe, SLOT_COUNT, +    CommandError, Device, Error, GetPasswordSafe, LibraryError, PasswordSafe, DEFAULT_ADMIN_PIN, +    DEFAULT_USER_PIN, SLOT_COUNT,  };  use nitrokey_sys;  use nitrokey_test::test as test_device; -use crate::util::{ADMIN_PASSWORD, USER_PASSWORD}; -  fn get_slot_name_direct(slot: u8) -> Result<String, Error> {      let ptr = unsafe { nitrokey_sys::NK_get_password_safe_slot_name(slot) };      if ptr.is_null() { @@ -33,33 +32,35 @@ fn get_slot_name_direct(slot: u8) -> Result<String, Error> {      }  } -fn get_pws<T>(device: &T) -> PasswordSafe +fn get_pws<T>(device: &mut T) -> PasswordSafe  where      T: Device,  { -    device.get_password_safe(USER_PASSWORD).unwrap() +    unwrap_ok!(device.get_password_safe(DEFAULT_USER_PIN))  }  #[test_device]  fn enable(device: DeviceWrapper) { +    let mut device = device;      assert_cmd_err!(          CommandError::WrongPassword, -        device.get_password_safe(&(USER_PASSWORD.to_owned() + "123")) +        device.get_password_safe(&(DEFAULT_USER_PIN.to_owned() + "123"))      ); -    assert!(device.get_password_safe(USER_PASSWORD).is_ok()); +    assert_any_ok!(device.get_password_safe(DEFAULT_USER_PIN));      assert_cmd_err!(          CommandError::WrongPassword, -        device.get_password_safe(ADMIN_PASSWORD) +        device.get_password_safe(DEFAULT_ADMIN_PIN)      ); -    assert!(device.get_password_safe(USER_PASSWORD).is_ok()); +    assert_any_ok!(device.get_password_safe(DEFAULT_USER_PIN));  }  #[test_device]  fn drop(device: DeviceWrapper) { +    let mut device = device;      { -        let pws = get_pws(&device); +        let mut pws = get_pws(&mut device);          assert_ok!((), pws.write_slot(1, "name", "login", "password")); -        assert_eq!("name", pws.get_slot_name(1).unwrap()); +        assert_ok!("name".to_string(), pws.get_slot_name(1));          let result = get_slot_name_direct(1);          assert_ok!(String::from("name"), result);      } @@ -72,15 +73,16 @@ fn drop(device: DeviceWrapper) {  #[test_device]  fn get_status(device: DeviceWrapper) { -    let pws = get_pws(&device); +    let mut device = device; +    let mut pws = get_pws(&mut device);      for i in 0..SLOT_COUNT {          assert_ok!((), pws.erase_slot(i));      } -    let status = pws.get_slot_status().unwrap(); +    let status = unwrap_ok!(pws.get_slot_status());      assert_eq!(status, [false; SLOT_COUNT as usize]);      assert_ok!((), pws.write_slot(1, "name", "login", "password")); -    let status = pws.get_slot_status().unwrap(); +    let status = unwrap_ok!(pws.get_slot_status());      for i in 0..SLOT_COUNT {          assert_eq!(i == 1, status[i as usize]);      } @@ -88,17 +90,17 @@ fn get_status(device: DeviceWrapper) {      for i in 0..SLOT_COUNT {          assert_ok!((), pws.write_slot(i, "name", "login", "password"));      } -    let status = pws.get_slot_status().unwrap(); -    assert_eq!(status, [true; SLOT_COUNT as usize]); +    assert_ok!([true; SLOT_COUNT as usize], pws.get_slot_status());  }  #[test_device]  fn get_data(device: DeviceWrapper) { -    let pws = get_pws(&device); +    let mut device = device; +    let mut pws = get_pws(&mut device);      assert_ok!((), pws.write_slot(1, "name", "login", "password")); -    assert_eq!("name", pws.get_slot_name(1).unwrap()); -    assert_eq!("login", pws.get_slot_login(1).unwrap()); -    assert_eq!("password", pws.get_slot_password(1).unwrap()); +    assert_ok!("name".to_string(), pws.get_slot_name(1)); +    assert_ok!("login".to_string(), pws.get_slot_login(1)); +    assert_ok!("password".to_string(), pws.get_slot_password(1));      assert_ok!((), pws.erase_slot(1));      assert_cmd_err!(CommandError::SlotNotProgrammed, pws.get_slot_name(1)); @@ -109,9 +111,9 @@ fn get_data(device: DeviceWrapper) {      let login = "pär@test.com";      let password = "'i3lJc[09?I:,[u7dWz9";      assert_ok!((), pws.write_slot(1, name, login, password)); -    assert_eq!(name, pws.get_slot_name(1).unwrap()); -    assert_eq!(login, pws.get_slot_login(1).unwrap()); -    assert_eq!(password, pws.get_slot_password(1).unwrap()); +    assert_ok!(name.to_string(), pws.get_slot_name(1)); +    assert_ok!(login.to_string(), pws.get_slot_login(1)); +    assert_ok!(password.to_string(), pws.get_slot_password(1));      assert_lib_err!(LibraryError::InvalidSlot, pws.get_slot_name(SLOT_COUNT));      assert_lib_err!(LibraryError::InvalidSlot, pws.get_slot_login(SLOT_COUNT)); @@ -120,7 +122,8 @@ fn get_data(device: DeviceWrapper) {  #[test_device]  fn write(device: DeviceWrapper) { -    let pws = get_pws(&device); +    let mut device = device; +    let mut pws = get_pws(&mut device);      assert_lib_err!(          LibraryError::InvalidSlot, @@ -145,7 +148,8 @@ fn write(device: DeviceWrapper) {  #[test_device]  fn erase(device: DeviceWrapper) { -    let pws = get_pws(&device); +    let mut device = device; +    let mut pws = get_pws(&mut device);      assert_lib_err!(LibraryError::InvalidSlot, pws.erase_slot(SLOT_COUNT));      assert_ok!((), pws.write_slot(0, "name", "login", "password")); diff --git a/nitrokey/tests/util/mod.rs b/nitrokey/tests/util/mod.rs index 49ec13e..f2b20ec 100644 --- a/nitrokey/tests/util/mod.rs +++ b/nitrokey/tests/util/mod.rs @@ -1,8 +1,35 @@  // Copyright (C) 2018-2019 Robin Krahl <robin.krahl@ireas.org>  // SPDX-License-Identifier: MIT -pub static ADMIN_PASSWORD: &str = "12345678"; -pub static USER_PASSWORD: &str = "123456"; +#[macro_export] +macro_rules! unwrap_ok { +    ($val:expr) => {{ +        match $val { +            Ok(val) => val, +            Err(err) => panic!( +                r#"assertion failed: `(left == right)` +  left: `Ok(_)`, + right: `Err({:?})`"#, +                err +            ), +        } +    }}; +} + +#[macro_export] +macro_rules! assert_any_ok { +    ($val:expr) => {{ +        match &$val { +            Ok(_) => {} +            Err(err) => panic!( +                r#"assertion failed: `(left == right)` +  left: `Ok(_)`, + right: `Err({:?})`"#, +                err +            ), +        } +    }}; +}  #[macro_export]  macro_rules! assert_ok {  | 
