From 39ad1f54bb2c1e828e19193fd8772f17731973f9 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Mon, 10 Dec 2018 14:44:39 +0000 Subject: Provide access to the status of a Nitrokey Storage This patch adds a `get_status` method to the `Storage` structure. The returned structure `StorageStatus` is based on the structure provided by libnitrokey. --- TODO.md | 3 +- src/device.rs | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/tests/device.rs | 10 +++++ 3 files changed, 126 insertions(+), 5 deletions(-) diff --git a/TODO.md b/TODO.md index 2d865a4..6086ad8 100644 --- a/TODO.md +++ b/TODO.md @@ -18,7 +18,6 @@ - `NK_clear_new_sd_card_warning` - `NK_fill_SD_card_with_random_data` - `NK_change_update_password` - - `NK_get_status_storage_as_string` - `NK_get_SD_usage_data_as_string` - `NK_get_progress_bar_value` - `NK_list_devices_by_cpuID` @@ -27,7 +26,6 @@ - `NK_get_library_version` - `NK_get_major_library_version` - `NK_get_minor_libray_version` - - `NK_get_status_storage` - `NK_get_storage_production_info` - `NK_totp_set_time_soft` - `NK_wink` @@ -43,5 +41,6 @@ issue 65][]). - Disable creation of multiple password safes at the same time. - Check timing in Storage tests. +- Consider restructuring `device::StorageStatus`. [nitrokey-storage-firmware issue 65]: https://github.com/Nitrokey/nitrokey-storage-firmware/issues/65 diff --git a/src/device.rs b/src/device.rs index 843b41d..f135261 100644 --- a/src/device.rs +++ b/src/device.rs @@ -164,6 +164,47 @@ pub struct Pro {} #[derive(Debug)] pub struct Storage {} +/// The status of a volume on a Nitrokey Storage device. +#[derive(Debug)] +pub struct VolumeStatus { + /// Indicates whether the volume is read-only. + pub read_only: bool, + /// Indicates whether the volume is active. + pub active: bool, +} + +/// The status of a Nitrokey Storage device. +#[derive(Debug)] +pub struct StorageStatus { + /// The status of the unencrypted volume. + pub unencrypted_volume: VolumeStatus, + /// The status of the encrypted volume. + pub encrypted_volume: VolumeStatus, + /// The status of the hidden volume. + pub hidden_volume: VolumeStatus, + /// The major firmware version, e. g. 0 in v0.40. + pub firmware_version_major: u8, + /// The minor firmware version, e. g. 40 in v0.40. + pub firmware_version_minor: u8, + /// Indicates whether the firmware is locked. + pub firmware_locked: bool, + /// The serial number of the SD card in the Storage stick. + pub serial_number_sd_card: u32, + /// The serial number of the smart card in the Storage stick. + pub serial_number_smart_card: u32, + /// The number of remaining login attempts for the user PIN. + pub user_retry_count: u8, + /// The number of remaining login attempts for the admin PIN. + pub admin_retry_count: u8, + /// Indicates whether a new SD card was found. + pub new_sd_card_found: bool, + /// Indicates whether the SD card is filled with random characters. + pub filled_with_random: bool, + /// Indicates whether the stick has been initialized by generating + /// the AES keys. + pub stick_initialized: bool, +} + /// A Nitrokey device. /// /// This trait provides the commands that can be executed without authentication and that are @@ -616,12 +657,54 @@ impl Storage { /// # Ok(()) /// # } /// ``` - /// - /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString - /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword pub fn disable_encrypted_volume(&self) -> Result<(), CommandError> { unsafe { get_command_result(nitrokey_sys::NK_lock_encrypted_volume()) } } + + + /// Returns the status of the connected storage device. + /// + /// # Example + /// + /// ```no_run + /// # use nitrokey::CommandError; + /// + /// fn use_volume() {} + /// + /// # fn try_main() -> Result<(), CommandError> { + /// let device = nitrokey::Storage::connect()?; + /// match device.get_status() { + /// Ok(status) => { + /// println!("SD card ID: {:#x}", status.serial_number_sd_card); + /// }, + /// Err(err) => println!("Could not get Storage status: {}", err), + /// }; + /// # Ok(()) + /// # } + /// ``` + pub fn get_status(&self) -> Result { + let mut raw_status = nitrokey_sys::NK_storage_status { + unencrypted_volume_read_only: false, + unencrypted_volume_active: false, + encrypted_volume_read_only: false, + encrypted_volume_active: false, + hidden_volume_read_only: false, + hidden_volume_active: false, + firmware_version_major: 0, + firmware_version_minor: 0, + firmware_locked: false, + serial_number_sd_card: 0, + serial_number_smart_card: 0, + user_retry_count: 0, + admin_retry_count: 0, + new_sd_card_found: false, + filled_with_random: false, + stick_initialized: false, + }; + let raw_result = unsafe { nitrokey_sys::NK_get_status_storage(&mut raw_status) }; + let result = get_command_result(raw_result); + result.and(Ok(StorageStatus::from(raw_status))) + } } impl Drop for Storage { @@ -635,3 +718,32 @@ impl Drop for Storage { impl Device for Storage {} impl GenerateOtp for Storage {} + +impl From for StorageStatus { + fn from(status: nitrokey_sys::NK_storage_status) -> Self { + StorageStatus { + unencrypted_volume: VolumeStatus { + read_only: status.unencrypted_volume_read_only, + active: status.unencrypted_volume_active, + }, + encrypted_volume: VolumeStatus { + read_only: status.encrypted_volume_read_only, + active: status.encrypted_volume_active, + }, + hidden_volume: VolumeStatus { + read_only: status.hidden_volume_read_only, + active: status.hidden_volume_active, + }, + firmware_version_major: status.firmware_version_major, + firmware_version_minor: status.firmware_version_minor, + firmware_locked: status.firmware_locked, + serial_number_sd_card: status.serial_number_sd_card, + serial_number_smart_card: status.serial_number_smart_card, + user_retry_count: status.user_retry_count, + admin_retry_count: status.admin_retry_count, + new_sd_card_found: status.new_sd_card_found, + filled_with_random: status.filled_with_random, + stick_initialized: status.stick_initialized, + } + } +} diff --git a/src/tests/device.rs b/src/tests/device.rs index c2c5336..fed465d 100644 --- a/src/tests/device.rs +++ b/src/tests/device.rs @@ -292,3 +292,13 @@ fn lock() { assert!(device.lock().is_ok()); assert_eq!(1, count_nitrokey_block_devices()); } + +#[test] +#[cfg_attr(not(feature = "test-storage"), ignore)] +fn get_storage_status() { + let device = Storage::connect().unwrap(); + let status = device.get_status().unwrap(); + + assert!(status.serial_number_sd_card > 0); + assert!(status.serial_number_smart_card > 0); +} -- cgit v1.2.3