aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md3
-rw-r--r--TODO.md1
-rw-r--r--src/device.rs36
-rw-r--r--tests/device.rs60
4 files changed, 92 insertions, 8 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1611414..8ecaef3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,8 +4,9 @@
- Add `CommandError::Undefined` to represent errors without further
information (e. g. a method returned `NULL` unexpectedly).
- Add error code to `CommandError::Unknown`.
-- Add function `Storage::change_update_pin` that changes the firmware update
+- Add the `Storage::change_update_pin` method that changes the firmware update
PIN.
+- Add the `Device::factory_reset` method that performs a factory reset.
# v0.2.3 (2018-12-31)
diff --git a/TODO.md b/TODO.md
index 0071dcc..5bcfa68 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,6 +1,5 @@
- Add support for the currently unsupported commands:
- `NK_set_unencrypted_volume_rorw_pin_type_user`
- - `NK_factory_reset`
- `NK_build_aes_key`
- `NK_is_AES_supported`
- `NK_send_startup`
diff --git a/src/device.rs b/src/device.rs
index 4b8cc5c..8702405 100644
--- a/src/device.rs
+++ b/src/device.rs
@@ -510,6 +510,36 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
fn lock(&self) -> Result<(), CommandError> {
unsafe { get_command_result(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.).
+ ///
+ /// # 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::CommandError;
+ ///
+ /// # fn try_main() -> Result<(), CommandError> {
+ /// let device = nitrokey::connect()?;
+ /// match device.factory_reset("12345678") {
+ /// Ok(()) => println!("Performed a factory reset."),
+ /// Err(err) => println!("Could not perform a factory reset: {}", err),
+ /// };
+ /// # Ok(())
+ /// # }
+ /// ```
+ fn factory_reset(&self, admin_pin: &str) -> Result<(), CommandError> {
+ let admin_pin_string = get_cstring(admin_pin)?;
+ unsafe { get_command_result(nitrokey_sys::NK_factory_reset(admin_pin_string.as_ptr())) }
+ }
}
/// Connects to a Nitrokey device. This method can be used to connect to any connected device,
@@ -700,9 +730,9 @@ impl Storage {
let new_string = get_cstring(new)?;
unsafe {
get_command_result(nitrokey_sys::NK_change_update_password(
- current_string.as_ptr(),
- new_string.as_ptr(),
- ))
+ current_string.as_ptr(),
+ new_string.as_ptr(),
+ ))
}
}
diff --git a/tests/device.rs b/tests/device.rs
index a225d2d..363b8d8 100644
--- a/tests/device.rs
+++ b/tests/device.rs
@@ -4,9 +4,12 @@ use std::ffi::CStr;
use std::process::Command;
use std::{thread, time};
-use nitrokey::{Authenticate, CommandError, Config, Device, Storage};
+use nitrokey::{
+ Authenticate, CommandError, Config, ConfigureOtp, Device, GenerateOtp, GetPasswordSafe,
+ OtpMode, OtpSlotData, Storage,
+};
-use crate::util::{Target, ADMIN_PASSWORD, USER_PASSWORD, UPDATE_PIN};
+use crate::util::{Target, ADMIN_PASSWORD, UPDATE_PIN, USER_PASSWORD};
static ADMIN_NEW_PASSWORD: &str = "1234567890";
static UPDATE_NEW_PIN: &str = "87654321";
@@ -296,11 +299,62 @@ fn unlock_user_pin() {
}
#[test]
+#[cfg_attr(not(any(feature = "test-pro", feature = "test-storage")), ignore)]
+fn factory_reset() {
+ let device = Target::connect().unwrap();
+
+ assert_eq!(
+ Ok(()),
+ device.change_user_pin(USER_PASSWORD, USER_NEW_PASSWORD)
+ );
+ assert_eq!(
+ Ok(()),
+ device.change_admin_pin(ADMIN_PASSWORD, ADMIN_NEW_PASSWORD)
+ );
+
+ let admin = device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap();
+ let otp_data = OtpSlotData::new(1, "test", "0123468790", OtpMode::SixDigits);
+ assert_eq!(Ok(()), admin.write_totp_slot(otp_data, 30));
+
+ let device = admin.device();
+ let pws = device.get_password_safe(USER_NEW_PASSWORD).unwrap();
+ assert_eq!(Ok(()), pws.write_slot(0, "test", "testlogin", "testpw"));
+ drop(pws);
+
+ assert_eq!(
+ Err(CommandError::WrongPassword),
+ device.factory_reset(USER_NEW_PASSWORD)
+ );
+ assert_eq!(
+ Err(CommandError::WrongPassword),
+ device.factory_reset(ADMIN_PASSWORD)
+ );
+ assert_eq!(Ok(()), device.factory_reset(ADMIN_NEW_PASSWORD));
+
+ let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device();
+
+ let user = device.authenticate_user(USER_PASSWORD).unwrap();
+ assert_eq!(
+ Err(CommandError::SlotNotProgrammed),
+ user.get_totp_slot_name(1)
+ );
+
+ let device = user.device();
+ let pws = device.get_password_safe(USER_PASSWORD).unwrap();
+ assert_ne!("test".to_string(), pws.get_slot_name(0).unwrap());
+ assert_ne!("testlogin".to_string(), pws.get_slot_login(0).unwrap());
+ assert_ne!("testpw".to_string(), pws.get_slot_password(0).unwrap());
+}
+
+#[test]
#[cfg_attr(not(feature = "test-storage"), ignore)]
fn change_update_pin() {
let device = Storage::connect().unwrap();
- assert_eq!(Err(CommandError::WrongPassword), device.change_update_pin(UPDATE_NEW_PIN, UPDATE_PIN));
+ assert_eq!(
+ Err(CommandError::WrongPassword),
+ device.change_update_pin(UPDATE_NEW_PIN, UPDATE_PIN)
+ );
assert_eq!(Ok(()), device.change_update_pin(UPDATE_PIN, UPDATE_NEW_PIN));
assert_eq!(Ok(()), device.change_update_pin(UPDATE_NEW_PIN, UPDATE_PIN));
}