diff options
-rw-r--r-- | nitrocli/README.md | 15 | ||||
-rw-r--r-- | nitrocli/src/main.rs | 82 | ||||
-rw-r--r-- | nitrocli/src/nitrokey.rs | 5 |
3 files changed, 101 insertions, 1 deletions
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<nitrokey::DeviceStatusResponse>; + + 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::<Response>::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)] |