diff options
Diffstat (limited to 'nitrokey/tests/device.rs')
-rw-r--r-- | nitrokey/tests/device.rs | 575 |
1 files changed, 0 insertions, 575 deletions
diff --git a/nitrokey/tests/device.rs b/nitrokey/tests/device.rs deleted file mode 100644 index e367558..0000000 --- a/nitrokey/tests/device.rs +++ /dev/null @@ -1,575 +0,0 @@ -// Copyright (C) 2018-2019 Robin Krahl <robin.krahl@ireas.org> -// SPDX-License-Identifier: MIT - -mod util; - -use std::ffi::CStr; -use std::process::Command; -use std::{thread, time}; - -use nitrokey::{ - 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; - -static ADMIN_NEW_PASSWORD: &str = "1234567890"; -static UPDATE_PIN: &str = "12345678"; -static UPDATE_NEW_PIN: &str = "87654321"; -static USER_NEW_PASSWORD: &str = "abcdefghij"; - -fn count_nitrokey_block_devices() -> usize { - thread::sleep(time::Duration::from_secs(2)); - let output = Command::new("lsblk") - .args(&["-o", "MODEL"]) - .output() - .expect("Could not list block devices"); - String::from_utf8_lossy(&output.stdout) - .split("\n") - .filter(|&s| s.replace("_", " ") == "Nitrokey Storage") - .count() -} - -#[test_device] -fn connect_no_device() { - 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); - - 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); - - 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() { - unsafe { - let ptr = nitrokey_sys::NK_device_serial_number(); - assert!(!ptr.is_null()); - let cstr = CStr::from_ptr(ptr); - assert_eq!(cstr.to_string_lossy(), ""); - } -} - -#[test_device] -fn disconnect(device: DeviceWrapper) { - drop(device); - assert_empty_serial_number(); -} - -#[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())); -} -#[test_device] -fn get_firmware_version(device: Pro) { - let version = unwrap_ok!(device.get_firmware_version()); - assert_eq!(0, version.major); - assert!(version.minor > 0); -} - -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_ok!(count, device.get_admin_retry_count()); - return device; -} - -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_ok!(count, device.get_user_retry_count()); - return device; -} - -#[test_device] -fn get_retry_count(device: DeviceWrapper) { - let device = admin_retry(device, "", 3); - let device = admin_retry(device, "123", 2); - let device = admin_retry(device, "456", 1); - let device = admin_retry(device, "", 3); - - let device = user_retry(device, "", 3); - let device = user_retry(device, "123", 2); - let device = user_retry(device, "456", 1); - user_retry(device, "", 3); -} - -#[test_device] -fn config(device: DeviceWrapper) { - let mut admin = unwrap_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN)); - - let config = Config::new(None, None, None, true); - assert_ok!((), admin.write_config(config)); - assert_ok!(config, admin.get_config()); - - let config = Config::new(None, Some(9), None, true); - assert_lib_err!(LibraryError::InvalidSlot, admin.write_config(config)); - - let config = Config::new(Some(1), None, Some(0), false); - assert_ok!((), admin.write_config(config)); - assert_ok!(config, admin.get_config()); - - let config = Config::new(None, None, None, false); - 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(DEFAULT_USER_PIN).unwrap().device(); - let device = device.authenticate_user(USER_NEW_PASSWORD).unwrap_err().0; - - let mut device = device; - assert_ok!( - (), - device.change_user_pin(DEFAULT_USER_PIN, USER_NEW_PASSWORD) - ); - - let device = device.authenticate_user(DEFAULT_USER_PIN).unwrap_err().0; - let device = device - .authenticate_user(USER_NEW_PASSWORD) - .unwrap() - .device(); - - let mut device = device; - let result = device.change_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN); - assert_cmd_err!(CommandError::WrongPassword, result); - - assert_ok!( - (), - device.change_user_pin(USER_NEW_PASSWORD, DEFAULT_USER_PIN) - ); - - 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(DEFAULT_ADMIN_PIN) - .unwrap() - .device(); - let mut device = device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err().0; - - assert_ok!( - (), - device.change_admin_pin(DEFAULT_ADMIN_PIN, ADMIN_NEW_PASSWORD) - ); - - let device = device.authenticate_admin(DEFAULT_ADMIN_PIN).unwrap_err().0; - let mut device = device - .authenticate_admin(ADMIN_NEW_PASSWORD) - .unwrap() - .device(); - - assert_cmd_err!( - CommandError::WrongPassword, - device.change_admin_pin(DEFAULT_ADMIN_PIN, DEFAULT_ADMIN_PIN) - ); - - assert_ok!( - (), - device.change_admin_pin(ADMIN_NEW_PASSWORD, DEFAULT_ADMIN_PIN) - ); - - let device = device - .authenticate_admin(DEFAULT_ADMIN_PIN) - .unwrap() - .device(); - device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err(); -} - -fn require_failed_user_login<'a, D>(device: D, password: &str, error: CommandError) -> D -where - 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(); - match err.1 { - Error::CommandError(err) => assert_eq!(error, err), - _ => assert!(false), - }; - err.0 -} - -#[test_device] -fn unlock_user_pin(device: DeviceWrapper) { - 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 = 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 mut device = - require_failed_user_login(device, DEFAULT_USER_PIN, CommandError::WrongPassword); - - // unblock with current PIN - assert_cmd_err!( - CommandError::WrongPassword, - device.unlock_user_pin(DEFAULT_USER_PIN, DEFAULT_USER_PIN) - ); - 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 mut device = - require_failed_user_login(device, DEFAULT_USER_PIN, CommandError::WrongPassword); - - // unblock with new PIN - 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) - ); - - // reset user PIN - 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 mut admin = unwrap_ok!(device.authenticate_admin(DEFAULT_ADMIN_PIN)); - let otp_data = OtpSlotData::new(1, "test", "0123468790", OtpMode::SixDigits); - assert_ok!((), admin.write_totp_slot(otp_data, 30)); - - 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_ok!( - (), - device.change_user_pin(DEFAULT_USER_PIN, USER_NEW_PASSWORD) - ); - assert_ok!( - (), - device.change_admin_pin(DEFAULT_ADMIN_PIN, ADMIN_NEW_PASSWORD) - ); - - assert_cmd_err!( - CommandError::WrongPassword, - device.factory_reset(USER_NEW_PASSWORD) - ); - assert_cmd_err!( - CommandError::WrongPassword, - device.factory_reset(DEFAULT_ADMIN_PIN) - ); - assert_ok!((), device.factory_reset(ADMIN_NEW_PASSWORD)); - - let device = device - .authenticate_admin(DEFAULT_ADMIN_PIN) - .unwrap() - .device(); - - let user = unwrap_ok!(device.authenticate_user(DEFAULT_USER_PIN)); - assert_cmd_err!(CommandError::SlotNotProgrammed, user.get_totp_slot_name(1)); - - 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_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 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_cmd_err!( - CommandError::WrongPassword, - device.build_aes_key(DEFAULT_USER_PIN) - ); - assert_ok!((), device.build_aes_key(DEFAULT_ADMIN_PIN)); - - let mut device = device - .authenticate_admin(DEFAULT_ADMIN_PIN) - .unwrap() - .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)); -} - -#[test_device] -fn change_update_pin(device: Storage) { - let mut device = device; - assert_cmd_err!( - CommandError::WrongPassword, - 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) { - let mut device = device; - assert_ok!((), device.lock()); - - assert_eq!(1, count_nitrokey_block_devices()); - assert_ok!((), device.disable_encrypted_volume()); - assert_eq!(1, count_nitrokey_block_devices()); - assert_cmd_err!( - CommandError::WrongPassword, - device.enable_encrypted_volume("123") - ); - assert_eq!(1, count_nitrokey_block_devices()); - assert_ok!((), device.enable_encrypted_volume(DEFAULT_USER_PIN)); - assert_eq!(2, count_nitrokey_block_devices()); - assert_ok!((), device.disable_encrypted_volume()); - assert_eq!(1, count_nitrokey_block_devices()); -} - -#[test_device] -fn hidden_volume(device: Storage) { - let mut device = device; - assert_ok!((), device.lock()); - - assert_eq!(1, count_nitrokey_block_devices()); - assert_ok!((), device.disable_hidden_volume()); - assert_eq!(1, count_nitrokey_block_devices()); - - assert_ok!((), device.enable_encrypted_volume(DEFAULT_USER_PIN)); - assert_eq!(2, count_nitrokey_block_devices()); - - // TODO: why this error code? - assert_cmd_err!( - CommandError::WrongPassword, - device.create_hidden_volume(5, 0, 100, "hiddenpw") - ); - 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_cmd_err!( - CommandError::WrongPassword, - device.enable_hidden_volume("blubb") - ); - assert_ok!((), device.enable_hidden_volume("hiddenpassword")); - assert_eq!(2, count_nitrokey_block_devices()); - assert_ok!((), device.enable_hidden_volume("otherpw")); - assert_eq!(2, count_nitrokey_block_devices()); - - assert_ok!((), device.disable_hidden_volume()); - assert_eq!(1, count_nitrokey_block_devices()); -} - -#[test_device] -fn lock(device: Storage) { - 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 = unwrap_ok!(device.get_status()); - assert_eq!( - status.unencrypted_volume.read_only, - mode == VolumeMode::ReadOnly - ); - } - - fn assert_success(device: &mut Storage, mode: VolumeMode) { - assert_ok!( - (), - device.set_unencrypted_volume_mode(DEFAULT_ADMIN_PIN, mode) - ); - assert_mode(&device, mode); - } - - let mut device = device; - assert_success(&mut device, VolumeMode::ReadOnly); - - assert_cmd_err!( - CommandError::WrongPassword, - device.set_unencrypted_volume_mode(DEFAULT_USER_PIN, VolumeMode::ReadOnly) - ); - assert_mode(&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 = 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 = 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); - 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 = 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) { - 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)); - - // 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()); - assert!(status.new_sd_card_found); - - assert_ok!((), device.clear_new_sd_card_warning(DEFAULT_ADMIN_PIN)); - - let status = unwrap_ok!(device.get_status()); - assert!(!status.new_sd_card_found); -} - -#[test_device] -fn export_firmware(device: Storage) { - let mut device = device; - assert_cmd_err!( - CommandError::WrongPassword, - device.export_firmware("someadminpn") - ); - assert_ok!((), device.export_firmware(DEFAULT_ADMIN_PIN)); - assert_ok!( - (), - device.set_unencrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadWrite) - ); - assert_ok!((), device.export_firmware(DEFAULT_ADMIN_PIN)); - assert_ok!( - (), - device.set_unencrypted_volume_mode(DEFAULT_ADMIN_PIN, VolumeMode::ReadOnly) - ); -} |