From fe2f39826ade5a156945dabb8c8ab725378a15c1 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Sun, 27 Jan 2019 18:42:14 +0000 Subject: Store mutable reference to Manager in Device In the last patches, we ensured that devices can only be obtained using the Manager struct. But we did not ensure that there is only one device at a time. This patch adds a mutable reference to the Manager instance to the Device implementations. The borrow checker makes sure that there is only one mutable reference at a time. In this patch, we have to remove the old connect, Pro::connect and Storage::connect functions as they do no longer compile. (They discard the MutexGuard which invalidates the reference to the Manager.) Therefore the tests do no longer compile. --- src/auth.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/auth.rs') diff --git a/src/auth.rs b/src/auth.rs index f9f50fa..2ed7bfc 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -170,14 +170,14 @@ where } } -fn authenticate_user_wrapper( +fn authenticate_user_wrapper<'a, T, C>( device: T, constructor: C, password: &str, -) -> Result, (DeviceWrapper, Error)> +) -> Result>, (DeviceWrapper<'a>, Error)> where T: Device, - C: Fn(T) -> DeviceWrapper, + C: Fn(T) -> DeviceWrapper<'a>, { let result = device.authenticate_user(password); match result { @@ -186,14 +186,14 @@ where } } -fn authenticate_admin_wrapper( +fn authenticate_admin_wrapper<'a, T, C>( device: T, constructor: C, password: &str, -) -> Result, (DeviceWrapper, Error)> +) -> Result>, (DeviceWrapper<'a>, Error)> where T: Device, - C: Fn(T) -> DeviceWrapper, + C: Fn(T) -> DeviceWrapper<'a>, { let result = device.authenticate_admin(password); match result { @@ -377,7 +377,7 @@ impl AuthenticatedDevice for Admin { } } -impl Authenticate for DeviceWrapper { +impl<'a> Authenticate for DeviceWrapper<'a> { fn authenticate_user(self, password: &str) -> Result, (Self, Error)> { match self { DeviceWrapper::Storage(storage) => { @@ -399,7 +399,7 @@ impl Authenticate for DeviceWrapper { } } -impl Authenticate for Pro { +impl<'a> Authenticate for Pro<'a> { fn authenticate_user(self, password: &str) -> Result, (Self, Error)> { authenticate(self, password, |password_ptr, temp_password_ptr| unsafe { nitrokey_sys::NK_user_authenticate(password_ptr, temp_password_ptr) @@ -413,7 +413,7 @@ impl Authenticate for Pro { } } -impl Authenticate for Storage { +impl<'a> Authenticate for Storage<'a> { fn authenticate_user(self, password: &str) -> Result, (Self, Error)> { authenticate(self, password, |password_ptr, temp_password_ptr| unsafe { nitrokey_sys::NK_user_authenticate(password_ptr, temp_password_ptr) -- cgit v1.2.1 From 12fa62483cf45d868099d5d4020333af492eebde Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 9 Jul 2019 08:09:02 +0000 Subject: Introduce into_manager for Device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To enable applications like nitrokey-test to go back to a manager instance from a Device instance, we add the into_manager function to the Device trait. To do that, we have to keep track of the Manager’s lifetime by adding a lifetime to Device (and then to some other traits that use Device). --- src/auth.rs | 69 +++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 32 deletions(-) (limited to 'src/auth.rs') diff --git a/src/auth.rs b/src/auth.rs index 2ed7bfc..829d083 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,6 +1,7 @@ // Copyright (C) 2018-2019 Robin Krahl // SPDX-License-Identifier: MIT +use std::marker; use std::ops; use std::os::raw::c_char; use std::os::raw::c_int; @@ -18,7 +19,7 @@ static TEMPORARY_PASSWORD_LENGTH: usize = 25; /// Provides methods to authenticate as a user or as an admin using a PIN. The authenticated /// methods will consume the current device instance. On success, they return the authenticated /// device. Otherwise, they return the current unauthenticated device and the error code. -pub trait Authenticate { +pub trait Authenticate<'a> { /// Performs user authentication. This method consumes the device. If successful, an /// authenticated device is returned. Otherwise, the current unauthenticated device and the /// error are returned. @@ -61,9 +62,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(self, password: &str) -> Result, (Self, Error)> + fn authenticate_user(self, password: &str) -> Result, (Self, Error)> where - Self: Device + Sized; + Self: Device<'a> + Sized; /// Performs admin authentication. This method consumes the device. If successful, an /// authenticated device is returned. Otherwise, the current unauthenticated device and the @@ -107,9 +108,9 @@ pub trait Authenticate { /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString /// [`RngError`]: enum.CommandError.html#variant.RngError /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword - fn authenticate_admin(self, password: &str) -> Result, (Self, Error)> + fn authenticate_admin(self, password: &str) -> Result, (Self, Error)> where - Self: Device + Sized; + Self: Device<'a> + Sized; } trait AuthenticatedDevice { @@ -128,9 +129,10 @@ trait AuthenticatedDevice { /// [`authenticate_admin`]: trait.Authenticate.html#method.authenticate_admin /// [`device`]: #method.device #[derive(Debug)] -pub struct User { +pub struct User<'a, T: Device<'a>> { device: T, temp_password: Vec, + marker: marker::PhantomData<&'a T>, } /// A Nitrokey device with admin authentication. @@ -143,14 +145,15 @@ pub struct User { /// [`authenticate_admin`]: trait.Authenticate.html#method.authenticate_admin /// [`device`]: #method.device #[derive(Debug)] -pub struct Admin { +pub struct Admin<'a, T: Device<'a>> { device: T, temp_password: Vec, + marker: marker::PhantomData<&'a T>, } -fn authenticate(device: D, password: &str, callback: T) -> Result +fn authenticate<'a, D, A, T>(device: D, password: &str, callback: T) -> Result where - D: Device, + D: Device<'a>, A: AuthenticatedDevice, T: Fn(*const c_char, *const c_char) -> c_int, { @@ -174,9 +177,9 @@ fn authenticate_user_wrapper<'a, T, C>( device: T, constructor: C, password: &str, -) -> Result>, (DeviceWrapper<'a>, Error)> +) -> Result>, (DeviceWrapper<'a>, Error)> where - T: Device, + T: Device<'a> + 'a, C: Fn(T) -> DeviceWrapper<'a>, { let result = device.authenticate_user(password); @@ -190,9 +193,9 @@ fn authenticate_admin_wrapper<'a, T, C>( device: T, constructor: C, password: &str, -) -> Result>, (DeviceWrapper<'a>, Error)> +) -> Result>, (DeviceWrapper<'a>, Error)> where - T: Device, + T: Device<'a> + 'a, C: Fn(T) -> DeviceWrapper<'a>, { let result = device.authenticate_admin(password); @@ -202,7 +205,7 @@ where } } -impl User { +impl<'a, T: Device<'a>> User<'a, 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. @@ -211,7 +214,7 @@ impl User { } } -impl ops::Deref for User { +impl<'a, T: Device<'a>> ops::Deref for User<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { @@ -219,13 +222,13 @@ impl ops::Deref for User { } } -impl ops::DerefMut for User { +impl<'a, T: Device<'a>> ops::DerefMut for User<'a, T> { fn deref_mut(&mut self) -> &mut T { &mut self.device } } -impl GenerateOtp for User { +impl<'a, T: Device<'a>> GenerateOtp for User<'a, T> { fn get_hotp_code(&mut self, slot: u8) -> Result { result_from_string(unsafe { nitrokey_sys::NK_get_hotp_code_PIN(slot, self.temp_password_ptr()) @@ -239,11 +242,12 @@ impl GenerateOtp for User { } } -impl AuthenticatedDevice for User { +impl<'a, T: Device<'a>> AuthenticatedDevice for User<'a, T> { fn new(device: T, temp_password: Vec) -> Self { User { device, temp_password, + marker: marker::PhantomData, } } @@ -252,7 +256,7 @@ impl AuthenticatedDevice for User { } } -impl ops::Deref for Admin { +impl<'a, T: Device<'a>> ops::Deref for Admin<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { @@ -260,13 +264,13 @@ impl ops::Deref for Admin { } } -impl ops::DerefMut for Admin { +impl<'a, T: Device<'a>> ops::DerefMut for Admin<'a, T> { fn deref_mut(&mut self) -> &mut T { &mut self.device } } -impl Admin { +impl<'a, T: Device<'a>> Admin<'a, 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. @@ -316,7 +320,7 @@ impl Admin { } } -impl ConfigureOtp for Admin { +impl<'a, T: Device<'a>> ConfigureOtp for Admin<'a, T> { fn write_hotp_slot(&mut self, data: OtpSlotData, counter: u64) -> Result<(), Error> { let raw_data = RawOtpSlotData::new(data)?; get_command_result(unsafe { @@ -364,11 +368,12 @@ impl ConfigureOtp for Admin { } } -impl AuthenticatedDevice for Admin { +impl<'a, T: Device<'a>> AuthenticatedDevice for Admin<'a, T> { fn new(device: T, temp_password: Vec) -> Self { Admin { device, temp_password, + marker: marker::PhantomData, } } @@ -377,8 +382,8 @@ impl AuthenticatedDevice for Admin { } } -impl<'a> Authenticate for DeviceWrapper<'a> { - fn authenticate_user(self, password: &str) -> Result, (Self, Error)> { +impl<'a> Authenticate<'a> for DeviceWrapper<'a> { + fn authenticate_user(self, password: &str) -> Result, (Self, Error)> { match self { DeviceWrapper::Storage(storage) => { authenticate_user_wrapper(storage, DeviceWrapper::Storage, password) @@ -387,7 +392,7 @@ impl<'a> Authenticate for DeviceWrapper<'a> { } } - fn authenticate_admin(self, password: &str) -> Result, (Self, Error)> { + fn authenticate_admin(self, password: &str) -> Result, (Self, Error)> { match self { DeviceWrapper::Storage(storage) => { authenticate_admin_wrapper(storage, DeviceWrapper::Storage, password) @@ -399,28 +404,28 @@ impl<'a> Authenticate for DeviceWrapper<'a> { } } -impl<'a> Authenticate for Pro<'a> { - fn authenticate_user(self, password: &str) -> Result, (Self, Error)> { +impl<'a> Authenticate<'a> for Pro<'a> { + fn authenticate_user(self, password: &str) -> Result, (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, (Self, Error)> { + fn authenticate_admin(self, password: &str) -> Result, (Self, Error)> { authenticate(self, password, |password_ptr, temp_password_ptr| unsafe { nitrokey_sys::NK_first_authenticate(password_ptr, temp_password_ptr) }) } } -impl<'a> Authenticate for Storage<'a> { - fn authenticate_user(self, password: &str) -> Result, (Self, Error)> { +impl<'a> Authenticate<'a> for Storage<'a> { + fn authenticate_user(self, password: &str) -> Result, (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, (Self, Error)> { + fn authenticate_admin(self, password: &str) -> Result, (Self, Error)> { authenticate(self, password, |password_ptr, temp_password_ptr| unsafe { nitrokey_sys::NK_first_authenticate(password_ptr, temp_password_ptr) }) -- cgit v1.2.1 From 62e8ee8f5d02511d6eb5dc179b087b04e88c1b94 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Sun, 27 Jan 2019 19:52:53 +0000 Subject: Update documentation for Manager refactoring This patch updates the documentation to reflect the latest changes to connection handling. It also updates the doc tests to prefer the new methods over the old ones. --- src/auth.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src/auth.rs') diff --git a/src/auth.rs b/src/auth.rs index 829d083..0b000f7 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -39,11 +39,12 @@ pub trait Authenticate<'a> { /// use nitrokey::{Authenticate, DeviceWrapper, User}; /// # use nitrokey::Error; /// - /// fn perform_user_task(device: &User) {} + /// fn perform_user_task<'a>(device: &User<'a, DeviceWrapper<'a>>) {} /// fn perform_other_task(device: &DeviceWrapper) {} /// /// # fn try_main() -> Result<(), Error> { - /// let device = nitrokey::connect()?; + /// let mut manager = nitrokey::take()?; + /// let device = manager.connect()?; /// let device = match device.authenticate_user("123456") { /// Ok(user) => { /// perform_user_task(&user); @@ -85,11 +86,12 @@ pub trait Authenticate<'a> { /// use nitrokey::{Authenticate, Admin, DeviceWrapper}; /// # use nitrokey::Error; /// - /// fn perform_admin_task(device: &Admin) {} + /// fn perform_admin_task<'a>(device: &Admin<'a, DeviceWrapper<'a>>) {} /// fn perform_other_task(device: &DeviceWrapper) {} /// /// # fn try_main() -> Result<(), Error> { - /// let device = nitrokey::connect()?; + /// let mut manager = nitrokey::take()?; + /// let device = manager.connect()?; /// let device = match device.authenticate_admin("123456") { /// Ok(admin) => { /// perform_admin_task(&admin); @@ -291,7 +293,8 @@ impl<'a, T: Device<'a>> Admin<'a, T> { /// # use nitrokey::Error; /// /// # fn try_main() -> Result<(), Error> { - /// let device = nitrokey::connect()?; + /// let mut manager = nitrokey::take()?; + /// let device = manager.connect()?; /// let config = Config::new(None, None, None, false); /// match device.authenticate_admin("12345678") { /// Ok(mut admin) => { -- cgit v1.2.1