diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/device.rs | 481 | ||||
-rw-r--r-- | tests/lib.rs | 23 | ||||
-rw-r--r-- | tests/otp.rs | 253 | ||||
-rw-r--r-- | tests/pws.rs | 172 | ||||
-rw-r--r-- | tests/util/mod.rs | 115 |
5 files changed, 619 insertions, 425 deletions
diff --git a/tests/device.rs b/tests/device.rs index 849d2ff..e367558 100644 --- a/tests/device.rs +++ b/tests/device.rs @@ -1,3 +1,6 @@ +// Copyright (C) 2018-2019 Robin Krahl <robin.krahl@ireas.org> +// SPDX-License-Identifier: MIT + mod util; use std::ffi::CStr; @@ -5,13 +8,12 @@ use std::process::Command; use std::{thread, time}; use nitrokey::{ - Authenticate, CommandError, Config, ConfigureOtp, Device, GenerateOtp, GetPasswordSafe, - OtpMode, OtpSlotData, Storage, VolumeMode, + Authenticate, CommandError, CommunicationError, Config, ConfigureOtp, Device, Error, + GenerateOtp, GetPasswordSafe, LibraryError, OtpMode, OtpSlotData, Storage, VolumeMode, + DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN, }; use nitrokey_test::test as test_device; -use crate::util::{ADMIN_PASSWORD, USER_PASSWORD}; - static ADMIN_NEW_PASSWORD: &str = "1234567890"; static UPDATE_PIN: &str = "12345678"; static UPDATE_NEW_PIN: &str = "87654321"; @@ -31,31 +33,39 @@ fn count_nitrokey_block_devices() -> usize { #[test_device] fn connect_no_device() { - assert!(nitrokey::connect().is_err()); - assert!(nitrokey::connect_model(nitrokey::Model::Pro).is_err()); - assert!(nitrokey::connect_model(nitrokey::Model::Storage).is_err()); - assert!(nitrokey::Pro::connect().is_err()); - assert!(nitrokey::Storage::connect().is_err()); + let mut manager = unwrap_ok!(nitrokey::take()); + + assert_cmu_err!(CommunicationError::NotConnected, manager.connect()); + assert_cmu_err!( + CommunicationError::NotConnected, + manager.connect_model(nitrokey::Model::Pro) + ); + assert_cmu_err!( + CommunicationError::NotConnected, + manager.connect_model(nitrokey::Model::Storage) + ); + assert_cmu_err!(CommunicationError::NotConnected, manager.connect_pro()); + assert_cmu_err!(CommunicationError::NotConnected, manager.connect_storage()); } #[test_device] fn connect_pro(device: Pro) { assert_eq!(device.get_model(), nitrokey::Model::Pro); - drop(device); - assert!(nitrokey::connect().is_ok()); - assert!(nitrokey::connect_model(nitrokey::Model::Pro).is_ok()); - assert!(nitrokey::Pro::connect().is_ok()); + let manager = device.into_manager(); + assert_any_ok!(manager.connect()); + assert_any_ok!(manager.connect_model(nitrokey::Model::Pro)); + assert_any_ok!(manager.connect_pro()); } #[test_device] fn connect_storage(device: Storage) { assert_eq!(device.get_model(), nitrokey::Model::Storage); - drop(device); - assert!(nitrokey::connect().is_ok()); - assert!(nitrokey::connect_model(nitrokey::Model::Storage).is_ok()); - assert!(nitrokey::Storage::connect().is_ok()); + let manager = device.into_manager(); + assert_any_ok!(manager.connect()); + assert_any_ok!(manager.connect_model(nitrokey::Model::Storage)); + assert_any_ok!(manager.connect_storage()); } fn assert_empty_serial_number() { @@ -75,36 +85,40 @@ fn disconnect(device: DeviceWrapper) { #[test_device] fn get_serial_number(device: DeviceWrapper) { - let result = device.get_serial_number(); - assert!(result.is_ok()); - let serial_number = result.unwrap(); + let serial_number = unwrap_ok!(device.get_serial_number()); assert!(serial_number.is_ascii()); assert!(serial_number.chars().all(|c| c.is_ascii_hexdigit())); } #[test_device] fn get_firmware_version(device: Pro) { - assert_eq!(0, device.get_major_firmware_version()); - let minor = device.get_minor_firmware_version(); - assert!(minor > 0); + let version = unwrap_ok!(device.get_firmware_version()); + assert_eq!(0, version.major); + assert!(version.minor > 0); } -fn admin_retry<T: Authenticate + Device>(device: T, suffix: &str, count: u8) -> T { - let result = device.authenticate_admin(&(ADMIN_PASSWORD.to_owned() + suffix)); +fn admin_retry<'a, T>(device: T, suffix: &str, count: u8) -> T +where + T: Authenticate<'a> + Device<'a> + 'a, +{ + let result = device.authenticate_admin(&(DEFAULT_ADMIN_PIN.to_owned() + suffix)); let device = match result { Ok(admin) => admin.device(), Err((device, _)) => device, }; - assert_eq!(count, device.get_admin_retry_count()); + assert_ok!(count, device.get_admin_retry_count()); return device; } -fn user_retry<T: Authenticate + Device>(device: T, suffix: &str, count: u8) -> T { - let result = device.authenticate_user(&(USER_PASSWORD.to_owned() + suffix)); +fn user_retry<'a, T>(device: T, suffix: &str, count: u8) -> T +where + T: Authenticate<'a> + Device<'a> + 'a, +{ + let result = device.authenticate_user(&(DEFAULT_USER_PIN.to_owned() + suffix)); let device = match result { Ok(admin) => admin.device(), Err((device, _)) => device, }; - assert_eq!(count, device.get_user_retry_count()); + assert_ok!(count, device.get_user_retry_count()); return device; } @@ -123,326 +137,390 @@ fn get_retry_count(device: DeviceWrapper) { #[test_device] fn config(device: DeviceWrapper) { - let admin = device.authenticate_admin(ADMIN_PASSWORD).unwrap(); + let mut admin = unwrap_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN)); + let config = Config::new(None, None, None, true); - assert_eq!(Ok(()), admin.write_config(config)); - let get_config = admin.get_config().unwrap(); - assert_eq!(config, get_config); + assert_ok!((), admin.write_config(config)); + assert_ok!(config, admin.get_config()); let config = Config::new(None, Some(9), None, true); - assert_eq!(Err(CommandError::InvalidSlot), admin.write_config(config)); + assert_lib_err!(LibraryError::InvalidSlot, admin.write_config(config)); let config = Config::new(Some(1), None, Some(0), false); - assert_eq!(Ok(()), admin.write_config(config)); - let get_config = admin.get_config().unwrap(); - assert_eq!(config, get_config); + assert_ok!((), admin.write_config(config)); + assert_ok!(config, admin.get_config()); let config = Config::new(None, None, None, false); - assert_eq!(Ok(()), admin.write_config(config)); - let get_config = admin.get_config().unwrap(); - assert_eq!(config, get_config); + assert_ok!((), admin.write_config(config)); + assert_ok!(config, admin.get_config()); } #[test_device] fn change_user_pin(device: DeviceWrapper) { - let device = device.authenticate_user(USER_PASSWORD).unwrap().device(); + let device = device.authenticate_user(DEFAULT_USER_PIN).unwrap().device(); let device = device.authenticate_user(USER_NEW_PASSWORD).unwrap_err().0; - assert!(device - .change_user_pin(USER_PASSWORD, USER_NEW_PASSWORD) - .is_ok()); + let mut device = device; + assert_ok!( + (), + device.change_user_pin(DEFAULT_USER_PIN, USER_NEW_PASSWORD) + ); - let device = device.authenticate_user(USER_PASSWORD).unwrap_err().0; + let device = device.authenticate_user(DEFAULT_USER_PIN).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!(Err(CommandError::WrongPassword), result); + let mut device = device; + let result = device.change_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN); + assert_cmd_err!(CommandError::WrongPassword, result); - assert!(device - .change_user_pin(USER_NEW_PASSWORD, USER_PASSWORD) - .is_ok()); + assert_ok!( + (), + device.change_user_pin(USER_NEW_PASSWORD, DEFAULT_USER_PIN) + ); - let device = device.authenticate_user(USER_PASSWORD).unwrap().device(); + let device = device.authenticate_user(DEFAULT_USER_PIN).unwrap().device(); assert!(device.authenticate_user(USER_NEW_PASSWORD).is_err()); } #[test_device] fn change_admin_pin(device: DeviceWrapper) { - let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device(); - let device = device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err().0; + let device = device + .authenticate_admin(DEFAULT_ADMIN_PIN) + .unwrap() + .device(); + let mut device = device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err().0; - assert!(device - .change_admin_pin(ADMIN_PASSWORD, ADMIN_NEW_PASSWORD) - .is_ok()); + assert_ok!( + (), + device.change_admin_pin(DEFAULT_ADMIN_PIN, ADMIN_NEW_PASSWORD) + ); - let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap_err().0; - let device = device + let device = device.authenticate_admin(DEFAULT_ADMIN_PIN).unwrap_err().0; + let mut device = device .authenticate_admin(ADMIN_NEW_PASSWORD) .unwrap() .device(); - assert_eq!( - Err(CommandError::WrongPassword), - device.change_admin_pin(ADMIN_PASSWORD, ADMIN_PASSWORD) + assert_cmd_err!( + CommandError::WrongPassword, + device.change_admin_pin(DEFAULT_ADMIN_PIN, DEFAULT_ADMIN_PIN) ); - assert!(device - .change_admin_pin(ADMIN_NEW_PASSWORD, ADMIN_PASSWORD) - .is_ok()); + assert_ok!( + (), + device.change_admin_pin(ADMIN_NEW_PASSWORD, DEFAULT_ADMIN_PIN) + ); - let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device(); + let device = device + .authenticate_admin(DEFAULT_ADMIN_PIN) + .unwrap() + .device(); device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err(); } -fn require_failed_user_login<D>(device: D, password: &str, error: CommandError) -> D +fn require_failed_user_login<'a, D>(device: D, password: &str, error: CommandError) -> D where - D: Device + Authenticate, - nitrokey::User<D>: std::fmt::Debug, + D: Device<'a> + Authenticate<'a> + 'a, + nitrokey::User<'a, D>: std::fmt::Debug, { let result = device.authenticate_user(password); assert!(result.is_err()); let err = result.unwrap_err(); - assert_eq!(error, err.1); + match err.1 { + Error::CommandError(err) => assert_eq!(error, err), + _ => assert!(false), + }; err.0 } #[test_device] fn unlock_user_pin(device: DeviceWrapper) { - let device = device.authenticate_user(USER_PASSWORD).unwrap().device(); - assert!(device - .unlock_user_pin(ADMIN_PASSWORD, USER_PASSWORD) - .is_ok()); - assert_eq!( - Err(CommandError::WrongPassword), - device.unlock_user_pin(USER_PASSWORD, USER_PASSWORD) + let mut device = device.authenticate_user(DEFAULT_USER_PIN).unwrap().device(); + assert_ok!( + (), + device.unlock_user_pin(DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN) + ); + assert_cmd_err!( + CommandError::WrongPassword, + device.unlock_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN) ); // block user PIN - let wrong_password = USER_PASSWORD.to_owned() + "foo"; + let wrong_password = DEFAULT_USER_PIN.to_owned() + "foo"; let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); - let device = require_failed_user_login(device, USER_PASSWORD, CommandError::WrongPassword); + let mut device = + require_failed_user_login(device, DEFAULT_USER_PIN, CommandError::WrongPassword); // unblock with current PIN - assert_eq!( - Err(CommandError::WrongPassword), - device.unlock_user_pin(USER_PASSWORD, USER_PASSWORD) + assert_cmd_err!( + CommandError::WrongPassword, + device.unlock_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN) ); - assert!(device - .unlock_user_pin(ADMIN_PASSWORD, USER_PASSWORD) - .is_ok()); - let device = device.authenticate_user(USER_PASSWORD).unwrap().device(); + assert_ok!( + (), + device.unlock_user_pin(DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN) + ); + let device = device.authenticate_user(DEFAULT_USER_PIN).unwrap().device(); // block user PIN let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); - let device = require_failed_user_login(device, USER_PASSWORD, CommandError::WrongPassword); + let mut device = + require_failed_user_login(device, DEFAULT_USER_PIN, CommandError::WrongPassword); // unblock with new PIN - assert_eq!( - Err(CommandError::WrongPassword), - device.unlock_user_pin(USER_PASSWORD, USER_PASSWORD) + assert_cmd_err!( + CommandError::WrongPassword, + device.unlock_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN) + ); + assert_ok!( + (), + device.unlock_user_pin(DEFAULT_ADMIN_PIN, USER_NEW_PASSWORD) ); - assert!(device - .unlock_user_pin(ADMIN_PASSWORD, USER_NEW_PASSWORD) - .is_ok()); // reset user PIN - assert!(device - .change_user_pin(USER_NEW_PASSWORD, USER_PASSWORD) - .is_ok()); + assert_ok!( + (), + device.change_user_pin(USER_NEW_PASSWORD, DEFAULT_USER_PIN) + ); +} + +fn assert_utf8_err_or_ne(left: &str, right: Result<String, Error>) { + match right { + Ok(s) => assert_ne!(left.to_string(), s), + Err(Error::Utf8Error(_)) => {} + Err(err) => panic!("Expected Utf8Error, got {}!", err), + } } #[test_device] fn factory_reset(device: DeviceWrapper) { - let admin = device.authenticate_admin(ADMIN_PASSWORD).unwrap(); + let mut admin = unwrap_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN)); let otp_data = OtpSlotData::new(1, "test", "0123468790", OtpMode::SixDigits); - assert_eq!(Ok(()), admin.write_totp_slot(otp_data, 30)); + assert_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")); + let mut device = admin.device(); + let mut pws = unwrap_ok!(device.get_password_safe(DEFAULT_USER_PIN)); + assert_ok!((), pws.write_slot(0, "test", "testlogin", "testpw")); drop(pws); - assert_eq!( - Ok(()), - device.change_user_pin(USER_PASSWORD, USER_NEW_PASSWORD) + assert_ok!( + (), + device.change_user_pin(DEFAULT_USER_PIN, USER_NEW_PASSWORD) ); - assert_eq!( - Ok(()), - device.change_admin_pin(ADMIN_PASSWORD, ADMIN_NEW_PASSWORD) + assert_ok!( + (), + device.change_admin_pin(DEFAULT_ADMIN_PIN, ADMIN_NEW_PASSWORD) ); - assert_eq!( - Err(CommandError::WrongPassword), + assert_cmd_err!( + CommandError::WrongPassword, device.factory_reset(USER_NEW_PASSWORD) ); - assert_eq!( - Err(CommandError::WrongPassword), - device.factory_reset(ADMIN_PASSWORD) + assert_cmd_err!( + CommandError::WrongPassword, + device.factory_reset(DEFAULT_ADMIN_PIN) ); - assert_eq!(Ok(()), device.factory_reset(ADMIN_NEW_PASSWORD)); + assert_ok!((), device.factory_reset(ADMIN_NEW_PASSWORD)); - let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device(); + let device = device + .authenticate_admin(DEFAULT_ADMIN_PIN) + .unwrap() + .device(); - let user = device.authenticate_user(USER_PASSWORD).unwrap(); - assert_eq!( - Err(CommandError::SlotNotProgrammed), - user.get_totp_slot_name(1) - ); + let user = unwrap_ok!(device.authenticate_user(DEFAULT_USER_PIN)); + assert_cmd_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()); + let mut device = user.device(); + let pws = unwrap_ok!(device.get_password_safe(DEFAULT_USER_PIN)); + assert_utf8_err_or_ne("test", pws.get_slot_name(0)); + assert_utf8_err_or_ne("testlogin", pws.get_slot_login(0)); + assert_utf8_err_or_ne("testpw", pws.get_slot_password(0)); + drop(pws); - assert_eq!(Ok(()), device.build_aes_key(ADMIN_PASSWORD)); + assert_ok!(3, device.get_user_retry_count()); + assert_ok!((), device.build_aes_key(DEFAULT_ADMIN_PIN)); } #[test_device] fn build_aes_key(device: DeviceWrapper) { - let pws = device.get_password_safe(USER_PASSWORD).unwrap(); - assert_eq!(Ok(()), pws.write_slot(0, "test", "testlogin", "testpw")); + let mut device = device; + let mut pws = unwrap_ok!(device.get_password_safe(DEFAULT_USER_PIN)); + assert_ok!((), pws.write_slot(0, "test", "testlogin", "testpw")); drop(pws); - assert_eq!( - Err(CommandError::WrongPassword), - device.build_aes_key(USER_PASSWORD) + assert_cmd_err!( + CommandError::WrongPassword, + device.build_aes_key(DEFAULT_USER_PIN) ); - assert_eq!(Ok(()), device.build_aes_key(ADMIN_PASSWORD)); + assert_ok!((), device.build_aes_key(DEFAULT_ADMIN_PIN)); - let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device(); + let mut device = device + .authenticate_admin(DEFAULT_ADMIN_PIN) + .unwrap() + .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()); + let pws = unwrap_ok!(device.get_password_safe(DEFAULT_USER_PIN)); + assert_utf8_err_or_ne("test", pws.get_slot_name(0)); + assert_utf8_err_or_ne("testlogin", pws.get_slot_login(0)); + assert_utf8_err_or_ne("testpw", pws.get_slot_password(0)); } #[test_device] fn change_update_pin(device: Storage) { - assert_eq!( - Err(CommandError::WrongPassword), + let mut device = device; + assert_cmd_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)); + assert_ok!((), device.change_update_pin(UPDATE_PIN, UPDATE_NEW_PIN)); + assert_ok!((), device.change_update_pin(UPDATE_NEW_PIN, UPDATE_PIN)); } #[test_device] fn encrypted_volume(device: Storage) { - assert_eq!(Ok(()), device.lock()); + let mut device = device; + assert_ok!((), device.lock()); assert_eq!(1, count_nitrokey_block_devices()); - assert_eq!(Ok(()), device.disable_encrypted_volume()); + assert_ok!((), device.disable_encrypted_volume()); assert_eq!(1, count_nitrokey_block_devices()); - assert_eq!( - Err(CommandError::WrongPassword), + assert_cmd_err!( + CommandError::WrongPassword, device.enable_encrypted_volume("123") ); assert_eq!(1, count_nitrokey_block_devices()); - assert_eq!(Ok(()), device.enable_encrypted_volume(USER_PASSWORD)); + assert_ok!((), device.enable_encrypted_volume(DEFAULT_USER_PIN)); assert_eq!(2, count_nitrokey_block_devices()); - assert_eq!(Ok(()), device.disable_encrypted_volume()); + assert_ok!((), device.disable_encrypted_volume()); assert_eq!(1, count_nitrokey_block_devices()); } #[test_device] fn hidden_volume(device: Storage) { - assert_eq!(Ok(()), device.lock()); + let mut device = device; + assert_ok!((), device.lock()); assert_eq!(1, count_nitrokey_block_devices()); - assert_eq!(Ok(()), device.disable_hidden_volume()); + assert_ok!((), device.disable_hidden_volume()); assert_eq!(1, count_nitrokey_block_devices()); - assert_eq!(Ok(()), device.enable_encrypted_volume(USER_PASSWORD)); + assert_ok!((), device.enable_encrypted_volume(DEFAULT_USER_PIN)); assert_eq!(2, count_nitrokey_block_devices()); // TODO: why this error code? - assert_eq!( - Err(CommandError::WrongPassword), + assert_cmd_err!( + CommandError::WrongPassword, device.create_hidden_volume(5, 0, 100, "hiddenpw") ); - assert_eq!(Ok(()), device.create_hidden_volume(0, 20, 21, "hidden-pw")); - assert_eq!( - Ok(()), - device.create_hidden_volume(0, 20, 21, "hiddenpassword") - ); - assert_eq!(Ok(()), device.create_hidden_volume(1, 0, 1, "otherpw")); + assert_ok!((), device.create_hidden_volume(0, 20, 21, "hidden-pw")); + assert_ok!((), device.create_hidden_volume(0, 20, 21, "hiddenpassword")); + assert_ok!((), device.create_hidden_volume(1, 0, 1, "otherpw")); // TODO: test invalid range (not handled by libnitrokey) assert_eq!(2, count_nitrokey_block_devices()); - assert_eq!( - Err(CommandError::WrongPassword), + assert_cmd_err!( + CommandError::WrongPassword, device.enable_hidden_volume("blubb") ); - assert_eq!(Ok(()), device.enable_hidden_volume("hiddenpassword")); + assert_ok!((), device.enable_hidden_volume("hiddenpassword")); assert_eq!(2, count_nitrokey_block_devices()); - assert_eq!(Ok(()), device.enable_hidden_volume("otherpw")); + assert_ok!((), device.enable_hidden_volume("otherpw")); assert_eq!(2, count_nitrokey_block_devices()); - assert_eq!(Ok(()), device.disable_hidden_volume()); + assert_ok!((), device.disable_hidden_volume()); assert_eq!(1, count_nitrokey_block_devices()); } #[test_device] fn lock(device: Storage) { - assert_eq!(Ok(()), device.enable_encrypted_volume(USER_PASSWORD)); - assert_eq!(Ok(()), device.lock()); + let mut device = device; + assert_ok!((), device.enable_encrypted_volume(DEFAULT_USER_PIN)); + assert_ok!((), device.lock()); assert_eq!(1, count_nitrokey_block_devices()); } #[test_device] +fn set_encrypted_volume_mode(device: Storage) { + // This test case does not check the device status as the command only works with firmware + // version 0.49. For later versions, it does not do anything and always returns Ok(()). + let mut device = device; + + assert_ok!( + (), + device.set_encrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadOnly) + ); + + // TODO: re-enable once the password is checked in the firmware + // assert_cmd_err!( + // CommandError::WrongPassword, + // device.set_encrypted_volume_mode(DEFAULT_USER_PIN, VolumeMode::ReadOnly) + // ); + + assert_ok!( + (), + device.set_encrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadOnly) + ); + assert_ok!( + (), + device.set_encrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadWrite) + ); + assert_ok!( + (), + device.set_encrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadOnly) + ); +} + +#[test_device] fn set_unencrypted_volume_mode(device: Storage) { fn assert_mode(device: &Storage, mode: VolumeMode) { - let status = device.get_status(); - assert!(status.is_ok()); + let status = unwrap_ok!(device.get_status()); assert_eq!( - status.unwrap().unencrypted_volume.read_only, + status.unencrypted_volume.read_only, mode == VolumeMode::ReadOnly ); } - fn assert_success(device: &Storage, mode: VolumeMode) { - assert_eq!( - Ok(()), - device.set_unencrypted_volume_mode(ADMIN_PASSWORD, mode) + fn assert_success(device: &mut Storage, mode: VolumeMode) { + assert_ok!( + (), + device.set_unencrypted_volume_mode(DEFAULT_ADMIN_PIN, mode) ); assert_mode(&device, mode); } - assert_success(&device, VolumeMode::ReadOnly); + let mut device = device; + assert_success(&mut device, VolumeMode::ReadOnly); - assert_eq!( - Err(CommandError::WrongPassword), - device.set_unencrypted_volume_mode(USER_PASSWORD, VolumeMode::ReadOnly) + assert_cmd_err!( + CommandError::WrongPassword, + device.set_unencrypted_volume_mode(DEFAULT_USER_PIN, VolumeMode::ReadOnly) ); assert_mode(&device, VolumeMode::ReadOnly); - assert_success(&device, VolumeMode::ReadWrite); - assert_success(&device, VolumeMode::ReadWrite); - assert_success(&device, VolumeMode::ReadOnly); + assert_success(&mut device, VolumeMode::ReadWrite); + assert_success(&mut device, VolumeMode::ReadWrite); + assert_success(&mut device, VolumeMode::ReadOnly); } #[test_device] fn get_storage_status(device: Storage) { - let status = device.get_status().unwrap(); - + let status = unwrap_ok!(device.get_status()); assert!(status.serial_number_sd_card > 0); assert!(status.serial_number_smart_card > 0); } #[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); + let info = unwrap_ok!(device.get_production_info()); + 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); @@ -453,44 +531,45 @@ fn get_production_info(device: Storage) { 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); + let status = unwrap_ok!(device.get_status()); + assert_eq!(status.firmware_version, info.firmware_version); 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)); + let mut device = device; + assert_ok!((), device.factory_reset(DEFAULT_ADMIN_PIN)); thread::sleep(time::Duration::from_secs(3)); - assert_eq!(Ok(()), device.build_aes_key(ADMIN_PASSWORD)); + assert_ok!((), device.build_aes_key(DEFAULT_ADMIN_PIN)); // We have to perform an SD card operation to reset the new_sd_card_found field - assert_eq!(Ok(()), device.lock()); + assert_ok!((), device.lock()); - let status = device.get_status().unwrap(); + let status = unwrap_ok!(device.get_status()); assert!(status.new_sd_card_found); - assert_eq!(Ok(()), device.clear_new_sd_card_warning(ADMIN_PASSWORD)); + assert_ok!((), device.clear_new_sd_card_warning(DEFAULT_ADMIN_PIN)); - let status = device.get_status().unwrap(); + let status = unwrap_ok!(device.get_status()); assert!(!status.new_sd_card_found); } #[test_device] fn export_firmware(device: Storage) { - assert_eq!( - Err(CommandError::WrongPassword), + let mut device = device; + assert_cmd_err!( + CommandError::WrongPassword, device.export_firmware("someadminpn") ); - assert_eq!(Ok(()), device.export_firmware(ADMIN_PASSWORD)); - assert_eq!( - Ok(()), - device.set_unencrypted_volume_mode(ADMIN_PASSWORD, VolumeMode::ReadWrite) + assert_ok!((), device.export_firmware(DEFAULT_ADMIN_PIN)); + assert_ok!( + (), + device.set_unencrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadWrite) ); - assert_eq!(Ok(()), device.export_firmware(ADMIN_PASSWORD)); - assert_eq!( - Ok(()), - device.set_unencrypted_volume_mode(ADMIN_PASSWORD, VolumeMode::ReadOnly) + assert_ok!((), device.export_firmware(DEFAULT_ADMIN_PIN)); + assert_ok!( + (), + device.set_unencrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadOnly) ); } diff --git a/tests/lib.rs b/tests/lib.rs index c92e224..25aae0f 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,7 +1,28 @@ +// Copyright (C) 2019 Robin Krahl <robin.krahl@ireas.org> +// SPDX-License-Identifier: MIT + +mod util; + #[test] fn get_library_version() { - let version = nitrokey::get_library_version(); + let version = unwrap_ok!(nitrokey::get_library_version()); assert!(version.git.is_empty() || version.git.starts_with("v")); assert!(version.major > 0); } + +#[test] +fn take_manager() { + assert!(nitrokey::take().is_ok()); + + let result = nitrokey::take(); + assert!(result.is_ok()); + let result2 = nitrokey::take(); + match result2 { + Ok(_) => panic!("Expected error, got Ok(_)!"), + Err(nitrokey::Error::ConcurrentAccessError) => {} + Err(err) => panic!("Expected ConcurrentAccessError, got {}", err), + } + drop(result); + assert!(nitrokey::take().is_ok()); +} diff --git a/tests/otp.rs b/tests/otp.rs index 712f7a2..38cd8a9 100644 --- a/tests/otp.rs +++ b/tests/otp.rs @@ -1,16 +1,17 @@ +// Copyright (C) 2018-2019 Robin Krahl <robin.krahl@ireas.org> +// SPDX-License-Identifier: MIT + mod util; use std::fmt::Debug; -use std::ops::Deref; +use std::ops::DerefMut; use nitrokey::{ - Admin, Authenticate, CommandError, Config, ConfigureOtp, Device, GenerateOtp, OtpMode, - OtpSlotData, + Admin, Authenticate, CommandError, Config, ConfigureOtp, Device, GenerateOtp, LibraryError, + OtpMode, OtpSlotData, DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN, }; use nitrokey_test::test as test_device; -use crate::util::{ADMIN_PASSWORD, USER_PASSWORD}; - // test suite according to RFC 4226, Appendix D static HOTP_SECRET: &str = "3132333435363738393031323334353637383930"; static HOTP_CODES: &[&str] = &[ @@ -20,13 +21,13 @@ static HOTP_CODES: &[&str] = &[ // test suite according to RFC 6238, Appendix B static TOTP_SECRET: &str = "3132333435363738393031323334353637383930"; -static TOTP_CODES: &[(u64, &str)] = &[ - (59, "94287082"), - (1111111109, "07081804"), - (1111111111, "14050471"), - (1234567890, "89005924"), - (2000000000, "69279037"), - (20000000000, "65353130"), +static TOTP_CODES: &[(u64, &[&str])] = &[ + (59, &["94287082", "37359152"]), + (1111111109, &["07081804"]), + (1111111111, &["14050471"]), + (1234567890, &["89005924"]), + (2000000000, &["69279037"]), + (20000000000, &["65353130"]), ]; #[derive(PartialEq)] @@ -35,268 +36,252 @@ enum TotpTimestampSize { U64, } -fn make_admin_test_device<T>(device: T) -> Admin<T> +fn make_admin_test_device<'a, T>(device: T) -> Admin<'a, T> where - T: Device, - (T, nitrokey::CommandError): Debug, + T: Device<'a>, + (T, nitrokey::Error): Debug, { - device - .authenticate_admin(ADMIN_PASSWORD) - .expect("Could not login as admin.") + unwrap_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN)) } -fn configure_hotp(admin: &ConfigureOtp, counter: u8) { +fn configure_hotp(admin: &mut dyn ConfigureOtp, counter: u8) { let slot_data = OtpSlotData::new(1, "test-hotp", HOTP_SECRET, OtpMode::SixDigits); - assert_eq!(Ok(()), admin.write_hotp_slot(slot_data, counter.into())); + assert_ok!((), admin.write_hotp_slot(slot_data, counter.into())); } -fn check_hotp_codes(device: &GenerateOtp, offset: u8) { +fn check_hotp_codes(device: &mut dyn GenerateOtp, offset: u8) { HOTP_CODES.iter().enumerate().for_each(|(i, code)| { if i >= offset as usize { - let result = device.get_hotp_code(1); - assert_eq!(code, &result.unwrap()); + assert_ok!(code.to_string(), device.get_hotp_code(1)); } }); } #[test_device] fn set_time(device: DeviceWrapper) { - assert_eq!(Ok(()), device.set_time(1546385382, true)); - assert_eq!(Ok(()), device.set_time(1546385392, false)); - assert_eq!( - Err(CommandError::Timestamp), - device.set_time(1546385292, false) - ); - assert_eq!(Ok(()), device.set_time(1546385382, true)); + let mut device = device; + assert_ok!((), device.set_time(1546385382, true)); + assert_ok!((), device.set_time(1546385392, false)); + assert_cmd_err!(CommandError::Timestamp, device.set_time(1546385292, false)); + assert_ok!((), device.set_time(1546385382, true)); } #[test_device] fn hotp_no_pin(device: DeviceWrapper) { - let admin = make_admin_test_device(device); + let mut admin = make_admin_test_device(device); let config = Config::new(None, None, None, false); - assert_eq!(Ok(()), admin.write_config(config)); + assert_ok!((), admin.write_config(config)); - configure_hotp(&admin, 0); - check_hotp_codes(admin.deref(), 0); + configure_hotp(&mut admin, 0); + check_hotp_codes(admin.deref_mut(), 0); - configure_hotp(&admin, 5); - check_hotp_codes(admin.deref(), 5); + configure_hotp(&mut admin, 5); + check_hotp_codes(admin.deref_mut(), 5); - configure_hotp(&admin, 0); - check_hotp_codes(&admin.device(), 0); + configure_hotp(&mut admin, 0); + check_hotp_codes(&mut admin.device(), 0); } #[test_device] fn hotp_pin(device: DeviceWrapper) { - let admin = make_admin_test_device(device); + let mut admin = make_admin_test_device(device); let config = Config::new(None, None, None, true); - assert_eq!(Ok(()), admin.write_config(config)); + assert_ok!((), admin.write_config(config)); - configure_hotp(&admin, 0); - let user = admin.device().authenticate_user(USER_PASSWORD).unwrap(); - check_hotp_codes(&user, 0); + configure_hotp(&mut admin, 0); + let mut user = unwrap_ok!(admin.device().authenticate_user(DEFAULT_USER_PIN)); + check_hotp_codes(&mut user, 0); - assert!(user.device().get_hotp_code(1).is_err()); + assert_cmd_err!(CommandError::NotAuthorized, user.device().get_hotp_code(1)); } #[test_device] fn hotp_slot_name(device: DeviceWrapper) { - let admin = make_admin_test_device(device); + let mut admin = make_admin_test_device(device); let slot_data = OtpSlotData::new(1, "test-hotp", HOTP_SECRET, OtpMode::SixDigits); - assert_eq!(Ok(()), admin.write_hotp_slot(slot_data, 0)); + assert_ok!((), admin.write_hotp_slot(slot_data, 0)); 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()); + assert_ok!("test-hotp".to_string(), device.get_hotp_slot_name(1)); + assert_lib_err!(LibraryError::InvalidSlot, device.get_hotp_slot_name(4)); } #[test_device] fn hotp_error(device: DeviceWrapper) { - let admin = make_admin_test_device(device); + let mut admin = make_admin_test_device(device); let slot_data = OtpSlotData::new(1, "", HOTP_SECRET, OtpMode::SixDigits); - assert_eq!( - Err(CommandError::NoName), - admin.write_hotp_slot(slot_data, 0) - ); + assert_cmd_err!(CommandError::NoName, admin.write_hotp_slot(slot_data, 0)); let slot_data = OtpSlotData::new(4, "test", HOTP_SECRET, OtpMode::SixDigits); - assert_eq!( - Err(CommandError::InvalidSlot), + assert_lib_err!( + LibraryError::InvalidSlot, admin.write_hotp_slot(slot_data, 0) ); let slot_data = OtpSlotData::new(1, "test", "foobar", OtpMode::SixDigits); - assert_eq!( - Err(CommandError::InvalidHexString), + assert_lib_err!( + LibraryError::InvalidHexString, admin.write_hotp_slot(slot_data, 0) ); let code = admin.get_hotp_code(4); - assert_eq!(CommandError::InvalidSlot, code.unwrap_err()); + assert_lib_err!(LibraryError::InvalidSlot, code); } #[test_device] fn hotp_erase(device: DeviceWrapper) { - let admin = make_admin_test_device(device); + let mut admin = make_admin_test_device(device); let config = Config::new(None, None, None, false); - assert_eq!(Ok(()), admin.write_config(config)); + assert_ok!((), admin.write_config(config)); let slot_data = OtpSlotData::new(1, "test1", HOTP_SECRET, OtpMode::SixDigits); - assert_eq!(Ok(()), admin.write_hotp_slot(slot_data, 0)); + assert_ok!((), admin.write_hotp_slot(slot_data, 0)); let slot_data = OtpSlotData::new(2, "test2", HOTP_SECRET, OtpMode::SixDigits); - assert_eq!(Ok(()), admin.write_hotp_slot(slot_data, 0)); + assert_ok!((), admin.write_hotp_slot(slot_data, 0)); - assert_eq!(Ok(()), admin.erase_hotp_slot(1)); + assert_ok!((), admin.erase_hotp_slot(1)); - let device = admin.device(); + let mut device = admin.device(); let result = device.get_hotp_slot_name(1); - assert_eq!(CommandError::SlotNotProgrammed, result.unwrap_err()); + assert_cmd_err!(CommandError::SlotNotProgrammed, result); let result = device.get_hotp_code(1); - assert_eq!(CommandError::SlotNotProgrammed, result.unwrap_err()); + assert_cmd_err!(CommandError::SlotNotProgrammed, result); - assert_eq!("test2", device.get_hotp_slot_name(2).unwrap()); + assert_ok!("test2".to_string(), device.get_hotp_slot_name(2)); } -fn configure_totp(admin: &ConfigureOtp, factor: u64) { +fn configure_totp(admin: &mut dyn ConfigureOtp, factor: u64) { let slot_data = OtpSlotData::new(1, "test-totp", TOTP_SECRET, OtpMode::EightDigits); let time_window = 30u64.checked_mul(factor).unwrap(); - assert_eq!(Ok(()), admin.write_totp_slot(slot_data, time_window as u16)); + assert_ok!((), admin.write_totp_slot(slot_data, time_window as u16)); } -fn check_totp_codes(device: &GenerateOtp, factor: u64, timestamp_size: TotpTimestampSize) { - for (i, &(base_time, code)) in TOTP_CODES.iter().enumerate() { +fn check_totp_codes(device: &mut dyn GenerateOtp, factor: u64, timestamp_size: TotpTimestampSize) { + for (base_time, codes) in TOTP_CODES { let time = base_time.checked_mul(factor).unwrap(); let is_u64 = time > u32::max_value() as u64; if is_u64 != (timestamp_size == TotpTimestampSize::U64) { continue; } - assert_eq!(Ok(()), device.set_time(time, true)); - let result = device.get_totp_code(1); - assert!(result.is_ok()); - let result_code = result.unwrap(); - assert_eq!( - code, result_code, - "TOTP code {} should be {} but is {}", - i, code, result_code + assert_ok!((), device.set_time(time, true)); + let code = unwrap_ok!(device.get_totp_code(1)); + assert!( + code.contains(&code), + "Generated TOTP code {} for {}, but expected one of {}", + code, + base_time, + codes.join(", ") ); } } #[test_device] fn totp_no_pin(device: DeviceWrapper) { - // TODO: this test may fail due to bad timing --> find solution - let admin = make_admin_test_device(device); + let mut admin = make_admin_test_device(device); let config = Config::new(None, None, None, false); - assert_eq!(Ok(()), admin.write_config(config)); + assert_ok!((), admin.write_config(config)); - configure_totp(&admin, 1); - check_totp_codes(admin.deref(), 1, TotpTimestampSize::U32); + configure_totp(&mut admin, 1); + check_totp_codes(admin.deref_mut(), 1, TotpTimestampSize::U32); - configure_totp(&admin, 2); - check_totp_codes(admin.deref(), 2, TotpTimestampSize::U32); + configure_totp(&mut admin, 2); + check_totp_codes(admin.deref_mut(), 2, TotpTimestampSize::U32); - configure_totp(&admin, 1); - check_totp_codes(&admin.device(), 1, TotpTimestampSize::U32); + configure_totp(&mut admin, 1); + check_totp_codes(&mut admin.device(), 1, TotpTimestampSize::U32); } #[test_device] // Nitrokey Storage does only support timestamps that fit in a 32-bit // unsigned integer, so don't test with it. fn totp_no_pin_64(device: Pro) { - let admin = make_admin_test_device(device); + let mut admin = make_admin_test_device(device); let config = Config::new(None, None, None, false); - assert_eq!(Ok(()), admin.write_config(config)); + assert_ok!((), admin.write_config(config)); - configure_totp(&admin, 1); - check_totp_codes(admin.deref(), 1, TotpTimestampSize::U64); + configure_totp(&mut admin, 1); + check_totp_codes(admin.deref_mut(), 1, TotpTimestampSize::U64); - configure_totp(&admin, 2); - check_totp_codes(admin.deref(), 2, TotpTimestampSize::U64); + configure_totp(&mut admin, 2); + check_totp_codes(admin.deref_mut(), 2, TotpTimestampSize::U64); - configure_totp(&admin, 1); - check_totp_codes(&admin.device(), 1, TotpTimestampSize::U64); + configure_totp(&mut admin, 1); + check_totp_codes(&mut admin.device(), 1, TotpTimestampSize::U64); } #[test_device] fn totp_pin(device: DeviceWrapper) { - // TODO: this test may fail due to bad timing --> find solution - let admin = make_admin_test_device(device); + let mut admin = make_admin_test_device(device); let config = Config::new(None, None, None, true); - assert_eq!(Ok(()), admin.write_config(config)); + assert_ok!((), admin.write_config(config)); - configure_totp(&admin, 1); - let user = admin.device().authenticate_user(USER_PASSWORD).unwrap(); - check_totp_codes(&user, 1, TotpTimestampSize::U32); + configure_totp(&mut admin, 1); + let mut user = unwrap_ok!(admin.device().authenticate_user(DEFAULT_USER_PIN)); + check_totp_codes(&mut user, 1, TotpTimestampSize::U32); - assert!(user.device().get_totp_code(1).is_err()); + assert_cmd_err!(CommandError::NotAuthorized, user.device().get_totp_code(1)); } #[test_device] // See comment for totp_no_pin_64. fn totp_pin_64(device: Pro) { - let admin = make_admin_test_device(device); + let mut admin = make_admin_test_device(device); let config = Config::new(None, None, None, true); - assert_eq!(Ok(()), admin.write_config(config)); + assert_ok!((), admin.write_config(config)); - configure_totp(&admin, 1); - let user = admin.device().authenticate_user(USER_PASSWORD).unwrap(); - check_totp_codes(&user, 1, TotpTimestampSize::U64); + configure_totp(&mut admin, 1); + let mut user = unwrap_ok!(admin.device().authenticate_user(DEFAULT_USER_PIN)); + check_totp_codes(&mut user, 1, TotpTimestampSize::U64); - assert!(user.device().get_totp_code(1).is_err()); + assert_cmd_err!(CommandError::NotAuthorized, user.device().get_totp_code(1)); } #[test_device] fn totp_slot_name(device: DeviceWrapper) { - let admin = make_admin_test_device(device); + let mut admin = make_admin_test_device(device); let slot_data = OtpSlotData::new(1, "test-totp", TOTP_SECRET, OtpMode::EightDigits); - assert_eq!(Ok(()), admin.write_totp_slot(slot_data, 0)); + assert_ok!((), admin.write_totp_slot(slot_data, 0)); let device = admin.device(); let result = device.get_totp_slot_name(1); - assert!(result.is_ok()); - assert_eq!("test-totp", result.unwrap()); + assert_ok!("test-totp", result); let result = device.get_totp_slot_name(16); - assert_eq!(CommandError::InvalidSlot, result.unwrap_err()); + assert_lib_err!(LibraryError::InvalidSlot, result); } #[test_device] fn totp_error(device: DeviceWrapper) { - let admin = make_admin_test_device(device); + let mut admin = make_admin_test_device(device); let slot_data = OtpSlotData::new(1, "", TOTP_SECRET, OtpMode::SixDigits); - assert_eq!( - Err(CommandError::NoName), - admin.write_totp_slot(slot_data, 0) - ); + assert_cmd_err!(CommandError::NoName, admin.write_totp_slot(slot_data, 0)); let slot_data = OtpSlotData::new(20, "test", TOTP_SECRET, OtpMode::SixDigits); - assert_eq!( - Err(CommandError::InvalidSlot), + assert_lib_err!( + LibraryError::InvalidSlot, admin.write_totp_slot(slot_data, 0) ); let slot_data = OtpSlotData::new(4, "test", "foobar", OtpMode::SixDigits); - assert_eq!( - Err(CommandError::InvalidHexString), + assert_lib_err!( + LibraryError::InvalidHexString, admin.write_totp_slot(slot_data, 0) ); let code = admin.get_totp_code(20); - assert_eq!(CommandError::InvalidSlot, code.unwrap_err()); + assert_lib_err!(LibraryError::InvalidSlot, code); } #[test_device] fn totp_erase(device: DeviceWrapper) { - let admin = make_admin_test_device(device); + let mut admin = make_admin_test_device(device); let config = Config::new(None, None, None, false); - assert_eq!(Ok(()), admin.write_config(config)); + assert_ok!((), admin.write_config(config)); let slot_data = OtpSlotData::new(1, "test1", TOTP_SECRET, OtpMode::SixDigits); - assert_eq!(Ok(()), admin.write_totp_slot(slot_data, 0)); + assert_ok!((), admin.write_totp_slot(slot_data, 0)); let slot_data = OtpSlotData::new(2, "test2", TOTP_SECRET, OtpMode::SixDigits); - assert_eq!(Ok(()), admin.write_totp_slot(slot_data, 0)); + assert_ok!((), admin.write_totp_slot(slot_data, 0)); - assert_eq!(Ok(()), admin.erase_totp_slot(1)); + assert_ok!((), admin.erase_totp_slot(1)); let device = admin.device(); let result = device.get_totp_slot_name(1); - assert_eq!(CommandError::SlotNotProgrammed, result.unwrap_err()); + assert_cmd_err!(CommandError::SlotNotProgrammed, result); let result = device.get_totp_code(1); - assert_eq!(CommandError::SlotNotProgrammed, result.unwrap_err()); + assert_cmd_err!(CommandError::SlotNotProgrammed, result); - assert_eq!("test2", device.get_totp_slot_name(2).unwrap()); + assert_ok!("test2".to_string(), device.get_totp_slot_name(2)); } diff --git a/tests/pws.rs b/tests/pws.rs index fbcc0c1..7169695 100644 --- a/tests/pws.rs +++ b/tests/pws.rs @@ -1,18 +1,22 @@ +// Copyright (C) 2018-2019 Robin Krahl <robin.krahl@ireas.org> +// SPDX-License-Identifier: MIT + mod util; use std::ffi::CStr; use libc::{c_int, c_void, free}; -use nitrokey::{CommandError, Device, GetPasswordSafe, PasswordSafe, SLOT_COUNT}; +use nitrokey::{ + CommandError, Device, Error, GetPasswordSafe, LibraryError, PasswordSafe, DEFAULT_ADMIN_PIN, + DEFAULT_USER_PIN, SLOT_COUNT, +}; use nitrokey_sys; use nitrokey_test::test as test_device; -use crate::util::{ADMIN_PASSWORD, USER_PASSWORD}; - -fn get_slot_name_direct(slot: u8) -> Result<String, CommandError> { +fn get_slot_name_direct(slot: u8) -> Result<String, Error> { let ptr = unsafe { nitrokey_sys::NK_get_password_safe_slot_name(slot) }; if ptr.is_null() { - return Err(CommandError::Undefined); + return Err(Error::UnexpectedError); } let s = unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() }; unsafe { free(ptr as *mut c_void) }; @@ -21,141 +25,135 @@ fn get_slot_name_direct(slot: u8) -> Result<String, CommandError> { let error = unsafe { nitrokey_sys::NK_get_last_command_status() } as c_int; match error { 0 => Ok(s), - other => Err(CommandError::from(other)), + other => Err(Error::from(other)), } } false => Ok(s), } } -fn get_pws<T>(device: &T) -> PasswordSafe +fn get_pws<'a, T>(device: &mut T) -> PasswordSafe<'_, 'a> where - T: Device, + T: Device<'a>, { - device.get_password_safe(USER_PASSWORD).unwrap() + unwrap_ok!(device.get_password_safe(DEFAULT_USER_PIN)) } #[test_device] fn enable(device: DeviceWrapper) { - assert!(device - .get_password_safe(&(USER_PASSWORD.to_owned() + "123")) - .is_err()); - assert!(device.get_password_safe(USER_PASSWORD).is_ok()); - assert!(device.get_password_safe(ADMIN_PASSWORD).is_err()); - assert!(device.get_password_safe(USER_PASSWORD).is_ok()); + let mut device = device; + assert_cmd_err!( + CommandError::WrongPassword, + device.get_password_safe(&(DEFAULT_USER_PIN.to_owned() + "123")) + ); + assert_any_ok!(device.get_password_safe(DEFAULT_USER_PIN)); + assert_cmd_err!( + CommandError::WrongPassword, + device.get_password_safe(DEFAULT_ADMIN_PIN) + ); + assert_any_ok!(device.get_password_safe(DEFAULT_USER_PIN)); } #[test_device] fn drop(device: DeviceWrapper) { + let mut device = device; { - let pws = get_pws(&device); - assert_eq!(Ok(()), pws.write_slot(1, "name", "login", "password")); - assert_eq!("name", pws.get_slot_name(1).unwrap()); + let mut pws = get_pws(&mut device); + assert_ok!((), pws.write_slot(1, "name", "login", "password")); + assert_ok!("name".to_string(), pws.get_slot_name(1)); let result = get_slot_name_direct(1); - assert_eq!(Ok(String::from("name")), result); + assert_ok!(String::from("name"), result); } let result = get_slot_name_direct(1); - assert_eq!(Ok(String::from("name")), result); - assert_eq!(Ok(()), device.lock()); + assert_ok!(String::from("name"), result); + assert_ok!((), device.lock()); let result = get_slot_name_direct(1); - assert_eq!(Err(CommandError::NotAuthorized), result); + assert_cmd_err!(CommandError::NotAuthorized, result); } #[test_device] fn get_status(device: DeviceWrapper) { - let pws = get_pws(&device); + let mut device = device; + let mut pws = get_pws(&mut device); for i in 0..SLOT_COUNT { - assert_eq!(Ok(()), pws.erase_slot(i), "Could not erase slot {}", i); + assert_ok!((), pws.erase_slot(i)); } - let status = pws.get_slot_status().unwrap(); + let status = unwrap_ok!(pws.get_slot_status()); assert_eq!(status, [false; SLOT_COUNT as usize]); - assert_eq!(Ok(()), pws.write_slot(1, "name", "login", "password")); - let status = pws.get_slot_status().unwrap(); + assert_ok!((), pws.write_slot(1, "name", "login", "password")); + let status = unwrap_ok!(pws.get_slot_status()); for i in 0..SLOT_COUNT { assert_eq!(i == 1, status[i as usize]); } for i in 0..SLOT_COUNT { - assert_eq!(Ok(()), pws.write_slot(i, "name", "login", "password")); + assert_ok!((), pws.write_slot(i, "name", "login", "password")); } - let status = pws.get_slot_status().unwrap(); - assert_eq!(status, [true; SLOT_COUNT as usize]); + assert_ok!([true; SLOT_COUNT as usize], pws.get_slot_status()); } #[test_device] fn get_data(device: DeviceWrapper) { - let pws = get_pws(&device); - assert_eq!(Ok(()), pws.write_slot(1, "name", "login", "password")); - assert_eq!("name", pws.get_slot_name(1).unwrap()); - assert_eq!("login", pws.get_slot_login(1).unwrap()); - assert_eq!("password", pws.get_slot_password(1).unwrap()); - - assert_eq!(Ok(()), pws.erase_slot(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 mut device = device; + let mut pws = get_pws(&mut device); + assert_ok!((), pws.write_slot(1, "name", "login", "password")); + assert_ok!("name".to_string(), pws.get_slot_name(1)); + assert_ok!("login".to_string(), pws.get_slot_login(1)); + assert_ok!("password".to_string(), pws.get_slot_password(1)); + + assert_ok!((), pws.erase_slot(1)); + assert_cmd_err!(CommandError::SlotNotProgrammed, pws.get_slot_name(1)); + assert_cmd_err!(CommandError::SlotNotProgrammed, pws.get_slot_login(1)); + assert_cmd_err!(CommandError::SlotNotProgrammed, pws.get_slot_password(1)); let name = "with å"; let login = "pär@test.com"; let password = "'i3lJc[09?I:,[u7dWz9"; - assert_eq!(Ok(()), pws.write_slot(1, name, login, password)); - assert_eq!(name, pws.get_slot_name(1).unwrap()); - assert_eq!(login, pws.get_slot_login(1).unwrap()); - assert_eq!(password, pws.get_slot_password(1).unwrap()); - - assert_eq!( - Err(CommandError::InvalidSlot), - pws.get_slot_name(SLOT_COUNT) - ); - assert_eq!( - Err(CommandError::InvalidSlot), - pws.get_slot_login(SLOT_COUNT) - ); - assert_eq!( - Err(CommandError::InvalidSlot), - pws.get_slot_password(SLOT_COUNT) - ); + assert_ok!((), pws.write_slot(1, name, login, password)); + assert_ok!(name.to_string(), pws.get_slot_name(1)); + assert_ok!(login.to_string(), pws.get_slot_login(1)); + assert_ok!(password.to_string(), pws.get_slot_password(1)); + + assert_lib_err!(LibraryError::InvalidSlot, pws.get_slot_name(SLOT_COUNT)); + assert_lib_err!(LibraryError::InvalidSlot, pws.get_slot_login(SLOT_COUNT)); + assert_lib_err!(LibraryError::InvalidSlot, pws.get_slot_password(SLOT_COUNT)); } #[test_device] fn write(device: DeviceWrapper) { - let pws = get_pws(&device); + let mut device = device; + let mut pws = get_pws(&mut device); - assert_eq!( - Err(CommandError::InvalidSlot), + assert_lib_err!( + LibraryError::InvalidSlot, pws.write_slot(SLOT_COUNT, "name", "login", "password") ); - assert_eq!(Ok(()), pws.write_slot(0, "", "login", "password")); - 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::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::SlotNotProgrammed), - pws.get_slot_password(0) - ); + assert_ok!((), pws.write_slot(0, "", "login", "password")); + assert_cmd_err!(CommandError::SlotNotProgrammed, pws.get_slot_name(0)); + assert_ok!(String::from("login"), pws.get_slot_login(0)); + assert_ok!(String::from("password"), pws.get_slot_password(0)); + + assert_ok!((), pws.write_slot(0, "name", "", "password")); + assert_ok!(String::from("name"), pws.get_slot_name(0)); + assert_cmd_err!(CommandError::SlotNotProgrammed, pws.get_slot_login(0)); + assert_ok!(String::from("password"), pws.get_slot_password(0)); + + assert_ok!((), pws.write_slot(0, "name", "login", "")); + assert_ok!(String::from("name"), pws.get_slot_name(0)); + assert_ok!(String::from("login"), pws.get_slot_login(0)); + assert_cmd_err!(CommandError::SlotNotProgrammed, pws.get_slot_password(0)); } #[test_device] fn erase(device: DeviceWrapper) { - let pws = get_pws(&device); - assert_eq!(Err(CommandError::InvalidSlot), pws.erase_slot(SLOT_COUNT)); - - 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::SlotNotProgrammed), pws.get_slot_name(0)); + let mut device = device; + let mut pws = get_pws(&mut device); + assert_lib_err!(LibraryError::InvalidSlot, pws.erase_slot(SLOT_COUNT)); + + assert_ok!((), pws.write_slot(0, "name", "login", "password")); + assert_ok!((), pws.erase_slot(0)); + assert_ok!((), pws.erase_slot(0)); + assert_cmd_err!(CommandError::SlotNotProgrammed, pws.get_slot_name(0)); } diff --git a/tests/util/mod.rs b/tests/util/mod.rs index cbf6b93..f2b20ec 100644 --- a/tests/util/mod.rs +++ b/tests/util/mod.rs @@ -1,2 +1,113 @@ -pub static ADMIN_PASSWORD: &str = "12345678"; -pub static USER_PASSWORD: &str = "123456"; +// Copyright (C) 2018-2019 Robin Krahl <robin.krahl@ireas.org> +// SPDX-License-Identifier: MIT + +#[macro_export] +macro_rules! unwrap_ok { + ($val:expr) => {{ + match $val { + Ok(val) => val, + Err(err) => panic!( + r#"assertion failed: `(left == right)` + left: `Ok(_)`, + right: `Err({:?})`"#, + err + ), + } + }}; +} + +#[macro_export] +macro_rules! assert_any_ok { + ($val:expr) => {{ + match &$val { + Ok(_) => {} + Err(err) => panic!( + r#"assertion failed: `(left == right)` + left: `Ok(_)`, + right: `Err({:?})`"#, + err + ), + } + }}; +} + +#[macro_export] +macro_rules! assert_ok { + ($left:expr, $right:expr) => {{ + match &$right { + Ok(right) => match &$left { + left => { + if !(*left == *right) { + panic!( + r#"assertion failed: `(left == right)` + left: `{:?}`, + right: `{:?}`"#, + left, right + ) + } + } + }, + Err(right_err) => panic!( + r#"assertion failed: `(left == right)` + left: `Ok({:?})`, + right: `Err({:?})`"#, + $left, right_err + ), + } + }}; +} + +#[macro_export] +macro_rules! assert_err { + ($err:path, $left:expr, $right:expr) => { + match &$right { + Err($err(ref right_err)) => match &$left { + left_err => { + if !(*left_err == *right_err) { + panic!( + r#"assertion failed: `(left == right)` + left: `{:?}`, + right: `{:?}`"#, + left_err, right_err + ) + } + } + }, + Err(ref right_err) => panic!( + r#"assertion failed: `(left == right)` + left: `{:?}`, + right: `{:?}`"#, + $err($left), + right_err + ), + Ok(right_ok) => panic!( + r#"assertion failed: `(left == right)` + left: `Err({:?})`, + right: `Ok({:?})`"#, + $err($left), + right_ok + ), + } + }; +} + +#[macro_export] +macro_rules! assert_cmd_err { + ($left:expr, $right:expr) => { + assert_err!(::nitrokey::Error::CommandError, $left, $right); + }; +} + +#[macro_export] +macro_rules! assert_cmu_err { + ($left:expr, $right:expr) => { + assert_err!(::nitrokey::Error::CommunicationError, $left, $right); + }; +} + +#[macro_export] +macro_rules! assert_lib_err { + ($left:expr, $right:expr) => { + assert_err!(::nitrokey::Error::LibraryError, $left, $right); + }; +} |