diff options
-rw-r--r-- | CHANGELOG.md | 4 | ||||
-rw-r--r-- | src/auth.rs | 183 | ||||
-rw-r--r-- | src/device.rs | 42 | ||||
-rw-r--r-- | src/lib.rs | 4 | ||||
-rw-r--r-- | src/otp.rs | 16 | ||||
-rw-r--r-- | tests/device.rs | 152 | ||||
-rw-r--r-- | tests/otp.rs | 62 | ||||
-rw-r--r-- | tests/util/mod.rs | 12 |
8 files changed, 277 insertions, 198 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 9227510..e98e857 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,10 +38,6 @@ SPDX-License-Identifier: MIT - 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. -- 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. diff --git a/src/auth.rs b/src/auth.rs index 573fed3..f9f50fa 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -42,10 +42,16 @@ pub trait Authenticate { /// fn perform_other_task(device: &DeviceWrapper) {} /// /// # fn try_main() -> Result<(), Error> { - /// let mut device = nitrokey::connect()?; - /// match device.authenticate_user("123456") { - /// Ok(user) => perform_user_task(&user), - /// Err(err) => eprintln!("Could not authenticate as user: {}", err), + /// let device = nitrokey::connect()?; + /// let device = match device.authenticate_user("123456") { + /// Ok(user) => { + /// perform_user_task(&user); + /// user.device() + /// }, + /// Err((device, err)) => { + /// eprintln!("Could not authenticate as user: {}", err); + /// device + /// }, /// }; /// perform_other_task(&device); /// # Ok(()) @@ -55,9 +61,9 @@ pub trait Authenticate { /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString /// [`RngError`]: enum.CommandError.html#variant.RngError /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword - fn authenticate_user(&mut self, password: &str) -> Result<User<'_, Self>, Error> + fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, Error)> where - Self: Device + std::marker::Sized; + Self: Device + Sized; /// Performs admin authentication. This method consumes the device. If successful, an /// authenticated device is returned. Otherwise, the current unauthenticated device and the @@ -82,10 +88,16 @@ pub trait Authenticate { /// fn perform_other_task(device: &DeviceWrapper) {} /// /// # fn try_main() -> Result<(), Error> { - /// let mut device = nitrokey::connect()?; - /// match device.authenticate_admin("123456") { - /// Ok(admin) => perform_admin_task(&admin), - /// Err(err) => eprintln!("Could not authenticate as admin: {}", err), + /// let device = nitrokey::connect()?; + /// let device = match device.authenticate_admin("123456") { + /// Ok(admin) => { + /// perform_admin_task(&admin); + /// admin.device() + /// }, + /// Err((device, err)) => { + /// eprintln!("Could not authenticate as admin: {}", err); + /// device + /// }, /// }; /// perform_other_task(&device); /// # Ok(()) @@ -95,13 +107,13 @@ pub trait Authenticate { /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString /// [`RngError`]: enum.CommandError.html#variant.RngError /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword - fn authenticate_admin(&mut self, password: &str) -> Result<Admin<'_, Self>, Error> + fn authenticate_admin(self, password: &str) -> Result<Admin<Self>, (Self, Error)> where - Self: Device + std::marker::Sized; + Self: Device + Sized; } -trait AuthenticatedDevice<'a, T> { - fn new(device: &'a mut T, temp_password: Vec<u8>) -> Self; +trait AuthenticatedDevice<T> { + fn new(device: T, temp_password: Vec<u8>) -> Self; fn temp_password_ptr(&self) -> *const c_char; } @@ -116,8 +128,8 @@ trait AuthenticatedDevice<'a, T> { /// [`authenticate_admin`]: trait.Authenticate.html#method.authenticate_admin /// [`device`]: #method.device #[derive(Debug)] -pub struct User<'a, T: Device> { - device: &'a mut T, +pub struct User<T: Device> { + device: T, temp_password: Vec<u8>, } @@ -131,42 +143,89 @@ pub struct User<'a, T: Device> { /// [`authenticate_admin`]: trait.Authenticate.html#method.authenticate_admin /// [`device`]: #method.device #[derive(Debug)] -pub struct Admin<'a, T: Device> { - device: &'a mut T, +pub struct Admin<T: Device> { + device: T, temp_password: Vec<u8>, } -fn authenticate<'a, D, A, T>(device: &'a mut D, password: &str, callback: T) -> Result<A, Error> +fn authenticate<D, A, T>(device: D, password: &str, callback: T) -> Result<A, (D, Error)> where D: Device, - A: AuthenticatedDevice<'a, D>, + A: AuthenticatedDevice<D>, T: Fn(*const c_char, *const c_char) -> c_int, { - let temp_password = generate_password(TEMPORARY_PASSWORD_LENGTH)?; - let password = get_cstring(password)?; + let temp_password = match generate_password(TEMPORARY_PASSWORD_LENGTH) { + Ok(temp_password) => temp_password, + Err(err) => return Err((device, err)), + }; + let password = match get_cstring(password) { + Ok(password) => password, + Err(err) => return Err((device, err)), + }; let password_ptr = password.as_ptr(); let temp_password_ptr = temp_password.as_ptr() as *const c_char; match callback(password_ptr, temp_password_ptr) { 0 => Ok(A::new(device, temp_password)), - rv => Err(Error::from(rv)), + rv => Err((device, Error::from(rv))), } } -impl<'a, T: Device> ops::Deref for User<'a, T> { +fn authenticate_user_wrapper<T, C>( + device: T, + constructor: C, + password: &str, +) -> Result<User<DeviceWrapper>, (DeviceWrapper, Error)> +where + T: Device, + C: Fn(T) -> DeviceWrapper, +{ + let result = device.authenticate_user(password); + match result { + Ok(user) => Ok(User::new(constructor(user.device), user.temp_password)), + Err((device, err)) => Err((constructor(device), err)), + } +} + +fn authenticate_admin_wrapper<T, C>( + device: T, + constructor: C, + password: &str, +) -> Result<Admin<DeviceWrapper>, (DeviceWrapper, Error)> +where + T: Device, + C: Fn(T) -> DeviceWrapper, +{ + let result = device.authenticate_admin(password); + match result { + Ok(user) => Ok(Admin::new(constructor(user.device), user.temp_password)), + Err((device, err)) => Err((constructor(device), err)), + } +} + +impl<T: Device> User<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 + /// Nitrokey. + pub fn device(self) -> T { + self.device + } +} + +impl<T: Device> ops::Deref for User<T> { type Target = T; fn deref(&self) -> &Self::Target { - self.device + &self.device } } -impl<'a, T: Device> ops::DerefMut for User<'a, T> { +impl<T: Device> ops::DerefMut for User<T> { fn deref_mut(&mut self) -> &mut T { - self.device + &mut self.device } } -impl<'a, T: Device> GenerateOtp for User<'a, T> { +impl<T: Device> GenerateOtp for User<T> { 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()) @@ -180,8 +239,8 @@ impl<'a, T: Device> GenerateOtp for User<'a, T> { } } -impl<'a, T: Device> AuthenticatedDevice<'a, T> for User<'a, T> { - fn new(device: &'a mut T, temp_password: Vec<u8>) -> Self { +impl<T: Device> AuthenticatedDevice<T> for User<T> { + fn new(device: T, temp_password: Vec<u8>) -> Self { User { device, temp_password, @@ -193,21 +252,28 @@ impl<'a, T: Device> AuthenticatedDevice<'a, T> for User<'a, T> { } } -impl<'a, T: Device> ops::Deref for Admin<'a, T> { +impl<T: Device> ops::Deref for Admin<T> { type Target = T; fn deref(&self) -> &Self::Target { - self.device + &self.device } } -impl<'a, T: Device> ops::DerefMut for Admin<'a, T> { +impl<T: Device> ops::DerefMut for Admin<T> { fn deref_mut(&mut self) -> &mut T { - self.device + &mut self.device } } -impl<'a, T: Device> Admin<'a, T> { +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 + /// Nitrokey. + pub fn device(self) -> T { + self.device + } + /// Writes the given configuration to the Nitrokey device. /// /// # Errors @@ -221,11 +287,14 @@ impl<'a, T: Device> Admin<'a, T> { /// # use nitrokey::Error; /// /// # fn try_main() -> Result<(), Error> { - /// let mut device = nitrokey::connect()?; + /// let device = nitrokey::connect()?; /// let config = Config::new(None, None, None, false); /// match device.authenticate_admin("12345678") { - /// Ok(mut admin) => admin.write_config(config)?, - /// Err(err) => eprintln!("Could not authenticate as admin: {}", err), + /// Ok(mut admin) => { + /// admin.write_config(config); + /// () + /// }, + /// Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err), /// }; /// # Ok(()) /// # } @@ -247,7 +316,7 @@ impl<'a, T: Device> Admin<'a, T> { } } -impl<'a, T: Device> ConfigureOtp for Admin<'a, T> { +impl<T: Device> ConfigureOtp for Admin<T> { fn write_hotp_slot(&mut self, data: OtpSlotData, counter: u64) -> Result<(), Error> { let raw_data = RawOtpSlotData::new(data)?; get_command_result(unsafe { @@ -295,8 +364,8 @@ impl<'a, T: Device> ConfigureOtp for Admin<'a, T> { } } -impl<'a, T: Device> AuthenticatedDevice<'a, T> for Admin<'a, T> { - fn new(device: &'a mut T, temp_password: Vec<u8>) -> Self { +impl<T: Device> AuthenticatedDevice<T> for Admin<T> { + fn new(device: T, temp_password: Vec<u8>) -> Self { Admin { device, temp_password, @@ -309,27 +378,35 @@ impl<'a, T: Device> AuthenticatedDevice<'a, T> for Admin<'a, T> { } impl Authenticate for DeviceWrapper { - fn authenticate_user(&mut self, password: &str) -> Result<User<'_, Self>, Error> { - authenticate(self, password, |password_ptr, temp_password_ptr| unsafe { - nitrokey_sys::NK_user_authenticate(password_ptr, temp_password_ptr) - }) + fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, Error)> { + match self { + DeviceWrapper::Storage(storage) => { + authenticate_user_wrapper(storage, DeviceWrapper::Storage, password) + } + DeviceWrapper::Pro(pro) => authenticate_user_wrapper(pro, DeviceWrapper::Pro, password), + } } - fn authenticate_admin(&mut self, password: &str) -> Result<Admin<'_, Self>, Error> { - authenticate(self, password, |password_ptr, temp_password_ptr| unsafe { - nitrokey_sys::NK_user_authenticate(password_ptr, temp_password_ptr) - }) + fn authenticate_admin(self, password: &str) -> Result<Admin<Self>, (Self, Error)> { + match self { + DeviceWrapper::Storage(storage) => { + authenticate_admin_wrapper(storage, DeviceWrapper::Storage, password) + } + DeviceWrapper::Pro(pro) => { + authenticate_admin_wrapper(pro, DeviceWrapper::Pro, password) + } + } } } impl Authenticate for Pro { - fn authenticate_user(&mut self, password: &str) -> Result<User<'_, Self>, Error> { + fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, Error)> { authenticate(self, password, |password_ptr, temp_password_ptr| unsafe { nitrokey_sys::NK_user_authenticate(password_ptr, temp_password_ptr) }) } - fn authenticate_admin(&mut self, password: &str) -> Result<Admin<'_, Self>, Error> { + fn authenticate_admin(self, password: &str) -> Result<Admin<Self>, (Self, Error)> { authenticate(self, password, |password_ptr, temp_password_ptr| unsafe { nitrokey_sys::NK_first_authenticate(password_ptr, temp_password_ptr) }) @@ -337,13 +414,13 @@ impl Authenticate for Pro { } impl Authenticate for Storage { - fn authenticate_user(&mut self, password: &str) -> Result<User<'_, Self>, Error> { + fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, Error)> { authenticate(self, password, |password_ptr, temp_password_ptr| unsafe { nitrokey_sys::NK_user_authenticate(password_ptr, temp_password_ptr) }) } - fn authenticate_admin(&mut self, password: &str) -> Result<Admin<'_, Self>, Error> { + fn authenticate_admin(self, password: &str) -> Result<Admin<Self>, (Self, Error)> { authenticate(self, password, |password_ptr, temp_password_ptr| unsafe { nitrokey_sys::NK_first_authenticate(password_ptr, temp_password_ptr) }) diff --git a/src/device.rs b/src/device.rs index a0df30e..f6492cd 100644 --- a/src/device.rs +++ b/src/device.rs @@ -71,10 +71,16 @@ impl fmt::Display for VolumeMode { /// fn perform_other_task(device: &DeviceWrapper) {} /// /// # fn try_main() -> Result<(), Error> { -/// let mut device = nitrokey::connect()?; -/// match device.authenticate_user("123456") { -/// Ok(user) => perform_user_task(&user), -/// Err(err) => eprintln!("Could not authenticate as user: {}", err), +/// let device = nitrokey::connect()?; +/// let device = match device.authenticate_user("123456") { +/// Ok(user) => { +/// perform_user_task(&user); +/// user.device() +/// }, +/// Err((device, err)) => { +/// eprintln!("Could not authenticate as user: {}", err); +/// device +/// }, /// }; /// perform_other_task(&device); /// # Ok(()) @@ -129,10 +135,16 @@ pub enum DeviceWrapper { /// fn perform_other_task(device: &Pro) {} /// /// # fn try_main() -> Result<(), Error> { -/// let mut device = nitrokey::Pro::connect()?; -/// match device.authenticate_user("123456") { -/// Ok(user) => perform_user_task(&user), -/// Err(err) => eprintln!("Could not authenticate as user: {}", err), +/// let device = nitrokey::Pro::connect()?; +/// let device = match device.authenticate_user("123456") { +/// Ok(user) => { +/// perform_user_task(&user); +/// user.device() +/// }, +/// Err((device, err)) => { +/// eprintln!("Could not authenticate as user: {}", err); +/// device +/// }, /// }; /// perform_other_task(&device); /// # Ok(()) @@ -169,10 +181,16 @@ pub struct Pro { /// fn perform_other_task(device: &Storage) {} /// /// # fn try_main() -> Result<(), Error> { -/// let mut device = nitrokey::Storage::connect()?; -/// match device.authenticate_user("123456") { -/// Ok(user) => perform_user_task(&user), -/// Err(err) => eprintln!("Could not authenticate as user: {}", err), +/// let device = nitrokey::Storage::connect()?; +/// let device = match device.authenticate_user("123456") { +/// Ok(user) => { +/// perform_user_task(&user); +/// user.device() +/// }, +/// Err((device, err)) => { +/// eprintln!("Could not authenticate as user: {}", err); +/// device +/// }, /// }; /// perform_other_task(&device); /// # Ok(()) @@ -44,7 +44,7 @@ //! # use nitrokey::Error; //! //! # fn try_main() -> Result<(), Error> { -//! let mut device = nitrokey::connect()?; +//! let device = nitrokey::connect()?; //! let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::SixDigits); //! match device.authenticate_admin("12345678") { //! Ok(mut admin) => { @@ -53,7 +53,7 @@ //! Err(err) => eprintln!("Could not write slot: {}", err), //! } //! }, -//! Err(err) => eprintln!("Could not authenticate as admin: {}", err), +//! Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err), //! } //! # Ok(()) //! # } @@ -35,7 +35,7 @@ pub trait ConfigureOtp { /// # use nitrokey::Error; /// /// # fn try_main() -> Result<(), Error> { - /// let mut device = nitrokey::connect()?; + /// let device = nitrokey::connect()?; /// let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::SixDigits); /// match device.authenticate_admin("12345678") { /// Ok(mut admin) => { @@ -44,7 +44,7 @@ pub trait ConfigureOtp { /// Err(err) => eprintln!("Could not write slot: {}", err), /// } /// }, - /// Err(err) => eprintln!("Could not authenticate as admin: {}", err), + /// Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err), /// } /// # Ok(()) /// # } @@ -71,7 +71,7 @@ pub trait ConfigureOtp { /// # use nitrokey::Error; /// /// # fn try_main() -> Result<(), Error> { - /// let mut device = nitrokey::connect()?; + /// let device = nitrokey::connect()?; /// let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::EightDigits); /// match device.authenticate_admin("12345678") { /// Ok(mut admin) => { @@ -80,7 +80,7 @@ pub trait ConfigureOtp { /// Err(err) => eprintln!("Could not write slot: {}", err), /// } /// }, - /// Err(err) => eprintln!("Could not authenticate as admin: {}", err), + /// Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err), /// } /// # Ok(()) /// # } @@ -104,7 +104,7 @@ pub trait ConfigureOtp { /// # use nitrokey::Error; /// /// # fn try_main() -> Result<(), Error> { - /// let mut device = nitrokey::connect()?; + /// let device = nitrokey::connect()?; /// match device.authenticate_admin("12345678") { /// Ok(mut admin) => { /// match admin.erase_hotp_slot(1) { @@ -112,7 +112,7 @@ pub trait ConfigureOtp { /// Err(err) => eprintln!("Could not erase slot: {}", err), /// } /// }, - /// Err(err) => eprintln!("Could not authenticate as admin: {}", err), + /// Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err), /// } /// # Ok(()) /// # } @@ -134,7 +134,7 @@ pub trait ConfigureOtp { /// # use nitrokey::Error; /// /// # fn try_main() -> Result<(), Error> { - /// let mut device = nitrokey::connect()?; + /// let device = nitrokey::connect()?; /// match device.authenticate_admin("12345678") { /// Ok(mut admin) => { /// match admin.erase_totp_slot(1) { @@ -142,7 +142,7 @@ pub trait ConfigureOtp { /// Err(err) => eprintln!("Could not erase slot: {}", err), /// } /// }, - /// Err(err) => eprintln!("Could not authenticate as admin: {}", err), + /// Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err), /// } /// # Ok(()) /// # } diff --git a/tests/device.rs b/tests/device.rs index ecc3cfa..6a3683b 100644 --- a/tests/device.rs +++ b/tests/device.rs @@ -97,34 +97,41 @@ fn get_firmware_version(device: Pro) { assert!(version.minor > 0); } -fn admin_retry<T: Authenticate + Device>(device: &mut T, suffix: &str, count: u8) { - assert_any_ok!(device.authenticate_admin(&(DEFAULT_ADMIN_PIN.to_owned() + suffix))); +fn admin_retry<T: Authenticate + Device>(device: T, suffix: &str, count: u8) -> T { + let result = device.authenticate_admin(&(DEFAULT_ADMIN_PIN.to_owned() + suffix)); + let device = match result { + Ok(admin) => admin.device(), + Err((device, _)) => device, + }; assert_ok!(count, device.get_admin_retry_count()); + return device; } -fn user_retry<T: Authenticate + Device>(device: &mut T, suffix: &str, count: u8) { - assert_any_ok!(device.authenticate_user(&(DEFAULT_USER_PIN.to_owned() + suffix))); +fn user_retry<T: Authenticate + Device>(device: T, suffix: &str, count: u8) -> T { + let result = device.authenticate_user(&(DEFAULT_USER_PIN.to_owned() + suffix)); + let device = match result { + Ok(admin) => admin.device(), + Err((device, _)) => device, + }; assert_ok!(count, device.get_user_retry_count()); + return device; } #[test_device] fn get_retry_count(device: DeviceWrapper) { - let mut device = device; - - admin_retry(&mut device, "", 3); - admin_retry(&mut device, "123", 2); - admin_retry(&mut device, "456", 1); - admin_retry(&mut device, "", 3); - - user_retry(&mut device, "", 3); - user_retry(&mut device, "123", 2); - user_retry(&mut device, "456", 1); - user_retry(&mut device, "", 3); + let device = admin_retry(device, "", 3); + let device = admin_retry(device, "123", 2); + let device = admin_retry(device, "456", 1); + let device = admin_retry(device, "", 3); + + let device = user_retry(device, "", 3); + let device = user_retry(device, "123", 2); + let device = user_retry(device, "456", 1); + user_retry(device, "", 3); } #[test_device] fn config(device: DeviceWrapper) { - let mut device = device; let mut admin = unwrap_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN)); let config = Config::new(None, None, None, true); @@ -145,24 +152,19 @@ fn config(device: DeviceWrapper) { #[test_device] fn change_user_pin(device: DeviceWrapper) { - let mut device = device; - assert_any_ok!(device.authenticate_user(DEFAULT_USER_PIN)); - assert_cmd_err!( - CommandError::WrongPassword, - device.authenticate_user(USER_NEW_PASSWORD) - ); + 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(DEFAULT_USER_PIN, USER_NEW_PASSWORD) - ); + let mut device = device; + assert_ok!((), device.change_user_pin(DEFAULT_USER_PIN, USER_NEW_PASSWORD)); - assert_cmd_err!( - CommandError::WrongPassword, - device.authenticate_user(DEFAULT_USER_PIN) - ); - assert_any_ok!(device.authenticate_user(USER_NEW_PASSWORD)); + let device = device.authenticate_user(DEFAULT_USER_PIN).unwrap_err().0; + let device = device + .authenticate_user(USER_NEW_PASSWORD) + .unwrap() + .device(); + let mut device = device; let result = device.change_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN); assert_cmd_err!(CommandError::WrongPassword, result); @@ -171,32 +173,25 @@ fn change_user_pin(device: DeviceWrapper) { device.change_user_pin(USER_NEW_PASSWORD, DEFAULT_USER_PIN) ); - assert_any_ok!(device.authenticate_user(DEFAULT_USER_PIN)); - assert_cmd_err!( - CommandError::WrongPassword, - device.authenticate_user(USER_NEW_PASSWORD) - ); + 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 mut device = device; - assert_any_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN)); - assert_cmd_err!( - CommandError::WrongPassword, - device.authenticate_admin(ADMIN_NEW_PASSWORD) - ); + 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(DEFAULT_ADMIN_PIN, ADMIN_NEW_PASSWORD) ); - assert_cmd_err!( - CommandError::WrongPassword, - device.authenticate_admin(DEFAULT_ADMIN_PIN) - ); - assert_any_ok!(device.authenticate_admin(ADMIN_NEW_PASSWORD)); + 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, @@ -208,28 +203,29 @@ fn change_admin_pin(device: DeviceWrapper) { device.change_admin_pin(ADMIN_NEW_PASSWORD, DEFAULT_ADMIN_PIN) ); - assert_any_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN)); - assert_cmd_err!( - CommandError::WrongPassword, - device.authenticate_admin(ADMIN_NEW_PASSWORD) - ); + let device = device.authenticate_admin(DEFAULT_ADMIN_PIN).unwrap().device(); + device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err(); } -fn require_failed_user_login<D: Authenticate + Device>(device: &mut D, password: &str) { - assert_cmd_err!( - CommandError::WrongPassword, - device.authenticate_user(password) - ); +fn require_failed_user_login<D>(device: D, password: &str, error: CommandError) -> D +where + D: Device + Authenticate, + nitrokey::User<D>: std::fmt::Debug, +{ + let result = device.authenticate_user(password); + assert!(result.is_err()); + let err = result.unwrap_err(); + match err.1 { + Error::CommandError(err) => assert_eq!(error, err), + _ => assert!(false), + }; + err.0 } #[test_device] fn unlock_user_pin(device: DeviceWrapper) { - let mut device = device; - assert_any_ok!(device.authenticate_user(DEFAULT_USER_PIN)); - assert_ok!( - (), - device.unlock_user_pin(DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN) - ); + 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(DEFAULT_USER_PIN, DEFAULT_USER_PIN) @@ -237,27 +233,24 @@ fn unlock_user_pin(device: DeviceWrapper) { // block user PIN let wrong_password = DEFAULT_USER_PIN.to_owned() + "foo"; - require_failed_user_login(&mut device, &wrong_password); - require_failed_user_login(&mut device, &wrong_password); - require_failed_user_login(&mut device, &wrong_password); - require_failed_user_login(&mut device, DEFAULT_USER_PIN); + let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); + let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); + let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); + let mut device = require_failed_user_login(device, DEFAULT_USER_PIN, CommandError::WrongPassword); // unblock with current PIN assert_cmd_err!( CommandError::WrongPassword, device.unlock_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN) ); - assert_ok!( - (), - device.unlock_user_pin(DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN) - ); - assert_any_ok!(device.authenticate_user(DEFAULT_USER_PIN)); + assert_ok!((), device.unlock_user_pin(DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN)); + let device = device.authenticate_user(DEFAULT_USER_PIN).unwrap().device(); // block user PIN - require_failed_user_login(&mut device, &wrong_password); - require_failed_user_login(&mut device, &wrong_password); - require_failed_user_login(&mut device, &wrong_password); - require_failed_user_login(&mut device, DEFAULT_USER_PIN); + let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); + let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); + let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); + let mut device = require_failed_user_login(device, DEFAULT_USER_PIN, CommandError::WrongPassword); // unblock with new PIN assert_cmd_err!( @@ -286,11 +279,11 @@ fn assert_utf8_err_or_ne(left: &str, right: Result<String, Error>) { #[test_device] fn factory_reset(device: DeviceWrapper) { - let mut device = device; 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 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); @@ -314,11 +307,12 @@ fn factory_reset(device: DeviceWrapper) { ); assert_ok!((), device.factory_reset(ADMIN_NEW_PASSWORD)); - assert_any_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN)); + let device = device.authenticate_admin(DEFAULT_ADMIN_PIN).unwrap().device(); let user = unwrap_ok!(device.authenticate_user(DEFAULT_USER_PIN)); assert_cmd_err!(CommandError::SlotNotProgrammed, user.get_totp_slot_name(1)); + 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)); @@ -341,7 +335,7 @@ fn build_aes_key(device: DeviceWrapper) { ); assert_ok!((), device.build_aes_key(DEFAULT_ADMIN_PIN)); - assert_any_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN)); + let mut device = device.authenticate_admin(DEFAULT_ADMIN_PIN).unwrap().device(); let pws = unwrap_ok!(device.get_password_safe(DEFAULT_USER_PIN)); assert_utf8_err_or_ne("test", pws.get_slot_name(0)); diff --git a/tests/otp.rs b/tests/otp.rs index d55d54a..c0bbecf 100644 --- a/tests/otp.rs +++ b/tests/otp.rs @@ -3,6 +3,7 @@ mod util; +use std::fmt::Debug; use std::ops::DerefMut; use nitrokey::{ @@ -35,9 +36,10 @@ enum TotpTimestampSize { U64, } -fn make_admin_test_device<'a, T>(device: &'a mut T) -> Admin<'a, T> +fn make_admin_test_device<T>(device: T) -> Admin<T> where T: Device, + (T, nitrokey::Error): Debug, { unwrap_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN)) } @@ -66,8 +68,7 @@ fn set_time(device: DeviceWrapper) { #[test_device] fn hotp_no_pin(device: DeviceWrapper) { - let mut device = device; - let mut admin = make_admin_test_device(&mut device); + let mut admin = make_admin_test_device(device); let config = Config::new(None, None, None, false); assert_ok!((), admin.write_config(config)); @@ -78,38 +79,36 @@ fn hotp_no_pin(device: DeviceWrapper) { check_hotp_codes(admin.deref_mut(), 5); configure_hotp(&mut admin, 0); - check_hotp_codes(&mut device, 0); + check_hotp_codes(&mut admin.device(), 0); } #[test_device] fn hotp_pin(device: DeviceWrapper) { - let mut device = device; - let mut admin = make_admin_test_device(&mut 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(&mut admin, 0); - let mut user = unwrap_ok!(device.authenticate_user(DEFAULT_USER_PIN)); + let mut user = unwrap_ok!(admin.device().authenticate_user(DEFAULT_USER_PIN)); check_hotp_codes(&mut user, 0); - assert_cmd_err!(CommandError::NotAuthorized, user.get_hotp_code(1)); + assert_cmd_err!(CommandError::NotAuthorized, user.device().get_hotp_code(1)); } #[test_device] fn hotp_slot_name(device: DeviceWrapper) { - let mut device = device; - let mut admin = make_admin_test_device(&mut 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(); 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 mut device = device; - let mut admin = make_admin_test_device(&mut 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); @@ -128,8 +127,7 @@ fn hotp_error(device: DeviceWrapper) { #[test_device] fn hotp_erase(device: DeviceWrapper) { - let mut device = device; - let mut admin = make_admin_test_device(&mut 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); @@ -139,6 +137,7 @@ fn hotp_erase(device: DeviceWrapper) { assert_ok!((), admin.erase_hotp_slot(1)); + 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); @@ -175,8 +174,7 @@ fn check_totp_codes(device: &mut GenerateOtp, factor: u64, timestamp_size: TotpT #[test_device] fn totp_no_pin(device: DeviceWrapper) { - let mut device = device; - let mut admin = make_admin_test_device(&mut device); + let mut admin = make_admin_test_device(device); let config = Config::new(None, None, None, false); assert_ok!((), admin.write_config(config)); @@ -187,15 +185,14 @@ fn totp_no_pin(device: DeviceWrapper) { check_totp_codes(admin.deref_mut(), 2, TotpTimestampSize::U32); configure_totp(&mut admin, 1); - check_totp_codes(&mut device, 1, TotpTimestampSize::U32); + 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 mut device = device; - let mut admin = make_admin_test_device(&mut device); + let mut admin = make_admin_test_device(device); let config = Config::new(None, None, None, false); assert_ok!((), admin.write_config(config)); @@ -206,45 +203,43 @@ fn totp_no_pin_64(device: Pro) { check_totp_codes(admin.deref_mut(), 2, TotpTimestampSize::U64); configure_totp(&mut admin, 1); - check_totp_codes(&mut device, 1, TotpTimestampSize::U64); + check_totp_codes(&mut admin.device(), 1, TotpTimestampSize::U64); } #[test_device] fn totp_pin(device: DeviceWrapper) { - let mut device = device; - let mut admin = make_admin_test_device(&mut 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(&mut admin, 1); - let mut user = unwrap_ok!(device.authenticate_user(DEFAULT_USER_PIN)); + 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.get_totp_code(1)); + assert_cmd_err!(CommandError::NotAuthorized, user.device().get_totp_code(1)); } #[test_device] // See comment for totp_no_pin_64. fn totp_pin_64(device: Pro) { - let mut device = device; - let mut admin = make_admin_test_device(&mut 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(&mut admin, 1); - let mut user = unwrap_ok!(admin.authenticate_user(DEFAULT_USER_PIN)); + 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, device.get_totp_code(1)); + assert_cmd_err!(CommandError::NotAuthorized, user.device().get_totp_code(1)); } #[test_device] fn totp_slot_name(device: DeviceWrapper) { - let mut device = device; - let mut admin = make_admin_test_device(&mut 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)); + let device = admin.device(); let result = device.get_totp_slot_name(1); assert_ok!("test-totp", result); let result = device.get_totp_slot_name(16); @@ -253,8 +248,7 @@ fn totp_slot_name(device: DeviceWrapper) { #[test_device] fn totp_error(device: DeviceWrapper) { - let mut device = device; - let mut admin = make_admin_test_device(&mut 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); @@ -273,8 +267,7 @@ fn totp_error(device: DeviceWrapper) { #[test_device] fn totp_erase(device: DeviceWrapper) { - let mut device = device; - let mut admin = make_admin_test_device(&mut 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); @@ -284,6 +277,7 @@ fn totp_erase(device: DeviceWrapper) { assert_ok!((), admin.erase_totp_slot(1)); + let device = admin.device(); let result = device.get_totp_slot_name(1); assert_cmd_err!(CommandError::SlotNotProgrammed, result); let result = device.get_totp_code(1); diff --git a/tests/util/mod.rs b/tests/util/mod.rs index 5bd19d1..f2b20ec 100644 --- a/tests/util/mod.rs +++ b/tests/util/mod.rs @@ -3,7 +3,7 @@ #[macro_export] macro_rules! unwrap_ok { - ($val:expr) => { + ($val:expr) => {{ match $val { Ok(val) => val, Err(err) => panic!( @@ -13,12 +13,12 @@ macro_rules! unwrap_ok { err ), } - }; + }}; } #[macro_export] macro_rules! assert_any_ok { - ($val:expr) => { + ($val:expr) => {{ match &$val { Ok(_) => {} Err(err) => panic!( @@ -28,12 +28,12 @@ macro_rules! assert_any_ok { err ), } - }; + }}; } #[macro_export] macro_rules! assert_ok { - ($left:expr, $right:expr) => { + ($left:expr, $right:expr) => {{ match &$right { Ok(right) => match &$left { left => { @@ -54,7 +54,7 @@ macro_rules! assert_ok { $left, right_err ), } - }; + }}; } #[macro_export] |