aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO.md2
-rw-r--r--src/lib.rs76
-rw-r--r--src/tests/pro.rs48
3 files changed, 123 insertions, 3 deletions
diff --git a/TODO.md b/TODO.md
index de33f8c..b9efdbd 100644
--- a/TODO.md
+++ b/TODO.md
@@ -5,8 +5,6 @@
- `NK_factory_reset`
- `NK_build_aes_key`
- `NK_unlock_user_password`
- - `NK_change_admin_PIN`
- - `NK_change_user_PIN`
- `NK_enable_password_safe`
- `NK_get_password_safe_slot_status`
- `NK_get_password_safe_slot_name`
diff --git a/src/lib.rs b/src/lib.rs
index 8ffbf5a..817ee0a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -211,7 +211,6 @@ struct RawConfig {
pub user_password: bool,
}
-#[derive(Debug)]
/// A Nitrokey device without user or admin authentication.
///
/// Use [`connect`][] or [`connect_model`][] to obtain an instance. If you
@@ -250,6 +249,7 @@ struct RawConfig {
/// [`authenticate_user`]: #method.authenticate_user
/// [`connect`]: fn.connect.html
/// [`connect_model`]: fn.connect_model.html
+#[derive(Debug)]
pub struct UnauthenticatedDevice {}
/// A Nitrokey device with user authentication.
@@ -261,6 +261,7 @@ pub struct UnauthenticatedDevice {}
/// [`authenticate_admin`]: struct.UnauthenticatedDevice#method.authenticate_admin
/// [`device`]: #method.device
/// [`UnauthenticatedDevice`]: struct.UnauthenticatedDevice.html
+#[derive(Debug)]
pub struct UserAuthenticatedDevice {
device: UnauthenticatedDevice,
temp_password: Vec<u8>,
@@ -275,6 +276,7 @@ pub struct UserAuthenticatedDevice {
/// [`authenticate_admin`]: struct.UnauthenticatedDevice#method.authenticate_admin
/// [`device`]: #method.device
/// [`UnauthenticatedDevice`]: struct.UnauthenticatedDevice.html
+#[derive(Debug)]
pub struct AdminAuthenticatedDevice {
device: UnauthenticatedDevice,
temp_password: Vec<u8>,
@@ -634,6 +636,78 @@ pub trait Device {
return result_from_string(nitrokey_sys::NK_get_totp_code(slot, 0, 0, 0));
}
}
+
+ /// 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::CommandError;
+ ///
+ /// # fn try_main() -> Result<(), CommandError> {
+ /// let device = nitrokey::connect()?;
+ /// match device.change_admin_pin("12345678", "12345679") {
+ /// CommandStatus::Success => println!("Updated admin PIN."),
+ /// CommandStatus::Error(err) => println!("Failed to update admin PIN: {:?}", err),
+ /// };
+ /// # Ok(())
+ /// # }
+ /// ```
+ ///
+ /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
+ fn change_admin_pin(&self, current: &str, new: &str) -> CommandStatus {
+ let current_string = CString::new(current);
+ let new_string = CString::new(new);
+ if current_string.is_err() || new_string.is_err() {
+ return CommandStatus::Error(CommandError::InvalidString);
+ }
+ let current_string = current_string.unwrap();
+ let new_string = new_string.unwrap();
+ unsafe { CommandStatus::from(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::CommandError;
+ ///
+ /// # fn try_main() -> Result<(), CommandError> {
+ /// let device = nitrokey::connect()?;
+ /// match device.change_user_pin("123456", "123457") {
+ /// CommandStatus::Success => println!("Updated admin PIN."),
+ /// CommandStatus::Error(err) => println!("Failed to update admin PIN: {:?}", err),
+ /// };
+ /// # Ok(())
+ /// # }
+ /// ```
+ ///
+ /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
+ fn change_user_pin(&self, current: &str, new: &str) -> CommandStatus {
+ let current_string = CString::new(current);
+ let new_string = CString::new(new);
+ if current_string.is_err() || new_string.is_err() {
+ return CommandStatus::Error(CommandError::InvalidString);
+ }
+ let current_string = current_string.unwrap();
+ let new_string = new_string.unwrap();
+ unsafe { CommandStatus::from(nitrokey_sys::NK_change_user_PIN(current_string.as_ptr(), new_string.as_ptr())) }
+ }
}
trait AuthenticatedDevice {
diff --git a/src/tests/pro.rs b/src/tests/pro.rs
index a23d42a..d2132f8 100644
--- a/src/tests/pro.rs
+++ b/src/tests/pro.rs
@@ -4,7 +4,9 @@ use {set_debug, AdminAuthenticatedDevice, CommandError, CommandStatus, Config, D
OtpMode, OtpSlotData, UnauthenticatedDevice};
static ADMIN_PASSWORD: &str = "12345678";
+static ADMIN_NEW_PASSWORD: &str = "1234567890";
static USER_PASSWORD: &str = "123456";
+static USER_NEW_PASSWORD: &str = "abcdefghij";
// test suite according to RFC 4226, Appendix D
static HOTP_SECRET: &str = "3132333435363738393031323334353637383930";
@@ -330,3 +332,49 @@ fn read_write_config() {
let get_config = admin.get_config().unwrap();
assert_eq!(config, get_config);
}
+
+#[test]
+#[cfg_attr(not(feature = "test-pro"), ignore)]
+fn change_user_pin() {
+ let device = get_test_device();
+ let device = device.authenticate_user(USER_PASSWORD).unwrap().device();
+ let device = device.authenticate_user(USER_NEW_PASSWORD).unwrap_err().0;
+
+ let result = device.change_user_pin(USER_PASSWORD, USER_NEW_PASSWORD);
+ assert_eq!(CommandStatus::Success, result);
+
+ let device = device.authenticate_user(USER_PASSWORD).unwrap_err().0;
+ let device = device.authenticate_user(USER_NEW_PASSWORD).unwrap().device();
+
+ let result = device.change_user_pin(USER_PASSWORD, USER_PASSWORD);
+ assert_eq!(CommandStatus::Error(CommandError::WrongPassword), result);
+
+ let result = device.change_user_pin(USER_NEW_PASSWORD, USER_PASSWORD);
+ assert_eq!(CommandStatus::Success, result);
+
+ let device = device.authenticate_user(USER_PASSWORD).unwrap().device();
+ device.authenticate_user(USER_NEW_PASSWORD).unwrap_err();
+}
+
+#[test]
+#[cfg_attr(not(feature = "test-pro"), ignore)]
+fn change_admin_pin() {
+ let device = get_test_device();
+ let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device();
+ let device = device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err().0;
+
+ let result = device.change_admin_pin(ADMIN_PASSWORD, ADMIN_NEW_PASSWORD);
+ assert_eq!(CommandStatus::Success, result);
+
+ let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap_err().0;
+ let device = device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap().device();
+
+ let result = device.change_admin_pin(ADMIN_PASSWORD, ADMIN_PASSWORD);
+ assert_eq!(CommandStatus::Error(CommandError::WrongPassword), result);
+
+ let result = device.change_admin_pin(ADMIN_NEW_PASSWORD, ADMIN_PASSWORD);
+ assert_eq!(CommandStatus::Success, result);
+
+ let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device();
+ device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err();
+}