aboutsummaryrefslogtreecommitdiff
path: root/nitrokey
diff options
context:
space:
mode:
authorDaniel Mueller <deso@posteo.net>2019-01-16 17:26:30 -0800
committerDaniel Mueller <deso@posteo.net>2019-01-16 17:26:30 -0800
commit8350ac6afb2d678b74581000a6aafe1994b72231 (patch)
tree2330da01a806921b3849c9e64d2b9f506495e2c0 /nitrokey
parentd6652b913b33e432a748187f9f5623cec1e9926e (diff)
downloadnitrocli-8350ac6afb2d678b74581000a6aafe1994b72231.tar.gz
nitrocli-8350ac6afb2d678b74581000a6aafe1994b72231.tar.bz2
Update nitrokey crate to 0.3.3
This change updates the nitrokey crate to version 0.3.3. Along with that change we update rand to 0.6.4 because rand 0.6.1 does not yet contain a publicly accessible rand_os. Note that we no longer require all crates in rand's workspace, but only rand_os and rand_core, which is a significant reduction in the number of lines of code compiled. Import subrepo nitrokey/:nitrokey at 7cf747d56ddc0b7eeedc3caf36dcc909907a171c Import subrepo rand/:rand at 4336232dda03323634b10ec72ddf27914aebc3a2
Diffstat (limited to 'nitrokey')
-rw-r--r--nitrokey/.builds/archlinux-use-system-lib.yaml22
-rw-r--r--nitrokey/.builds/archlinux.yml21
-rw-r--r--nitrokey/CHANGELOG.md9
-rw-r--r--nitrokey/Cargo.toml5
-rw-r--r--nitrokey/TODO.md3
-rw-r--r--nitrokey/src/auth.rs5
-rw-r--r--nitrokey/src/device.rs130
-rw-r--r--nitrokey/src/lib.rs9
-rw-r--r--nitrokey/src/pws.rs29
-rw-r--r--nitrokey/src/util.rs26
-rw-r--r--nitrokey/tests/device.rs57
-rw-r--r--nitrokey/tests/lib.rs3
-rw-r--r--nitrokey/tests/pws.rs23
13 files changed, 299 insertions, 43 deletions
diff --git a/nitrokey/.builds/archlinux-use-system-lib.yaml b/nitrokey/.builds/archlinux-use-system-lib.yaml
new file mode 100644
index 0000000..6fba33a
--- /dev/null
+++ b/nitrokey/.builds/archlinux-use-system-lib.yaml
@@ -0,0 +1,22 @@
+image: archlinux
+packages:
+ - rust
+ - libnitrokey
+environment:
+ USE_SYSTEM_LIBNITROKEY: "1"
+sources:
+ - https://git.sr.ht/~ireas/nitrokey-rs
+tasks:
+ - build: |
+ cd nitrokey-rs
+ cargo build --release
+ - test: |
+ cd nitrokey-rs
+ cargo test
+ - format: |
+ cd nitrokey-rs
+ cargo fmt -- --check
+triggers:
+ - action: email
+ condition: failure
+ to: nitrokey-rs-dev <nitrokey-rs-dev@ireas.org>
diff --git a/nitrokey/.builds/archlinux.yml b/nitrokey/.builds/archlinux.yml
new file mode 100644
index 0000000..9d45386
--- /dev/null
+++ b/nitrokey/.builds/archlinux.yml
@@ -0,0 +1,21 @@
+image: archlinux
+packages:
+ - rust
+ - hidapi
+ - gcc
+sources:
+ - https://git.sr.ht/~ireas/nitrokey-rs
+tasks:
+ - build: |
+ cd nitrokey-rs
+ cargo build --release
+ - test: |
+ cd nitrokey-rs
+ cargo test
+ - format: |
+ cd nitrokey-rs
+ cargo fmt -- --check
+triggers:
+ - action: email
+ condition: failure
+ to: nitrokey-rs-dev <nitrokey-rs-dev@ireas.org>
diff --git a/nitrokey/CHANGELOG.md b/nitrokey/CHANGELOG.md
index 72e6986..3845aaf 100644
--- a/nitrokey/CHANGELOG.md
+++ b/nitrokey/CHANGELOG.md
@@ -1,3 +1,12 @@
+# v0.3.3 (2019-01-16)
+- Add the `get_production_info` and `clear_new_sd_card_warning` methods to the
+ `Storage` struct.
+- Use `rand_os` instead of `rand` for random data creation.
+ - (Re-)add `CommandError::RngError` variant.
+- Account for the possibility that an empty string returned by libnitrokey can
+ not only indicate an error but also be a valid return value.
+- Make test cases more robust and avoid side effects on other test cases.
+
# v0.3.2 (2019-01-12)
- Make three additional error codes known: `CommandError::StringTooLong`,
`CommandError::InvalidHexString` and `CommandError::TargetBufferTooSmall`.
diff --git a/nitrokey/Cargo.toml b/nitrokey/Cargo.toml
index 09811f0..802d022 100644
--- a/nitrokey/Cargo.toml
+++ b/nitrokey/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "nitrokey"
-version = "0.3.2"
+version = "0.3.3"
authors = ["Robin Krahl <robin.krahl@ireas.org>"]
edition = "2018"
homepage = "https://code.ireas.org/nitrokey-rs/"
@@ -19,7 +19,8 @@ test-storage = []
[dependencies]
libc = "0.2"
nitrokey-sys = "3.4"
-rand = "0.6"
+rand_core = {version = "0.3", default-features = false}
+rand_os = {version = "0.1"}
[dev-dependencies]
nitrokey-test = {version = "0.1"}
diff --git a/nitrokey/TODO.md b/nitrokey/TODO.md
index 7c8c5e6..28bd3b8 100644
--- a/nitrokey/TODO.md
+++ b/nitrokey/TODO.md
@@ -1,19 +1,16 @@
- Add support for the currently unsupported commands:
- `NK_is_AES_supported`
- `NK_send_startup`
- - `NK_clear_new_sd_card_warning`
- `NK_fill_SD_card_with_random_data`
- `NK_get_SD_usage_data_as_string`
- `NK_get_progress_bar_value`
- `NK_list_devices_by_cpuID`
- `NK_connect_with_ID`
- - `NK_get_storage_production_info`
- Fix timing issues with the `totp_no_pin` and `totp_pin` test cases.
- Clear passwords from memory.
- Find a nicer syntax for the `write_config` test.
- Prevent construction of internal types.
- More specific error checking in the tests.
-- Differentiate empty strings and errors (see `result_from_string`).
- Check integer conversions.
- Consider implementing `Into<CommandError>` for `(Device, CommandError)`
- Lock password safe in `PasswordSafe::drop()` (see [nitrokey-storage-firmware
diff --git a/nitrokey/src/auth.rs b/nitrokey/src/auth.rs
index a129bd8..3280924 100644
--- a/nitrokey/src/auth.rs
+++ b/nitrokey/src/auth.rs
@@ -149,7 +149,10 @@ where
A: AuthenticatedDevice<D>,
T: Fn(*const i8, *const i8) -> c_int,
{
- let temp_password = generate_password(TEMPORARY_PASSWORD_LENGTH);
+ let temp_password = match generate_password(TEMPORARY_PASSWORD_LENGTH) {
+ Ok(temp_password) => temp_password,
+ Err(err) => return Err((device, err)),
+ };
let password = match get_cstring(password) {
Ok(password) => password,
Err(err) => return Err((device, err)),
diff --git a/nitrokey/src/device.rs b/nitrokey/src/device.rs
index f247f58..9813c50 100644
--- a/nitrokey/src/device.rs
+++ b/nitrokey/src/device.rs
@@ -208,6 +208,38 @@ pub struct VolumeStatus {
pub active: bool,
}
+/// Information about the SD card in a Storage device.
+#[derive(Debug)]
+pub struct SdCardData {
+ /// The serial number of the SD card.
+ pub serial_number: u32,
+ /// The size of the SD card in GB.
+ pub size: u8,
+ /// The year the card was manufactured, e. g. 17 for 2017.
+ pub manufacturing_year: u8,
+ /// The month the card was manufactured.
+ pub manufacturing_month: u8,
+ /// The OEM ID.
+ pub oem: u16,
+ /// The manufacturer ID.
+ pub manufacturer: u8,
+}
+
+#[derive(Debug)]
+/// Production information for a Storage device.
+pub struct StorageProductionInfo {
+ /// The major firmware version, e. g. 0 in v0.40.
+ pub firmware_version_major: u8,
+ /// The minor firmware version, e. g. 40 in v0.40.
+ pub firmware_version_minor: u8,
+ /// The internal firmware version.
+ pub firmware_version_internal: u8,
+ /// The serial number of the CPU.
+ pub serial_number_cpu: u32,
+ /// Information about the SD card.
+ pub sd_card: SdCardData,
+}
+
/// The status of a Nitrokey Storage device.
#[derive(Debug)]
pub struct StorageStatus {
@@ -566,7 +598,7 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// The AES key is used to encrypt the password safe and the encrypted volume. You may need
/// to call this method after a factory reset, either using [`factory_reset`][] or using `gpg
- /// --card-edit`. You can also use it to destory the data stored in the password safe or on
+ /// --card-edit`. You can also use it to destroy the data stored in the password safe or on
/// the encrypted volume.
///
/// # Errors
@@ -1166,6 +1198,83 @@ impl Storage {
result.and(Ok(StorageStatus::from(raw_status)))
}
+ /// Returns the production information for the connected storage device.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// # use nitrokey::CommandError;
+ ///
+ /// fn use_volume() {}
+ ///
+ /// # fn try_main() -> Result<(), CommandError> {
+ /// let device = nitrokey::Storage::connect()?;
+ /// match device.get_production_info() {
+ /// Ok(data) => {
+ /// println!("SD card ID: {:#x}", data.sd_card.serial_number);
+ /// println!("SD card size: {} GB", data.sd_card.size);
+ /// },
+ /// Err(err) => println!("Could not get Storage production info: {}", err),
+ /// };
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn get_production_info(&self) -> Result<StorageProductionInfo, CommandError> {
+ let mut raw_data = nitrokey_sys::NK_storage_ProductionTest {
+ FirmwareVersion_au8: [0, 2],
+ FirmwareVersionInternal_u8: 0,
+ SD_Card_Size_u8: 0,
+ CPU_CardID_u32: 0,
+ SmartCardID_u32: 0,
+ SD_CardID_u32: 0,
+ SC_UserPwRetryCount: 0,
+ SC_AdminPwRetryCount: 0,
+ SD_Card_ManufacturingYear_u8: 0,
+ SD_Card_ManufacturingMonth_u8: 0,
+ SD_Card_OEM_u16: 0,
+ SD_WriteSpeed_u16: 0,
+ SD_Card_Manufacturer_u8: 0,
+ };
+ let raw_result = unsafe { nitrokey_sys::NK_get_storage_production_info(&mut raw_data) };
+ let result = get_command_result(raw_result);
+ result.and(Ok(StorageProductionInfo::from(raw_data)))
+ }
+
+ /// Clears the warning for a new SD card.
+ ///
+ /// The Storage status contains a field for a new SD card warning. After a factory reset, the
+ /// field is set to true. After filling the SD card with random data, it is set to false.
+ /// This method can be used to set it to false without filling the SD card with random data.
+ ///
+ /// # Errors
+ ///
+ /// - [`InvalidString`][] if the provided password contains a null byte
+ /// - [`WrongPassword`][] if the provided admin password is wrong
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// # use nitrokey::CommandError;
+ ///
+ /// # fn try_main() -> Result<(), CommandError> {
+ /// let device = nitrokey::Storage::connect()?;
+ /// match device.clear_new_sd_card_warning("12345678") {
+ /// Ok(()) => println!("Cleared the new SD card warning."),
+ /// Err(err) => println!("Could not set the clear the new SD card warning: {}", err),
+ /// };
+ /// # Ok(())
+ /// # }
+ /// ```
+ ///
+ /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
+ pub fn clear_new_sd_card_warning(&self, admin_pin: &str) -> Result<(), CommandError> {
+ let admin_pin = get_cstring(admin_pin)?;
+ get_command_result(unsafe {
+ nitrokey_sys::NK_clear_new_sd_card_warning(admin_pin.as_ptr())
+ })
+ }
+
/// Blinks the red and green LED alternatively and infinitely until the device is reconnected.
pub fn wink(&self) -> Result<(), CommandError> {
get_command_result(unsafe { nitrokey_sys::NK_wink() })
@@ -1209,6 +1318,25 @@ impl Device for Storage {
impl GenerateOtp for Storage {}
+impl From<nitrokey_sys::NK_storage_ProductionTest> for StorageProductionInfo {
+ fn from(data: nitrokey_sys::NK_storage_ProductionTest) -> Self {
+ Self {
+ firmware_version_major: data.FirmwareVersion_au8[0],
+ firmware_version_minor: data.FirmwareVersion_au8[1],
+ firmware_version_internal: data.FirmwareVersionInternal_u8,
+ serial_number_cpu: data.CPU_CardID_u32,
+ sd_card: SdCardData {
+ serial_number: data.SD_CardID_u32,
+ size: data.SD_Card_Size_u8,
+ manufacturing_year: data.SD_Card_ManufacturingYear_u8,
+ manufacturing_month: data.SD_Card_ManufacturingMonth_u8,
+ oem: data.SD_Card_OEM_u16,
+ manufacturer: data.SD_Card_Manufacturer_u8,
+ },
+ }
+ }
+}
+
impl From<nitrokey_sys::NK_storage_status> for StorageStatus {
fn from(status: nitrokey_sys::NK_storage_status) -> Self {
StorageStatus {
diff --git a/nitrokey/src/lib.rs b/nitrokey/src/lib.rs
index c50b713..02a622b 100644
--- a/nitrokey/src/lib.rs
+++ b/nitrokey/src/lib.rs
@@ -98,8 +98,8 @@ use nitrokey_sys;
pub use crate::auth::{Admin, Authenticate, User};
pub use crate::config::Config;
pub use crate::device::{
- connect, connect_model, Device, DeviceWrapper, Model, Pro, Storage, StorageStatus, VolumeMode,
- VolumeStatus,
+ connect, connect_model, Device, DeviceWrapper, Model, Pro, SdCardData, Storage,
+ StorageProductionInfo, StorageStatus, VolumeMode, VolumeStatus,
};
pub use crate::otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData};
pub use crate::pws::{GetPasswordSafe, PasswordSafe, SLOT_COUNT};
@@ -111,12 +111,13 @@ pub use crate::util::{CommandError, LogLevel};
/// version.
#[derive(Clone, Debug, PartialEq)]
pub struct Version {
- /// The library version as a string.
+ /// The Git library version as a string.
///
/// The library version is the output of `git describe --always` at compile time, for example
/// `v3.3` or `v3.4.1`. If the library has not been built from a release, the version string
/// contains the number of commits since the last release and the hash of the current commit, for
- /// example `v3.3-19-gaee920b`.
+ /// example `v3.3-19-gaee920b`. If the library has not been built from a Git checkout, this
+ /// string may be empty.
pub git: String,
/// The major library version.
pub major: u32,
diff --git a/nitrokey/src/pws.rs b/nitrokey/src/pws.rs
index ebd5fcd..28f0681 100644
--- a/nitrokey/src/pws.rs
+++ b/nitrokey/src/pws.rs
@@ -129,6 +129,14 @@ fn get_password_safe<'a>(
result.map(|()| PasswordSafe { _device: device })
}
+fn get_pws_result(s: String) -> Result<String, CommandError> {
+ if s.is_empty() {
+ Err(CommandError::SlotNotProgrammed)
+ } else {
+ Ok(s)
+ }
+}
+
impl<'a> PasswordSafe<'a> {
/// Returns the status of all password slots.
///
@@ -172,10 +180,12 @@ impl<'a> PasswordSafe<'a> {
/// Returns the name of the given slot (if it is programmed).
///
+ /// This method also returns a `SlotNotProgrammed` error if the name is empty.
+ ///
/// # Errors
///
/// - [`InvalidSlot`][] if the given slot is out of range
- /// - [`Undefined`][] if the slot is not programmed
+ /// - [`SlotNotProgrammed`][] if the slot is not programmed
///
/// # Example
///
@@ -199,17 +209,20 @@ impl<'a> PasswordSafe<'a> {
/// ```
///
/// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
- /// [`Undefined`]: enum.CommandError.html#variant.Undefined
+ /// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
pub fn get_slot_name(&self, slot: u8) -> Result<String, CommandError> {
unsafe { result_from_string(nitrokey_sys::NK_get_password_safe_slot_name(slot)) }
+ .and_then(get_pws_result)
}
/// Returns the login for the given slot (if it is programmed).
///
+ /// This method also returns a `SlotNotProgrammed` error if the login is empty.
+ ///
/// # Errors
///
/// - [`InvalidSlot`][] if the given slot is out of range
- /// - [`Undefined`][] if the slot is not programmed
+ /// - [`SlotNotProgrammed`][] if the slot is not programmed
///
/// # Example
///
@@ -229,17 +242,20 @@ impl<'a> PasswordSafe<'a> {
/// ```
///
/// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
- /// [`Undefined`]: enum.CommandError.html#variant.Undefined
+ /// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
pub fn get_slot_login(&self, slot: u8) -> Result<String, CommandError> {
unsafe { result_from_string(nitrokey_sys::NK_get_password_safe_slot_login(slot)) }
+ .and_then(get_pws_result)
}
/// Returns the password for the given slot (if it is programmed).
///
+ /// This method also returns a `SlotNotProgrammed` error if the password is empty.
+ ///
/// # Errors
///
/// - [`InvalidSlot`][] if the given slot is out of range
- /// - [`Undefined`][] if the slot is not programmed
+ /// - [`SlotNotProgrammed`][] if the slot is not programmed
///
/// # Example
///
@@ -259,9 +275,10 @@ impl<'a> PasswordSafe<'a> {
/// ```
///
/// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
- /// [`Undefined`]: enum.CommandError.html#variant.Undefined
+ /// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
pub fn get_slot_password(&self, slot: u8) -> Result<String, CommandError> {
unsafe { result_from_string(nitrokey_sys::NK_get_password_safe_slot_password(slot)) }
+ .and_then(get_pws_result)
}
/// Writes the given slot with the given name, login and password.
diff --git a/nitrokey/src/util.rs b/nitrokey/src/util.rs
index cb109d0..567c478 100644
--- a/nitrokey/src/util.rs
+++ b/nitrokey/src/util.rs
@@ -4,7 +4,8 @@ use std::fmt;
use std::os::raw::{c_char, c_int};
use libc::{c_void, free};
-use rand::Rng;
+use rand_core::RngCore;
+use rand_os::OsRng;
/// Error types returned by Nitrokey device or by the library.
#[derive(Clone, Copy, Debug, PartialEq)]
@@ -44,6 +45,8 @@ pub enum CommandError {
InvalidHexString,
/// The target buffer was smaller than the source.
TargetBufferTooSmall,
+ /// An error occurred during random number generation.
+ RngError,
}
/// Log level for libnitrokey.
@@ -80,10 +83,13 @@ pub fn result_from_string(ptr: *const c_char) -> Result<String, CommandError> {
unsafe {
let s = owned_str_from_ptr(ptr);
free(ptr as *mut c_void);
+ // An empty string can both indicate an error or be a valid return value. In this case, we
+ // have to check the last command status to decide what to return.
if s.is_empty() {
- return Err(get_last_error());
+ get_last_result().map(|_| s)
+ } else {
+ Ok(s)
}
- return Ok(s);
}
}
@@ -106,10 +112,11 @@ pub fn get_last_error() -> CommandError {
};
}
-pub fn generate_password(length: usize) -> Vec<u8> {
+pub fn generate_password(length: usize) -> Result<Vec<u8>, CommandError> {
+ let mut rng = OsRng::new()?;
let mut data = vec![0u8; length];
- rand::thread_rng().fill(&mut data[..]);
- return data;
+ rng.fill_bytes(&mut data[..]);
+ Ok(data)
}
pub fn get_cstring<T: Into<Vec<u8>>>(s: T) -> Result<CString, CommandError> {
@@ -146,6 +153,7 @@ impl CommandError {
"The supplied string is not in hexadecimal format".into()
}
CommandError::TargetBufferTooSmall => "The target buffer is too small".into(),
+ CommandError::RngError => "An error occurred during random number generation".into(),
}
}
}
@@ -178,6 +186,12 @@ impl From<c_int> for CommandError {
}
}
+impl From<rand_core::Error> for CommandError {
+ fn from(_error: rand_core::Error) -> Self {
+ CommandError::RngError
+ }
+}
+
impl Into<i32> for LogLevel {
fn into(self) -> i32 {
match self {
diff --git a/nitrokey/tests/device.rs b/nitrokey/tests/device.rs
index e40ae12..849d2ff 100644
--- a/nitrokey/tests/device.rs
+++ b/nitrokey/tests/device.rs
@@ -260,6 +260,15 @@ fn unlock_user_pin(device: DeviceWrapper) {
#[test_device]
fn factory_reset(device: DeviceWrapper) {
+ let admin = device.authenticate_admin(ADMIN_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_PASSWORD).unwrap();
+ assert_eq!(Ok(()), pws.write_slot(0, "test", "testlogin", "testpw"));
+ drop(pws);
+
assert_eq!(
Ok(()),
device.change_user_pin(USER_PASSWORD, USER_NEW_PASSWORD)
@@ -269,15 +278,6 @@ fn factory_reset(device: DeviceWrapper) {
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)
@@ -439,6 +439,45 @@ fn get_storage_status(device: Storage) {
}
#[test_device]
+fn get_production_info(device: Storage) {
+ let info = device.get_production_info().unwrap();
+ assert_eq!(0, info.firmware_version_major);
+ assert!(info.firmware_version_minor != 0);
+ assert!(info.serial_number_cpu != 0);
+ assert!(info.sd_card.serial_number != 0);
+ assert!(info.sd_card.size > 0);
+ assert!(info.sd_card.manufacturing_year > 10);
+ assert!(info.sd_card.manufacturing_year < 100);
+ // TODO: month value is not valid atm
+ // assert!(info.sd_card.manufacturing_month < 12);
+ assert!(info.sd_card.oem != 0);
+ assert!(info.sd_card.manufacturer != 0);
+
+ let status = device.get_status().unwrap();
+ assert_eq!(status.firmware_version_major, info.firmware_version_major);
+ assert_eq!(status.firmware_version_minor, info.firmware_version_minor);
+ assert_eq!(status.serial_number_sd_card, info.sd_card.serial_number);
+}
+
+#[test_device]
+fn clear_new_sd_card_warning(device: Storage) {
+ assert_eq!(Ok(()), device.factory_reset(ADMIN_PASSWORD));
+ thread::sleep(time::Duration::from_secs(3));
+ assert_eq!(Ok(()), device.build_aes_key(ADMIN_PASSWORD));
+
+ // We have to perform an SD card operation to reset the new_sd_card_found field
+ assert_eq!(Ok(()), device.lock());
+
+ let status = device.get_status().unwrap();
+ assert!(status.new_sd_card_found);
+
+ assert_eq!(Ok(()), device.clear_new_sd_card_warning(ADMIN_PASSWORD));
+
+ let status = device.get_status().unwrap();
+ assert!(!status.new_sd_card_found);
+}
+
+#[test_device]
fn export_firmware(device: Storage) {
assert_eq!(
Err(CommandError::WrongPassword),
diff --git a/nitrokey/tests/lib.rs b/nitrokey/tests/lib.rs
index 06de0ad..c92e224 100644
--- a/nitrokey/tests/lib.rs
+++ b/nitrokey/tests/lib.rs
@@ -2,7 +2,6 @@
fn get_library_version() {
let version = nitrokey::get_library_version();
- assert!(!version.git.is_empty());
- assert!(version.git.starts_with("v"));
+ assert!(version.git.is_empty() || version.git.starts_with("v"));
assert!(version.major > 0);
}
diff --git a/nitrokey/tests/pws.rs b/nitrokey/tests/pws.rs
index b349558..fbcc0c1 100644
--- a/nitrokey/tests/pws.rs
+++ b/nitrokey/tests/pws.rs
@@ -20,7 +20,7 @@ fn get_slot_name_direct(slot: u8) -> Result<String, CommandError> {
true => {
let error = unsafe { nitrokey_sys::NK_get_last_command_status() } as c_int;
match error {
- 0 => Err(CommandError::Undefined),
+ 0 => Ok(s),
other => Err(CommandError::from(other)),
}
}
@@ -92,10 +92,12 @@ fn get_data(device: DeviceWrapper) {
assert_eq!("password", pws.get_slot_password(1).unwrap());
assert_eq!(Ok(()), pws.erase_slot(1));
- // TODO: check error codes
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_name(1));
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_login(1));
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_password(1));
+ assert_eq!(Err(CommandError::SlotNotProgrammed), pws.get_slot_name(1));
+ assert_eq!(Err(CommandError::SlotNotProgrammed), pws.get_slot_login(1));
+ assert_eq!(
+ Err(CommandError::SlotNotProgrammed),
+ pws.get_slot_password(1)
+ );
let name = "with å";
let login = "pär@test.com";
@@ -129,19 +131,22 @@ fn write(device: DeviceWrapper) {
);
assert_eq!(Ok(()), pws.write_slot(0, "", "login", "password"));
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_name(0));
+ assert_eq!(Err(CommandError::SlotNotProgrammed), pws.get_slot_name(0));
assert_eq!(Ok(String::from("login")), pws.get_slot_login(0));
assert_eq!(Ok(String::from("password")), pws.get_slot_password(0));
assert_eq!(Ok(()), pws.write_slot(0, "name", "", "password"));
assert_eq!(Ok(String::from("name")), pws.get_slot_name(0));
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_login(0));
+ assert_eq!(Err(CommandError::SlotNotProgrammed), pws.get_slot_login(0));
assert_eq!(Ok(String::from("password")), pws.get_slot_password(0));
assert_eq!(Ok(()), pws.write_slot(0, "name", "login", ""));
assert_eq!(Ok(String::from("name")), pws.get_slot_name(0));
assert_eq!(Ok(String::from("login")), pws.get_slot_login(0));
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_password(0));
+ assert_eq!(
+ Err(CommandError::SlotNotProgrammed),
+ pws.get_slot_password(0)
+ );
}
#[test_device]
@@ -152,5 +157,5 @@ fn erase(device: DeviceWrapper) {
assert_eq!(Ok(()), pws.write_slot(0, "name", "login", "password"));
assert_eq!(Ok(()), pws.erase_slot(0));
assert_eq!(Ok(()), pws.erase_slot(0));
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_name(0));
+ assert_eq!(Err(CommandError::SlotNotProgrammed), pws.get_slot_name(0));
}