From 0ee7ef7705ebfc0d419bba9a61db55fccd14b638 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Sat, 12 Jan 2019 16:51:47 +0000 Subject: Add set_unencrypted_volume_mode to Storage The new set_unencrypted_volume_mode method sets the access mode of the unencrypted volume on the Nitrokey Storage. Depending on the requested access mode, it calls either NK_set_unencrypted_read_only_admin or NK_set_unencrypted_read_write_admin. Note that this function requires firmware version 0.51 or later. (Earlier firmware versions used the user PIN.) --- CHANGELOG.md | 2 ++ TODO.md | 2 -- src/device.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ tests/device.rs | 34 +++++++++++++++++++++++++++++++++- 4 files changed, 81 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b475168..b5f7b45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ `CommandError::InvalidHexString` and `CommandError::TargetBufferTooSmall`. - Add the `get_library_version` function to query the libnitrokey version. - Add the `wink` method to the `Storage` struct. +- Add the `set_unencrypted_volume_mode` to set the access mode of the + unencrypted volume. # v0.3.1 (2019-01-07) - Use `nitrokey-test` to select and execute the unit tests. diff --git a/TODO.md b/TODO.md index cd258fc..65ee4ea 100644 --- a/TODO.md +++ b/TODO.md @@ -3,9 +3,7 @@ - `NK_is_AES_supported` - `NK_send_startup` - `NK_set_unencrypted_read_only` - - `NK_set_unencrypted_read_only_admin` - `NK_set_unencrypted_read_write` - - `NK_set_unencrypted_read_write_admin` - `NK_set_encrypted_read_only` - `NK_set_encrypted_read_write` - `NK_export_firmware` diff --git a/src/device.rs b/src/device.rs index 792ac2f..ee8e31c 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1076,6 +1076,52 @@ impl Storage { } } + /// Sets the access mode of the unencrypted volume. + /// + /// This command will reconnect the unencrypted volume so buffers should be flushed before + /// calling it. Since firmware version v0.51, this command requires the admin PIN. Older + /// firmware versions are not supported. + /// + /// # Errors + /// + /// - [`InvalidString`][] if the provided password contains a null byte + /// - [`WrongPassword`][] if the provided admin password is wrong + /// + /// # Example + /// + /// ```no_run + /// # use nitrokey::CommandError; + /// use nitrokey::VolumeMode; + /// + /// # fn try_main() -> Result<(), CommandError> { + /// let device = nitrokey::Storage::connect()?; + /// match device.set_unencrypted_volume_mode("123456", 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), + /// }; + /// # Ok(()) + /// # } + /// ``` + /// + /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString + /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword + pub fn set_unencrypted_volume_mode( + &self, + admin_pin: &str, + mode: VolumeMode, + ) -> Result<(), CommandError> { + let admin_pin = get_cstring(admin_pin)?; + let result = match mode { + VolumeMode::ReadOnly => unsafe { + nitrokey_sys::NK_set_unencrypted_read_only_admin(admin_pin.as_ptr()) + }, + VolumeMode::ReadWrite => unsafe { + nitrokey_sys::NK_set_unencrypted_read_write_admin(admin_pin.as_ptr()) + }, + }; + get_command_result(result) + } + /// Returns the status of the connected storage device. /// /// # Example diff --git a/tests/device.rs b/tests/device.rs index 6f21dcb..9985e7a 100644 --- a/tests/device.rs +++ b/tests/device.rs @@ -6,7 +6,7 @@ use std::{thread, time}; use nitrokey::{ Authenticate, CommandError, Config, ConfigureOtp, Device, GenerateOtp, GetPasswordSafe, - OtpMode, OtpSlotData, + OtpMode, OtpSlotData, Storage, VolumeMode, }; use nitrokey_test::test as test_device; @@ -398,6 +398,38 @@ fn lock(device: Storage) { assert_eq!(1, count_nitrokey_block_devices()); } +#[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()); + assert_eq!( + status.unwrap().unencrypted_volume.read_only, + mode == VolumeMode::ReadOnly + ); + } + + fn assert_success(device: &Storage, mode: VolumeMode) { + assert_eq!( + Ok(()), + device.set_unencrypted_volume_mode(ADMIN_PASSWORD, mode) + ); + assert_mode(&device, mode); + } + + assert_success(&device, VolumeMode::ReadOnly); + + assert_eq!( + Err(CommandError::WrongPassword), + device.set_unencrypted_volume_mode(USER_PASSWORD, VolumeMode::ReadOnly) + ); + assert_mode(&device, VolumeMode::ReadOnly); + + assert_success(&device, VolumeMode::ReadWrite); + assert_success(&device, VolumeMode::ReadWrite); + assert_success(&device, VolumeMode::ReadOnly); +} + #[test_device] fn get_storage_status(device: Storage) { let status = device.get_status().unwrap(); -- cgit v1.2.1