aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Krahl <robin.krahl@ireas.org>2018-05-21 21:59:25 +0000
committerRobin Krahl <robin.krahl@ireas.org>2018-05-22 00:01:54 +0200
commit9428ce3221209828b8cff0e34957ebb9b10b2d99 (patch)
tree94fb08204694966d6db1a487add706c7fedc85a9
parent3472841949caacadeec92dbf80eca13fd2171f5c (diff)
downloadnitrokey-rs-9428ce3221209828b8cff0e34957ebb9b10b2d99.tar.gz
nitrokey-rs-9428ce3221209828b8cff0e34957ebb9b10b2d99.tar.bz2
Correct invalid slot handling
While the Nitrokey device would generate a WrongSlot error, libnitrokey catches these errors and raises an InvalidSlotException with error code 201. This patch matches this error code to CommandError::InvalidSlot, corrects the documentation and adds test cases. To be able to test a failing OTP generation command, we have to adapt get_string_result to free the string only if successful. This is due to the segfault issue in libnitrokey v3.3 (see todo list).
-rw-r--r--src/lib.rs28
-rw-r--r--src/tests/pro.rs34
2 files changed, 47 insertions, 15 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 471d481..117659f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -394,8 +394,8 @@ pub trait Device {
///
/// # Errors
///
+ /// - [`InvalidSlot`][] if there is no slot with the given number
/// - [`SlotNotProgrammed`][] if the given slot is not configured
- /// - [`WrongSlot`][] if there is no slot with the given number
///
/// # Example
///
@@ -413,8 +413,8 @@ pub trait Device {
/// # }
/// ```
///
+ /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
/// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
- /// [`WrongSlot`]: enum.CommandError.html#variant.WrongSlot
fn get_hotp_slot_name(&self, slot: u8) -> Result<String, CommandError> {
unsafe { result_from_string(nitrokey_sys::NK_get_hotp_slot_name(slot)) }
}
@@ -423,8 +423,8 @@ pub trait Device {
///
/// # Errors
///
+ /// - [`InvalidSlot`][] if there is no slot with the given number
/// - [`SlotNotProgrammed`][] if the given slot is not configured
- /// - [`WrongSlot`][] if there is no slot with the given number
///
/// # Example
///
@@ -442,8 +442,8 @@ pub trait Device {
/// # }
/// ```
///
+ /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
/// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
- /// [`WrongSlot`]: enum.CommandError.html#variant.WrongSlot
fn get_totp_slot_name(&self, slot: u8) -> Result<String, CommandError> {
unsafe { result_from_string(nitrokey_sys::NK_get_totp_slot_name(slot)) }
}
@@ -569,9 +569,9 @@ pub trait Device {
///
/// # Errors
///
+ /// - [`InvalidSlot`][] if there is no slot with the given number
/// - [`NotAuthorized`][] if OTP generation requires user authentication
/// - [`SlotNotProgrammed`][] if the given slot is not configured
- /// - [`WrongSlot`][] if there is no slot with the given number
///
/// # Example
///
@@ -588,9 +588,9 @@ pub trait Device {
/// ```
///
/// [`get_config`]: #method.get_config
+ /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
/// [`NotAuthorized`]: enum.CommandError.html#variant.NotAuthorized
/// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
- /// [`WrongSlot`]: enum.CommandError.html#variant.WrongSlot
fn get_hotp_code(&self, slot: u8) -> Result<String, CommandError> {
unsafe {
return result_from_string(nitrokey_sys::NK_get_hotp_code(slot));
@@ -606,9 +606,9 @@ pub trait Device {
///
/// # Errors
///
+ /// - [`InvalidSlot`][] if there is no slot with the given number
/// - [`NotAuthorized`][] if OTP generation requires user authentication
/// - [`SlotNotProgrammed`][] if the given slot is not configured
- /// - [`WrongSlot`][] if there is no slot with the given number
///
/// # Example
///
@@ -626,9 +626,9 @@ pub trait Device {
///
/// [`set_time`]: #method.set_time
/// [`get_config`]: #method.get_config
+ /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
/// [`NotAuthorized`]: enum.CommandError.html#variant.NotAuthorized
/// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
- /// [`WrongSlot`]: enum.CommandError.html#variant.WrongSlot
fn get_totp_code(&self, slot: u8) -> Result<String, CommandError> {
unsafe {
return result_from_string(nitrokey_sys::NK_get_totp_code(slot, 0, 0, 0));
@@ -746,6 +746,7 @@ impl From<c_int> for CommandError {
8 => CommandError::NotSupported,
9 => CommandError::UnknownCommand,
10 => CommandError::AesDecryptionFailed,
+ 201 => CommandError::InvalidSlot,
_ => CommandError::Unknown,
}
}
@@ -799,10 +800,11 @@ fn result_from_string(ptr: *const std::os::raw::c_char) -> Result<String, Comman
}
unsafe {
let s = owned_str_from_ptr(ptr);
- libc::free(ptr as *mut libc::c_void);
if s.is_empty() {
return Err(get_last_error());
}
+ // TODO: move up for newer libnitrokey versions
+ libc::free(ptr as *mut libc::c_void);
return Ok(s);
}
}
@@ -1214,9 +1216,9 @@ impl AdminAuthenticatedDevice {
///
/// # Errors
///
+ /// - [`InvalidSlot`][] if there is no slot with the given number
/// - [`InvalidString`][] if the provided token ID contains a null byte
/// - [`NoName`][] if the provided name is empty
- /// - [`WrongSlot`][] if there is no slot with the given number
///
/// # Example
///
@@ -1240,9 +1242,9 @@ impl AdminAuthenticatedDevice {
/// # }
/// ```
///
+ /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
/// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
/// [`NoName`]: enum.CommandError.html#variant.NoName
- /// [`WrongSlot`]: enum.CommandError.html#variant.WrongSlot
pub fn write_hotp_slot(&self, data: OtpSlotData, counter: u64) -> CommandStatus {
return self.write_otp_slot(data, |raw_data: RawOtpSlotData, temp_password_ptr| unsafe {
nitrokey_sys::NK_write_hotp_slot(
@@ -1264,9 +1266,9 @@ impl AdminAuthenticatedDevice {
///
/// # Errors
///
+ /// - [`InvalidSlot`][] if there is no slot with the given number
/// - [`InvalidString`][] if the provided token ID contains a null byte
/// - [`NoName`][] if the provided name is empty
- /// - [`WrongSlot`][] if there is no slot with the given number
///
/// # Example
///
@@ -1290,9 +1292,9 @@ impl AdminAuthenticatedDevice {
/// # }
/// ```
///
+ /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
/// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
/// [`NoName`]: enum.CommandError.html#variant.NoName
- /// [`WrongSlot`]: enum.CommandError.html#variant.WrongSlot
pub fn write_totp_slot(&self, data: OtpSlotData, time_window: u16) -> CommandStatus {
return self.write_otp_slot(data, |raw_data: RawOtpSlotData, temp_password_ptr| unsafe {
nitrokey_sys::NK_write_totp_slot(
diff --git a/src/tests/pro.rs b/src/tests/pro.rs
index 8394e47..a508801 100644
--- a/src/tests/pro.rs
+++ b/src/tests/pro.rs
@@ -117,8 +117,23 @@ fn hotp_slot_name() {
let slot_data = OtpSlotData::new(1, "test-hotp", HOTP_SECRET, OtpMode::SixDigits);
assert_eq!(CommandStatus::Success, admin.write_hotp_slot(slot_data, 0));
- let result = admin.device().get_hotp_slot_name(1);
+ let device = admin.device();
+ let result = device.get_hotp_slot_name(1);
assert_eq!("test-hotp", result.unwrap());
+ let result = device.get_hotp_slot_name(4);
+ assert_eq!(CommandError::InvalidSlot, result.unwrap_err());
+}
+
+#[test]
+#[cfg_attr(not(feature = "test-pro"), ignore)]
+fn hotp_error() {
+ let admin = get_admin_test_device();
+ let slot_data = OtpSlotData::new(1, "", HOTP_SECRET, OtpMode::SixDigits);
+ assert_eq!(CommandStatus::Error(CommandError::NoName), admin.write_hotp_slot(slot_data, 0));
+ let slot_data = OtpSlotData::new(4, "test", HOTP_SECRET, OtpMode::SixDigits);
+ assert_eq!(CommandStatus::Error(CommandError::InvalidSlot), admin.write_hotp_slot(slot_data, 0));
+ let code = admin.get_hotp_code(4);
+ assert_eq!(CommandError::InvalidSlot, code.unwrap_err());
}
fn configure_totp(admin: &AdminAuthenticatedDevice) {
@@ -181,9 +196,24 @@ fn totp_slot_name() {
let slot_data = OtpSlotData::new(1, "test-totp", TOTP_SECRET, OtpMode::EightDigits);
assert_eq!(CommandStatus::Success, admin.write_totp_slot(slot_data, 0));
- let result = admin.device().get_totp_slot_name(1);
+ let device = admin.device();
+ let result = device.get_totp_slot_name(1);
assert!(result.is_ok());
assert_eq!("test-totp", result.unwrap());
+ let result = device.get_totp_slot_name(16);
+ assert_eq!(CommandError::InvalidSlot, result.unwrap_err());
+}
+
+#[test]
+#[cfg_attr(not(feature = "test-pro"), ignore)]
+fn totp_error() {
+ let admin = get_admin_test_device();
+ let slot_data = OtpSlotData::new(1, "", HOTP_SECRET, OtpMode::SixDigits);
+ assert_eq!(CommandStatus::Error(CommandError::NoName), admin.write_hotp_slot(slot_data, 0));
+ let slot_data = OtpSlotData::new(4, "test", HOTP_SECRET, OtpMode::SixDigits);
+ assert_eq!(CommandStatus::Error(CommandError::InvalidSlot), admin.write_hotp_slot(slot_data, 0));
+ let code = admin.get_hotp_code(4);
+ assert_eq!(CommandError::InvalidSlot, code.unwrap_err());
}
#[test]