From c74b8b3ea8dc4fe7c6891ae120540f8da5623227 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Sun, 29 Dec 2019 12:51:28 +0100 Subject: Add list_devices function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for libnitrokey’s NK_list_devices function by introducing the top-level list_devices function. It returns a vector of DeviceInfo structs with information about all connected Nitrokey devices. --- tests/device.rs | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) (limited to 'tests/device.rs') diff --git a/tests/device.rs b/tests/device.rs index e367558..5e60002 100644 --- a/tests/device.rs +++ b/tests/device.rs @@ -8,8 +8,8 @@ use std::process::Command; use std::{thread, time}; use nitrokey::{ - Authenticate, CommandError, CommunicationError, Config, ConfigureOtp, Device, Error, - GenerateOtp, GetPasswordSafe, LibraryError, OtpMode, OtpSlotData, Storage, VolumeMode, + Authenticate, CommandError, CommunicationError, Config, ConfigureOtp, Device, DeviceInfo, + Error, GenerateOtp, GetPasswordSafe, LibraryError, OtpMode, OtpSlotData, Storage, VolumeMode, DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN, }; use nitrokey_test::test as test_device; @@ -31,6 +31,33 @@ fn count_nitrokey_block_devices() -> usize { .count() } +#[test_device] +fn list_no_devices() { + let devices = nitrokey::list_devices(); + assert_ok!(Vec::::new(), devices); +} + +#[test_device] +fn list_devices(_device: DeviceWrapper) { + let devices = unwrap_ok!(nitrokey::list_devices()); + for device in devices { + assert!(!device.path.is_empty()); + if let Some(model) = device.model { + match model { + nitrokey::Model::Pro => { + assert!(device.serial_number.is_some()); + let serial_number = device.serial_number.unwrap(); + assert!(!serial_number.is_empty()); + assert_valid_serial_number(&serial_number); + }, + nitrokey::Model::Storage => { + assert_eq!(None, device.serial_number); + }, + } + } + } +} + #[test_device] fn connect_no_device() { let mut manager = unwrap_ok!(nitrokey::take()); @@ -83,12 +110,17 @@ fn disconnect(device: DeviceWrapper) { assert_empty_serial_number(); } +fn assert_valid_serial_number(serial_number: &str) { + assert!(serial_number.is_ascii()); + assert!(serial_number.chars().all(|c| c.is_ascii_hexdigit())); +} + #[test_device] fn get_serial_number(device: DeviceWrapper) { let serial_number = unwrap_ok!(device.get_serial_number()); - assert!(serial_number.is_ascii()); - assert!(serial_number.chars().all(|c| c.is_ascii_hexdigit())); + assert_valid_serial_number(&serial_number); } + #[test_device] fn get_firmware_version(device: Pro) { let version = unwrap_ok!(device.get_firmware_version()); -- cgit v1.2.1 From 97c772724dd1fe395e7154e0d71c3b2408436082 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Sun, 29 Dec 2019 13:15:04 +0100 Subject: Add the connect_path function to the Manager struct This patch adds the connect_path function to the Manager struct that uses NK_connect_with_path to connect to a Nitrokey device at a given USB path. --- tests/device.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) (limited to 'tests/device.rs') diff --git a/tests/device.rs b/tests/device.rs index 5e60002..509763b 100644 --- a/tests/device.rs +++ b/tests/device.rs @@ -49,10 +49,10 @@ fn list_devices(_device: DeviceWrapper) { let serial_number = device.serial_number.unwrap(); assert!(!serial_number.is_empty()); assert_valid_serial_number(&serial_number); - }, + } nitrokey::Model::Storage => { assert_eq!(None, device.serial_number); - }, + } } } } @@ -104,6 +104,49 @@ fn assert_empty_serial_number() { } } +#[test_device] +fn connect_path_no_device() { + let mut manager = unwrap_ok!(nitrokey::take()); + + assert_cmu_err!(CommunicationError::NotConnected, manager.connect_path("")); + assert_cmu_err!( + CommunicationError::NotConnected, + manager.connect_path("foobar") + ); + // TODO: add realistic path +} + +#[test_device] +fn connect_path(device: DeviceWrapper) { + let manager = device.into_manager(); + + assert_cmu_err!(CommunicationError::NotConnected, manager.connect_path("")); + assert_cmu_err!( + CommunicationError::NotConnected, + manager.connect_path("foobar") + ); + // TODO: add realistic path + + let devices = unwrap_ok!(nitrokey::list_devices()); + assert!(!devices.is_empty()); + for device in devices { + let connected_device = unwrap_ok!(manager.connect_path(device.path)); + assert_eq!(device.model, Some(connected_device.get_model())); + match device.model.unwrap() { + nitrokey::Model::Pro => { + assert!(device.serial_number.is_some()); + assert_ok!( + device.serial_number.unwrap(), + connected_device.get_serial_number() + ); + } + nitrokey::Model::Storage => { + assert_eq!(None, device.serial_number); + } + } + } +} + #[test_device] fn disconnect(device: DeviceWrapper) { drop(device); -- cgit v1.2.1 From dbee55efa41496c8a683bfab96163facc93d6639 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Sat, 11 Jan 2020 20:05:39 +0100 Subject: Add support for the GET_STATUS command This patch adds support for the GET_STATUS command that returns the status information common to all Nitrokey devices. It can be accessed using the Device::get_status function and is stored in a Status struct. Due to a bug in the Storage firmware [0], the GET_STATUS command returns wrong firmware versions and serial numbers. Until this is fixed in libnitrokey [1], we have to manually execute the GET_DEVICE_STATUS command to fix these values for the Nitrokey Storage. Also, this leads to a name clash with the existing Storage::get_status function, which will be renamed in an upcoming patch. [0] https://github.com/Nitrokey/nitrokey-storage-firmware/issues/96 [1] https://github.com/Nitrokey/libnitrokey/issues/166 --- tests/device.rs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tests/device.rs') diff --git a/tests/device.rs b/tests/device.rs index 509763b..92b79bd 100644 --- a/tests/device.rs +++ b/tests/device.rs @@ -153,6 +153,15 @@ fn disconnect(device: DeviceWrapper) { assert_empty_serial_number(); } +#[test_device] +fn get_status(device: DeviceWrapper) { + let status = unwrap_ok!(device.get_status()); + assert_ok!(status.firmware_version, device.get_firmware_version()); + let serial_number = format!("{:08x}", status.serial_number); + assert_ok!(serial_number, device.get_serial_number()); + assert_ok!(status.config, device.get_config()); +} + fn assert_valid_serial_number(serial_number: &str) { assert!(serial_number.is_ascii()); assert!(serial_number.chars().all(|c| c.is_ascii_hexdigit())); -- cgit v1.2.1 From 6142752da1563c1ab873dc7069aeec72522cca99 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Sat, 11 Jan 2020 20:13:22 +0100 Subject: Rename Status::get_status to get_storage_status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the last patch, we added the get_status function to the Device trait. This patch renames the Storage::get_status function to get_storage_status to resolve the name clash – though allowed by the compiler, it is rather confusing for the end user. --- tests/device.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'tests/device.rs') diff --git a/tests/device.rs b/tests/device.rs index 92b79bd..f2a7031 100644 --- a/tests/device.rs +++ b/tests/device.rs @@ -564,7 +564,7 @@ fn set_encrypted_volume_mode(device: Storage) { #[test_device] fn set_unencrypted_volume_mode(device: Storage) { fn assert_mode(device: &Storage, mode: VolumeMode) { - let status = unwrap_ok!(device.get_status()); + let status = unwrap_ok!(device.get_storage_status()); assert_eq!( status.unencrypted_volume.read_only, mode == VolumeMode::ReadOnly @@ -595,7 +595,7 @@ fn set_unencrypted_volume_mode(device: Storage) { #[test_device] fn get_storage_status(device: Storage) { - let status = unwrap_ok!(device.get_status()); + let status = unwrap_ok!(device.get_storage_status()); assert!(status.serial_number_sd_card > 0); assert!(status.serial_number_smart_card > 0); } @@ -615,7 +615,7 @@ fn get_production_info(device: Storage) { assert!(info.sd_card.oem != 0); assert!(info.sd_card.manufacturer != 0); - let status = unwrap_ok!(device.get_status()); + let status = unwrap_ok!(device.get_storage_status()); assert_eq!(status.firmware_version, info.firmware_version); assert_eq!(status.serial_number_sd_card, info.sd_card.serial_number); } @@ -630,12 +630,12 @@ fn clear_new_sd_card_warning(device: Storage) { // We have to perform an SD card operation to reset the new_sd_card_found field assert_ok!((), device.lock()); - let status = unwrap_ok!(device.get_status()); + let status = unwrap_ok!(device.get_storage_status()); assert!(status.new_sd_card_found); assert_ok!((), device.clear_new_sd_card_warning(DEFAULT_ADMIN_PIN)); - let status = unwrap_ok!(device.get_status()); + let status = unwrap_ok!(device.get_storage_status()); assert!(!status.new_sd_card_found); } -- cgit v1.2.1 From 73c8aebac338d3454d7e345ffd687324317077ec Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 14 Jan 2020 12:00:15 +0100 Subject: Add the get_sd_card_usage function to the Storage struct This patch adds support for the NK_get_SD_usage_data function. It returns a range of the SD card that has not been accessed during this power cycle. --- tests/device.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'tests/device.rs') diff --git a/tests/device.rs b/tests/device.rs index f2a7031..070f3c1 100644 --- a/tests/device.rs +++ b/tests/device.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2018-2019 Robin Krahl +// Copyright (C) 2018-2020 Robin Krahl // SPDX-License-Identifier: MIT mod util; @@ -639,6 +639,14 @@ fn clear_new_sd_card_warning(device: Storage) { assert!(!status.new_sd_card_found); } +#[test_device] +fn get_sd_card_usage(device: Storage) { + let range = unwrap_ok!(device.get_sd_card_usage()); + + assert!(range.end >= range.start); + assert!(range.end <= 100); +} + #[test_device] fn export_firmware(device: Storage) { let mut device = device; -- cgit v1.2.1 From f266ea63039c87886f871b068ef3dcdf851a1eca Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 14 Jan 2020 13:48:56 +0100 Subject: Add the get_operation_status function to the Storage struct This patch adds support for the NK_get_progress_bar_value function: It adds the OperationStatus enum that stores the return value of this command and adds the get_operation_status function to the Storage struct that executes the command. --- tests/device.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'tests/device.rs') diff --git a/tests/device.rs b/tests/device.rs index 070f3c1..7296372 100644 --- a/tests/device.rs +++ b/tests/device.rs @@ -9,8 +9,8 @@ use std::{thread, time}; use nitrokey::{ Authenticate, CommandError, CommunicationError, Config, ConfigureOtp, Device, DeviceInfo, - Error, GenerateOtp, GetPasswordSafe, LibraryError, OtpMode, OtpSlotData, Storage, VolumeMode, - DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN, + Error, GenerateOtp, GetPasswordSafe, LibraryError, OperationStatus, OtpMode, OtpSlotData, + Storage, VolumeMode, DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN, }; use nitrokey_test::test as test_device; @@ -647,6 +647,11 @@ fn get_sd_card_usage(device: Storage) { assert!(range.end <= 100); } +#[test_device] +fn get_operation_status(device: Storage) { + assert_ok!(OperationStatus::Idle, device.get_operation_status()); +} + #[test_device] fn export_firmware(device: Storage) { let mut device = device; -- cgit v1.2.1 From 2e543445c3059fa9decdbef718caf84696bb8786 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 14 Jan 2020 16:15:40 +0100 Subject: Add the fill_sd_card function to Storage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for libnitrokey’s NK_fill_SD_card_with_random_data function. It is executed by the fill_sd_card function of the Storage struct. We also add a new test case that is set to ignore because it takes between 30 and 60 minutes to run. --- tests/device.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'tests/device.rs') diff --git a/tests/device.rs b/tests/device.rs index 7296372..a88c956 100644 --- a/tests/device.rs +++ b/tests/device.rs @@ -652,6 +652,45 @@ fn get_operation_status(device: Storage) { assert_ok!(OperationStatus::Idle, device.get_operation_status()); } +#[test_device] +#[ignore] +fn fill_sd_card(device: Storage) { + // This test takes up to 60 min to execute and is therefore ignored by default. Use `cargo + // test -- --ignored fill_sd_card` to run the test. + + let mut device = device; + assert_ok!((), device.factory_reset(DEFAULT_ADMIN_PIN)); + thread::sleep(time::Duration::from_secs(3)); + assert_ok!((), device.build_aes_key(DEFAULT_ADMIN_PIN)); + + let status = unwrap_ok!(device.get_storage_status()); + assert!(!status.filled_with_random); + + assert_ok!((), device.fill_sd_card(DEFAULT_ADMIN_PIN)); + assert_cmd_err!(CommandError::WrongCrc, device.get_status()); + + let mut status = OperationStatus::Ongoing(0); + let mut last_progress = 0u8; + while status != OperationStatus::Idle { + status = unwrap_ok!(device.get_operation_status()); + if let OperationStatus::Ongoing(progress) = status { + assert!(progress <= 100, "progress = {}", progress); + assert!( + progress >= last_progress, + "progress = {}, last_progress = {}", + progress, + last_progress + ); + last_progress = progress; + + thread::sleep(time::Duration::from_secs(10)); + } + } + + let status = unwrap_ok!(device.get_storage_status()); + assert!(status.filled_with_random); +} + #[test_device] fn export_firmware(device: Storage) { let mut device = device; -- cgit v1.2.1