summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nitrocli/README.md15
-rw-r--r--nitrocli/src/main.rs82
-rw-r--r--nitrocli/src/nitrokey.rs5
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)]