From ba716c0ba1fdcdfe824d84f04f7580a1c8501777 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Mon, 21 May 2018 22:19:17 +0000 Subject: Add support for erase_hotp_slot and erase_totp_slot --- TODO.md | 2 -- src/lib.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tests/pro.rs | 44 +++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index 132086c..de33f8c 100644 --- a/TODO.md +++ b/TODO.md @@ -5,8 +5,6 @@ - `NK_factory_reset` - `NK_build_aes_key` - `NK_unlock_user_password` - - `NK_erase_hotp_slot` - - `NK_erase_totp_slot` - `NK_change_admin_PIN` - `NK_change_user_PIN` - `NK_enable_password_safe` diff --git a/src/lib.rs b/src/lib.rs index 117659f..8ffbf5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1310,6 +1310,72 @@ impl AdminAuthenticatedDevice { ) }); } + + /// Erase an HOTP slot. + /// + /// # Errors + /// + /// - [`InvalidSlot`][] if there is no slot with the given number + /// + /// # Example + /// + /// ```no_run + /// use nitrokey::{CommandStatus, Device, OtpMode, OtpSlotData}; + /// # use nitrokey::CommandError; + /// + /// # fn try_main() -> Result<(), (CommandError)> { + /// let device = nitrokey::connect()?; + /// match device.authenticate_admin("12345678") { + /// Ok(admin) => { + /// match admin.erase_hotp_slot(1) { + /// CommandStatus::Success => println!("Successfully erased slot."), + /// CommandStatus::Error(err) => println!("Could not erase slot: {:?}", err), + /// } + /// }, + /// Err((_, err)) => println!("Could not authenticate as admin: {:?}", err), + /// } + /// # Ok(()) + /// # } + /// ``` + /// + /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot + pub fn erase_hotp_slot(&self, slot: u8) -> CommandStatus { + let temp_password_ptr = self.temp_password.as_ptr() as *const i8; + unsafe { CommandStatus::from(nitrokey_sys::NK_erase_hotp_slot(slot, temp_password_ptr)) } + } + + /// Erase a TOTP slot. + /// + /// # Errors + /// + /// - [`InvalidSlot`][] if there is no slot with the given number + /// + /// # Example + /// + /// ```no_run + /// use nitrokey::{CommandStatus, Device, OtpMode, OtpSlotData}; + /// # use nitrokey::CommandError; + /// + /// # fn try_main() -> Result<(), (CommandError)> { + /// let device = nitrokey::connect()?; + /// match device.authenticate_admin("12345678") { + /// Ok(admin) => { + /// match admin.erase_totp_slot(1) { + /// CommandStatus::Success => println!("Successfully erased slot."), + /// CommandStatus::Error(err) => println!("Could not erase slot: {:?}", err), + /// } + /// }, + /// Err((_, err)) => println!("Could not authenticate as admin: {:?}", err), + /// } + /// # Ok(()) + /// # } + /// ``` + /// + /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot + pub fn erase_totp_slot(&self, slot: u8) -> CommandStatus { + let temp_password_ptr = self.temp_password.as_ptr() as *const i8; + unsafe { CommandStatus::from(nitrokey_sys::NK_erase_totp_slot(slot, temp_password_ptr)) } + } } impl Device for AdminAuthenticatedDevice {} diff --git a/src/tests/pro.rs b/src/tests/pro.rs index a508801..a23d42a 100644 --- a/src/tests/pro.rs +++ b/src/tests/pro.rs @@ -136,6 +136,28 @@ fn hotp_error() { assert_eq!(CommandError::InvalidSlot, code.unwrap_err()); } +#[test] +#[cfg_attr(not(feature = "test-pro"), ignore)] +fn hotp_erase() { + let admin = get_admin_test_device(); + let config = Config::new(None, None, None, false); + assert_eq!(CommandStatus::Success, admin.write_config(config)); + let slot_data = OtpSlotData::new(1, "test1", HOTP_SECRET, OtpMode::SixDigits); + assert_eq!(CommandStatus::Success, admin.write_hotp_slot(slot_data, 0)); + let slot_data = OtpSlotData::new(2, "test2", HOTP_SECRET, OtpMode::SixDigits); + assert_eq!(CommandStatus::Success, admin.write_hotp_slot(slot_data, 0)); + + assert_eq!(CommandStatus::Success, admin.erase_hotp_slot(1)); + + let device = admin.device(); + let result = device.get_hotp_slot_name(1); + assert_eq!(CommandError::SlotNotProgrammed, result.unwrap_err()); + let result = device.get_hotp_code(1); + assert_eq!(CommandError::SlotNotProgrammed, result.unwrap_err()); + + assert_eq!("test2", device.get_hotp_slot_name(2).unwrap()); +} + fn configure_totp(admin: &AdminAuthenticatedDevice) { let slot_data = OtpSlotData::new(1, "test-totp", TOTP_SECRET, OtpMode::EightDigits); assert_eq!(CommandStatus::Success, admin.write_totp_slot(slot_data, 30)); @@ -216,6 +238,28 @@ fn totp_error() { assert_eq!(CommandError::InvalidSlot, code.unwrap_err()); } +#[test] +#[cfg_attr(not(feature = "test-pro"), ignore)] +fn totp_erase() { + let admin = get_admin_test_device(); + let config = Config::new(None, None, None, false); + assert_eq!(CommandStatus::Success, admin.write_config(config)); + let slot_data = OtpSlotData::new(1, "test1", TOTP_SECRET, OtpMode::SixDigits); + assert_eq!(CommandStatus::Success, admin.write_totp_slot(slot_data, 0)); + let slot_data = OtpSlotData::new(2, "test2", TOTP_SECRET, OtpMode::SixDigits); + assert_eq!(CommandStatus::Success, admin.write_totp_slot(slot_data, 0)); + + assert_eq!(CommandStatus::Success, admin.erase_totp_slot(1)); + + let device = admin.device(); + let result = device.get_totp_slot_name(1); + assert_eq!(CommandError::SlotNotProgrammed, result.unwrap_err()); + let result = device.get_totp_code(1); + assert_eq!(CommandError::SlotNotProgrammed, result.unwrap_err()); + + assert_eq!("test2", device.get_totp_slot_name(2).unwrap()); +} + #[test] #[cfg_attr(not(feature = "test-pro"), ignore)] fn get_firmware_version() { -- cgit v1.2.1