diff options
Diffstat (limited to 'nitrokey/src/device/mod.rs')
-rw-r--r-- | nitrokey/src/device/mod.rs | 464 |
1 files changed, 0 insertions, 464 deletions
diff --git a/nitrokey/src/device/mod.rs b/nitrokey/src/device/mod.rs deleted file mode 100644 index 5e15f08..0000000 --- a/nitrokey/src/device/mod.rs +++ /dev/null @@ -1,464 +0,0 @@ -// Copyright (C) 2018-2019 Robin Krahl <robin.krahl@ireas.org> -// SPDX-License-Identifier: MIT - -mod pro; -mod storage; -mod wrapper; - -use std::fmt; - -use libc; -use nitrokey_sys; - -use crate::auth::Authenticate; -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, result_or_error, -}; - -pub use pro::Pro; -pub use storage::{ - SdCardData, Storage, StorageProductionInfo, StorageStatus, VolumeMode, VolumeStatus, -}; -pub use wrapper::DeviceWrapper; - -/// Available Nitrokey models. -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum Model { - /// The Nitrokey Storage. - Storage, - /// The Nitrokey Pro. - Pro, -} - -impl fmt::Display for Model { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match *self { - Model::Pro => "Pro", - Model::Storage => "Storage", - }) - } -} - -/// A firmware version for a Nitrokey device. -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct FirmwareVersion { - /// The major firmware version, e. g. 0 in v0.40. - pub major: u8, - /// The minor firmware version, e. g. 40 in v0.40. - pub minor: u8, -} - -impl fmt::Display for FirmwareVersion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "v{}.{}", self.major, self.minor) - } -} - -/// A Nitrokey device. -/// -/// This trait provides the commands that can be executed without authentication and that are -/// present on all supported Nitrokey devices. -pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt::Debug { - /// Returns the [`Manager`][] instance that has been used to connect to this device. - /// - /// # Example - /// - /// ``` - /// use nitrokey::{Device, DeviceWrapper}; - /// - /// fn do_something(device: DeviceWrapper) { - /// // reconnect to any device - /// let manager = device.into_manager(); - /// let device = manager.connect(); - /// // do something with the device - /// // ... - /// } - /// - /// match nitrokey::take()?.connect() { - /// Ok(device) => do_something(device), - /// Err(err) => println!("Could not connect to a Nitrokey: {}", err), - /// } - /// # Ok::<(), nitrokey::Error>(()) - /// ``` - fn into_manager(self) -> &'a mut crate::Manager; - - /// Returns the model of the connected Nitrokey device. - /// - /// # Example - /// - /// ```no_run - /// use nitrokey::Device; - /// # use nitrokey::Error; - /// - /// # fn try_main() -> Result<(), Error> { - /// let mut manager = nitrokey::take()?; - /// let device = manager.connect()?; - /// println!("Connected to a Nitrokey {}", device.get_model()); - /// # Ok(()) - /// # } - fn get_model(&self) -> Model; - - /// Returns the serial number of the Nitrokey device. The serial number is the string - /// representation of a hex number. - /// - /// # Example - /// - /// ```no_run - /// use nitrokey::Device; - /// # use nitrokey::Error; - /// - /// # fn try_main() -> Result<(), Error> { - /// let mut manager = nitrokey::take()?; - /// let device = manager.connect()?; - /// match device.get_serial_number() { - /// Ok(number) => println!("serial no: {}", number), - /// Err(err) => eprintln!("Could not get serial number: {}", err), - /// }; - /// # Ok(()) - /// # } - /// ``` - fn get_serial_number(&self) -> Result<String, Error> { - result_from_string(unsafe { nitrokey_sys::NK_device_serial_number() }) - } - - /// Returns the number of remaining authentication attempts for the user. The total number of - /// available attempts is three. - /// - /// # Example - /// - /// ```no_run - /// use nitrokey::Device; - /// # use nitrokey::Error; - /// - /// # fn try_main() -> Result<(), Error> { - /// let mut manager = nitrokey::take()?; - /// let device = manager.connect()?; - /// let count = device.get_user_retry_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) -> 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 - /// available attempts is three. - /// - /// # Example - /// - /// ```no_run - /// use nitrokey::Device; - /// # use nitrokey::Error; - /// - /// # fn try_main() -> Result<(), Error> { - /// let mut manager = nitrokey::take()?; - /// let device = manager.connect()?; - /// let count = device.get_admin_retry_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) -> Result<u8, Error> { - result_or_error(unsafe { nitrokey_sys::NK_get_admin_retry_count() }) - } - - /// Returns the firmware version. - /// - /// # Example - /// - /// ```no_run - /// use nitrokey::Device; - /// # use nitrokey::Error; - /// - /// # fn try_main() -> Result<(), Error> { - /// let mut manager = nitrokey::take()?; - /// let device = manager.connect()?; - /// match device.get_firmware_version() { - /// Ok(version) => println!("Firmware version: {}", version), - /// Err(err) => eprintln!("Could not access firmware version: {}", err), - /// }; - /// # Ok(()) - /// # } - /// ``` - 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() })?; - Ok(FirmwareVersion { major, minor }) - } - - /// Returns the current configuration of the Nitrokey device. - /// - /// # Example - /// - /// ```no_run - /// use nitrokey::Device; - /// # use nitrokey::Error; - /// - /// # fn try_main() -> Result<(), Error> { - /// let mut manager = nitrokey::take()?; - /// let device = manager.connect()?; - /// let config = device.get_config()?; - /// println!("numlock binding: {:?}", config.numlock); - /// println!("capslock binding: {:?}", config.capslock); - /// println!("scrollock binding: {:?}", config.scrollock); - /// println!("require password for OTP: {:?}", config.user_password); - /// # Ok(()) - /// # } - /// ``` - fn get_config(&self) -> Result<Config, Error> { - let config_ptr = unsafe { nitrokey_sys::NK_read_config() }; - if config_ptr.is_null() { - return Err(get_last_error()); - } - let config_array_ptr = config_ptr as *const [u8; 5]; - let raw_config = unsafe { RawConfig::from(*config_array_ptr) }; - unsafe { libc::free(config_ptr as *mut libc::c_void) }; - Ok(raw_config.into()) - } - - /// Changes the administrator PIN. - /// - /// # Errors - /// - /// - [`InvalidString`][] if one of the provided passwords contains a null byte - /// - [`WrongPassword`][] if the current admin password is wrong - /// - /// # Example - /// - /// ```no_run - /// use nitrokey::Device; - /// # use nitrokey::Error; - /// - /// # fn try_main() -> Result<(), Error> { - /// let mut manager = nitrokey::take()?; - /// let mut device = manager.connect()?; - /// match device.change_admin_pin("12345678", "12345679") { - /// Ok(()) => println!("Updated admin PIN."), - /// Err(err) => eprintln!("Failed to update admin PIN: {}", err), - /// }; - /// # Ok(()) - /// # } - /// ``` - /// - /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString - /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword - 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 { - nitrokey_sys::NK_change_admin_PIN(current_string.as_ptr(), new_string.as_ptr()) - }) - } - - /// Changes the user PIN. - /// - /// # Errors - /// - /// - [`InvalidString`][] if one of the provided passwords contains a null byte - /// - [`WrongPassword`][] if the current user password is wrong - /// - /// # Example - /// - /// ```no_run - /// use nitrokey::Device; - /// # use nitrokey::Error; - /// - /// # fn try_main() -> Result<(), Error> { - /// let mut manager = nitrokey::take()?; - /// let mut device = manager.connect()?; - /// match device.change_user_pin("123456", "123457") { - /// Ok(()) => println!("Updated admin PIN."), - /// Err(err) => eprintln!("Failed to update admin PIN: {}", err), - /// }; - /// # Ok(()) - /// # } - /// ``` - /// - /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString - /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword - 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 { - nitrokey_sys::NK_change_user_PIN(current_string.as_ptr(), new_string.as_ptr()) - }) - } - - /// Unlocks the user PIN after three failed login attempts and sets it to the given value. - /// - /// # Errors - /// - /// - [`InvalidString`][] if one of the provided passwords contains a null byte - /// - [`WrongPassword`][] if the admin password is wrong - /// - /// # Example - /// - /// ```no_run - /// use nitrokey::Device; - /// # use nitrokey::Error; - /// - /// # fn try_main() -> Result<(), Error> { - /// let mut manager = nitrokey::take()?; - /// let mut device = manager.connect()?; - /// match device.unlock_user_pin("12345678", "123456") { - /// Ok(()) => println!("Unlocked user PIN."), - /// Err(err) => eprintln!("Failed to unlock user PIN: {}", err), - /// }; - /// # Ok(()) - /// # } - /// ``` - /// - /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString - /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword - 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 { - nitrokey_sys::NK_unlock_user_password( - admin_pin_string.as_ptr(), - user_pin_string.as_ptr(), - ) - }) - } - - /// Locks the Nitrokey device. - /// - /// This disables the password store if it has been unlocked. On the Nitrokey Storage, this - /// also disables the volumes if they have been enabled. - /// - /// # Example - /// - /// ```no_run - /// use nitrokey::Device; - /// # use nitrokey::Error; - /// - /// # fn try_main() -> Result<(), Error> { - /// let mut manager = nitrokey::take()?; - /// let mut device = manager.connect()?; - /// match device.lock() { - /// Ok(()) => println!("Locked the Nitrokey device."), - /// Err(err) => eprintln!("Could not lock the Nitrokey device: {}", err), - /// }; - /// # Ok(()) - /// # } - /// ``` - fn lock(&mut self) -> Result<(), Error> { - get_command_result(unsafe { nitrokey_sys::NK_lock_device() }) - } - - /// Performs a factory reset on the Nitrokey device. - /// - /// This commands performs a factory reset on the smart card (like the factory reset via `gpg - /// --card-edit`) and then clears the flash memory (password safe, one-time passwords etc.). - /// After a factory reset, [`build_aes_key`][] has to be called before the password safe or the - /// encrypted volume can be used. - /// - /// # Errors - /// - /// - [`InvalidString`][] if the provided password contains a null byte - /// - [`WrongPassword`][] if the admin password is wrong - /// - /// # Example - /// - /// ```no_run - /// use nitrokey::Device; - /// # use nitrokey::Error; - /// - /// # fn try_main() -> Result<(), Error> { - /// let mut manager = nitrokey::take()?; - /// let mut device = manager.connect()?; - /// match device.factory_reset("12345678") { - /// Ok(()) => println!("Performed a factory reset."), - /// Err(err) => eprintln!("Could not perform a factory reset: {}", err), - /// }; - /// # Ok(()) - /// # } - /// ``` - /// - /// [`build_aes_key`]: #method.build_aes_key - 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()) }) - } - - /// Builds a new AES key on the Nitrokey. - /// - /// The AES key is used to encrypt the password safe and the encrypted volume. You may need - /// to call this method after a factory reset, either using [`factory_reset`][] or using `gpg - /// --card-edit`. You can also use it to destroy the data stored in the password safe or on - /// the encrypted volume. - /// - /// # Errors - /// - /// - [`InvalidString`][] if the provided password contains a null byte - /// - [`WrongPassword`][] if the admin password is wrong - /// - /// # Example - /// - /// ```no_run - /// use nitrokey::Device; - /// # use nitrokey::Error; - /// - /// # fn try_main() -> Result<(), Error> { - /// let mut manager = nitrokey::take()?; - /// let mut device = manager.connect()?; - /// match device.build_aes_key("12345678") { - /// Ok(()) => println!("New AES keys have been built."), - /// Err(err) => eprintln!("Could not build new AES keys: {}", err), - /// }; - /// # Ok(()) - /// # } - /// ``` - /// - /// [`factory_reset`]: #method.factory_reset - 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()) }) - } -} - -fn get_connected_model() -> Option<Model> { - match unsafe { nitrokey_sys::NK_get_device_model() } { - nitrokey_sys::NK_device_model_NK_PRO => Some(Model::Pro), - nitrokey_sys::NK_device_model_NK_STORAGE => Some(Model::Storage), - _ => None, - } -} - -pub(crate) fn create_device_wrapper( - manager: &mut crate::Manager, - model: Model, -) -> DeviceWrapper<'_> { - match model { - Model::Pro => Pro::new(manager).into(), - Model::Storage => Storage::new(manager).into(), - } -} - -pub(crate) fn get_connected_device( - manager: &mut crate::Manager, -) -> Result<DeviceWrapper<'_>, Error> { - match get_connected_model() { - Some(model) => Ok(create_device_wrapper(manager, model)), - None => Err(CommunicationError::NotConnected.into()), - } -} - -pub(crate) fn connect_enum(model: Model) -> bool { - let model = match model { - Model::Storage => nitrokey_sys::NK_device_model_NK_STORAGE, - Model::Pro => nitrokey_sys::NK_device_model_NK_PRO, - }; - unsafe { nitrokey_sys::NK_login_enum(model) == 1 } -} |