From f94d04578f44fc79212550203838f7c78e1ac414 Mon Sep 17 00:00:00 2001 From: Daniel Mueller Date: Sun, 9 Apr 2017 19:36:35 -0700 Subject: Add 'status' command The nitrokey supports a status command that instructs it to report details about itself. This data includes general useful information such as the current version of the firmware being installed along with more contextual bits such as the number of remaining retries for the user and admin PINs or whether the different volumes (unencrypted, encrypted, hidden) are writable. This change introduces the 'status' command line option that can be used to retrieve this information from the nitrokey and to display it. --- nitrocli/README.md | 15 +++++++++ nitrocli/src/main.rs | 82 +++++++++++++++++++++++++++++++++++++++++++++++- nitrocli/src/nitrokey.rs | 5 +++ 3 files changed, 101 insertions(+), 1 deletion(-) (limited to 'nitrocli') diff --git a/nitrocli/README.md b/nitrocli/README.md index 5ec814e..69f9b8c 100644 --- a/nitrocli/README.md +++ b/nitrocli/README.md @@ -7,6 +7,7 @@ certain commands on the [Nitrokey Storage][nitrokey] device. The following commands are currently supported: - open: Open the encrypted volume. The user PIN needs to be entered. - close: Close the encrypted volume. +- status: Report status information about the Nitrokey. Usage @@ -17,6 +18,20 @@ parameter, e.g.: ```bash # Open the nitrokey's encrypted volume. $ nitrocli open + +$ nitrocli status +Status: + SD card ID: 0xdeadbeef + firmware version: 44.0 + firmware: unlocked + storage keys: created + user retry count: 3 + admin retry count: 3 + volumes: + unencrypted: active + encrypted: active + hidden: inactive + # Close it again. $ nitrocli close ``` diff --git a/nitrocli/src/main.rs b/nitrocli/src/main.rs index 32ecb3a..92aa79e 100644 --- a/nitrocli/src/main.rs +++ b/nitrocli/src/main.rs @@ -148,6 +148,86 @@ fn nitrokey_do(function: &NitroFunc) -> Result<()> { } +/// Pretty print the response of a status command. +fn print_status(response: &nitrokey::DeviceStatusResponse) { + println!("Status:"); + // We omit displaying information about the smartcard here as this + // program really is only about the SD card portion of the device. + println!(" SD card ID: {:#x}", response.active_sdcard_id); + println!(" firmware version: {}.{}", + response.version_major, + response.version_minor); + println!(" firmware: {}", + if response.firmware_locked != 0 { + "locked".to_string() + } else { + "unlocked".to_string() + }); + println!(" storage keys: {}", + if response.storage_keys_missing == 0 { + "created".to_string() + } else { + "not created".to_string() + }); + println!(" user retry count: {}", + response.user_password_retry_count); + println!(" admin retry count: {}", + response.admin_password_retry_count); + println!(" volumes:"); + println!(" unencrypted: {}", + if response.volume_active & nitrokey::VOLUME_ACTIVE_UNENCRYPTED == 0 { + "inactive" + } else if response.unencrypted_volume_read_only != 0 { + "read-only" + } else { + "active" + }); + println!(" encrypted: {}", + if response.volume_active & nitrokey::VOLUME_ACTIVE_ENCRYPTED == 0 { + "inactive" + } else if response.encrypted_volume_read_only != 0 { + "read-only" + } else { + "active" + }); + println!(" hidden: {}", + if response.volume_active & nitrokey::VOLUME_ACTIVE_HIDDEN == 0 { + "inactive" + } else if response.hidden_volume_read_only != 0 { + "read-only" + } else { + "active" + }); +} + + +/// Inquire the status of the nitrokey. +fn status() -> Result<()> { + type Response = nitrokey::Response; + + return nitrokey_do(&|handle| { + let payload = nitrokey::DeviceStatusCommand::new(); + let report = nitrokey::Report::from(payload); + + let report = transmit::<_, nitrokey::EmptyPayload>(handle, &report)?; + let response = &AsRef::::as_ref(&report.data).data; + + // TODO: We should probably check the success of the command as + // well. + if response.magic != nitrokey::MAGIC_NUMBER_STICK20_CONFIG { + let error = format!("Status response contains invalid magic: {:#x} \ + (expected: {:#x})", + response.magic, + nitrokey::MAGIC_NUMBER_STICK20_CONFIG); + return Err(Error::Error(error.to_string())); + } + + print_status(response); + return Ok(()); + }); +} + + /// Open the encrypted volume on the nitrokey. fn open() -> Result<()> { return nitrokey_do(&|handle| { @@ -203,7 +283,7 @@ fn run() -> i32 { return 1; } - commands!(&argv[1], [open, close]); + commands!(&argv[1], [open, close, status]); } fn main() { diff --git a/nitrocli/src/nitrokey.rs b/nitrocli/src/nitrokey.rs index d5e21be..d1d6c72 100644 --- a/nitrocli/src/nitrokey.rs +++ b/nitrocli/src/nitrokey.rs @@ -30,6 +30,11 @@ pub const PID: u16 = 0x4109; // Magic number identifying a storage response. pub const MAGIC_NUMBER_STICK20_CONFIG: u16 = 0x3318; +// Flags indicating whether the respective volume is active or not. +pub const VOLUME_ACTIVE_UNENCRYPTED: u8 = 0b001; +pub const VOLUME_ACTIVE_ENCRYPTED: u8 = 0b010; +pub const VOLUME_ACTIVE_HIDDEN: u8 = 0b100; + #[derive(Debug)] #[derive(PartialEq)] -- cgit v1.2.1