summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Krahl <robin.krahl@ireas.org>2020-01-11 20:05:39 +0100
committerRobin Krahl <robin.krahl@ireas.org>2020-01-11 20:25:56 +0100
commitdbee55efa41496c8a683bfab96163facc93d6639 (patch)
tree93aa1d17acd18b6884b8421c593dab6e7cbf6011
parent1532f92de1d63613602acb0b68486361571f3e50 (diff)
downloadnitrokey-rs-dbee55efa41496c8a683bfab96163facc93d6639.tar.gz
nitrokey-rs-dbee55efa41496c8a683bfab96163facc93d6639.tar.bz2
Add support for the GET_STATUS command
This patch adds support for the GET_STATUS command that returns the status information common to all Nitrokey devices. It can be accessed using the Device::get_status function and is stored in a Status struct. Due to a bug in the Storage firmware [0], the GET_STATUS command returns wrong firmware versions and serial numbers. Until this is fixed in libnitrokey [1], we have to manually execute the GET_DEVICE_STATUS command to fix these values for the Nitrokey Storage. Also, this leads to a name clash with the existing Storage::get_status function, which will be renamed in an upcoming patch. [0] https://github.com/Nitrokey/nitrokey-storage-firmware/issues/96 [1] https://github.com/Nitrokey/libnitrokey/issues/166
-rw-r--r--CHANGELOG.md1
-rw-r--r--TODO.md3
-rw-r--r--src/device/mod.rs58
-rw-r--r--src/device/pro.rs18
-rw-r--r--src/device/storage.rs31
-rw-r--r--src/device/wrapper.rs9
-rw-r--r--src/lib.rs4
-rw-r--r--tests/device.rs9
8 files changed, 125 insertions, 8 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index abdcab7..a9ef359 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ SPDX-License-Identifier: CC0-1.0
- Add the `DeviceInfo` struct.
- Add the `list_devices` function.
- Add the `connect_path` function to the `Manager` struct.
+- Add the `get_status` function to the `Device` trait.
# v0.4.0 (2020-01-02)
- Remove the `test-pro` and `test-storage` features.
diff --git a/TODO.md b/TODO.md
index eba14be..ed5a0ca 100644
--- a/TODO.md
+++ b/TODO.md
@@ -7,13 +7,12 @@ SPDX-License-Identifier: CC0-1.0
- `NK_fill_SD_card_with_random_data`
- `NK_get_SD_usage_data`
- `NK_get_progress_bar_value`
- - `NK_get_status` -- waiting for [libnitrokey issue 166][]
- Clear passwords from memory.
- Lock password safe in `PasswordSafe::drop()` (see [nitrokey-storage-firmware
issue 65][]).
- Disable creation of multiple password safes at the same time.
- Check timing in Storage tests.
- Consider restructuring `device::StorageStatus`.
+- Consider renaming `Storage::get_status` (cf. `Device::get_status`).
-[libnitrokey issue 166]: https://github.com/Nitrokey/libnitrokey/issues/166
[nitrokey-storage-firmware issue 65]: https://github.com/Nitrokey/nitrokey-storage-firmware/issues/65
diff --git a/src/device/mod.rs b/src/device/mod.rs
index e015886..668c230 100644
--- a/src/device/mod.rs
+++ b/src/device/mod.rs
@@ -153,6 +153,35 @@ impl fmt::Display for FirmwareVersion {
}
}
+/// The status information common to all Nitrokey devices.
+pub struct Status {
+ /// The firmware version of the device.
+ pub firmware_version: FirmwareVersion,
+ /// The serial number of the device.
+ pub serial_number: u32,
+ /// The configuration of the device.
+ pub config: Config,
+}
+
+impl From<nitrokey_sys::NK_status> for Status {
+ fn from(status: nitrokey_sys::NK_status) -> Self {
+ Self {
+ firmware_version: FirmwareVersion {
+ major: status.firmware_version_major,
+ minor: status.firmware_version_minor,
+ },
+ serial_number: status.serial_number_smart_card,
+ config: RawConfig {
+ numlock: status.config_numlock,
+ capslock: status.config_capslock,
+ scrollock: status.config_scrolllock,
+ user_password: status.otp_user_password,
+ }
+ .into(),
+ }
+ }
+}
+
/// A Nitrokey device.
///
/// This trait provides the commands that can be executed without authentication and that are
@@ -197,6 +226,35 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
/// # }
fn get_model(&self) -> Model;
+ /// Returns the status of the Nitrokey device.
+ ///
+ /// This methods returns the status information common to all Nitrokey devices as a
+ /// [`Status`][] struct. Some models may provide more information, for example
+ /// [`Storage::get_status`][] returns the [`StorageStatus`][] struct.
+ ///
+ /// # Errors
+ ///
+ /// - [`NotConnected`][] if the Nitrokey device has been disconnected
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use nitrokey::Device;
+ ///
+ /// let mut manager = nitrokey::take()?;
+ /// let device = manager.connect()?;
+ /// let status = device.get_status()?;
+ /// println!("Firmware version: {}", status.firmware_version);
+ /// println!("Serial number: {:x}", status.serial_number);
+ /// # Ok::<(), nitrokey::Error>(())
+ /// ```
+ ///
+ /// [`NotConnected`]: enum.CommunicationError.html#variant.NotConnected
+ /// [`Status`]: struct.Status.html
+ /// [`Storage::get_status`]: struct.Storage.html#method.get_status
+ /// [`StorageStatus`]: struct.StorageStatus.html
+ fn get_status(&self) -> Result<Status, Error>;
+
/// Returns the serial number of the Nitrokey device. The serial number is the string
/// representation of a hex number.
///
diff --git a/src/device/pro.rs b/src/device/pro.rs
index a65345e..591b730 100644
--- a/src/device/pro.rs
+++ b/src/device/pro.rs
@@ -3,8 +3,10 @@
use nitrokey_sys;
-use crate::device::{Device, Model};
+use crate::device::{Device, Model, Status};
+use crate::error::Error;
use crate::otp::GenerateOtp;
+use crate::util::get_command_result;
/// A Nitrokey Pro device without user or admin authentication.
///
@@ -74,6 +76,20 @@ impl<'a> Device<'a> for Pro<'a> {
fn get_model(&self) -> Model {
Model::Pro
}
+
+ fn get_status(&self) -> Result<Status, Error> {
+ let mut raw_status = nitrokey_sys::NK_status {
+ firmware_version_major: 0,
+ firmware_version_minor: 0,
+ serial_number_smart_card: 0,
+ config_numlock: 0,
+ config_capslock: 0,
+ config_scrolllock: 0,
+ otp_user_password: false,
+ };
+ get_command_result(unsafe { nitrokey_sys::NK_get_status(&mut raw_status) })?;
+ Ok(raw_status.into())
+ }
}
impl<'a> GenerateOtp for Pro<'a> {}
diff --git a/src/device/storage.rs b/src/device/storage.rs
index 370ce36..64e6848 100644
--- a/src/device/storage.rs
+++ b/src/device/storage.rs
@@ -1,11 +1,11 @@
-// Copyright (C) 2018-2019 Robin Krahl <robin.krahl@ireas.org>
+// Copyright (C) 2019-2019 Robin Krahl <robin.krahl@ireas.org>
// SPDX-License-Identifier: MIT
use std::fmt;
use nitrokey_sys;
-use crate::device::{Device, FirmwareVersion, Model};
+use crate::device::{Device, FirmwareVersion, Model, Status};
use crate::error::Error;
use crate::otp::GenerateOtp;
use crate::util::{get_command_result, get_cstring};
@@ -678,6 +678,33 @@ impl<'a> Device<'a> for Storage<'a> {
fn get_model(&self) -> Model {
Model::Storage
}
+
+ fn get_status(&self) -> Result<Status, Error> {
+ // Currently, the GET_STATUS command does not report the correct firmware version and
+ // serial number on the Nitrokey Storage, see [0]. Until this is fixed in libnitrokey, we
+ // have to manually execute the GET_DEVICE_STATUS command (Storage::get_status) and
+ // complete the missing data, see [1].
+ // [0] https://github.com/Nitrokey/nitrokey-storage-firmware/issues/96
+ // [1] https://github.com/Nitrokey/libnitrokey/issues/166
+
+ let mut raw_status = nitrokey_sys::NK_status {
+ firmware_version_major: 0,
+ firmware_version_minor: 0,
+ serial_number_smart_card: 0,
+ config_numlock: 0,
+ config_capslock: 0,
+ config_scrolllock: 0,
+ otp_user_password: false,
+ };
+ get_command_result(unsafe { nitrokey_sys::NK_get_status(&mut raw_status) })?;
+ let mut status = Status::from(raw_status);
+
+ let storage_status = Storage::get_status(&self)?;
+ status.firmware_version = storage_status.firmware_version;
+ status.serial_number = storage_status.serial_number_smart_card;
+
+ Ok(status)
+ }
}
impl<'a> GenerateOtp for Storage<'a> {}
diff --git a/src/device/wrapper.rs b/src/device/wrapper.rs
index a3a18f9..adbb695 100644
--- a/src/device/wrapper.rs
+++ b/src/device/wrapper.rs
@@ -1,7 +1,7 @@
// Copyright (C) 2018-2019 Robin Krahl <robin.krahl@ireas.org>
// SPDX-License-Identifier: MIT
-use crate::device::{Device, Model, Pro, Storage};
+use crate::device::{Device, Model, Pro, Status, Storage};
use crate::error::Error;
use crate::otp::GenerateOtp;
@@ -131,4 +131,11 @@ impl<'a> Device<'a> for DeviceWrapper<'a> {
DeviceWrapper::Storage(_) => Model::Storage,
}
}
+
+ fn get_status(&self) -> Result<Status, Error> {
+ match self {
+ DeviceWrapper::Pro(dev) => dev.get_status(),
+ DeviceWrapper::Storage(dev) => Device::get_status(dev),
+ }
+ }
}
diff --git a/src/lib.rs b/src/lib.rs
index 7e8b3ef..41c99c5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -126,8 +126,8 @@ use nitrokey_sys;
pub use crate::auth::{Admin, Authenticate, User};
pub use crate::config::Config;
pub use crate::device::{
- Device, DeviceInfo, DeviceWrapper, Model, Pro, SdCardData, Storage, StorageProductionInfo,
- StorageStatus, VolumeMode, VolumeStatus,
+ Device, DeviceInfo, DeviceWrapper, Model, Pro, SdCardData, Status, Storage,
+ StorageProductionInfo, StorageStatus, VolumeMode, VolumeStatus,
};
pub use crate::error::{CommandError, CommunicationError, Error, LibraryError};
pub use crate::otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData};
diff --git a/tests/device.rs b/tests/device.rs
index 509763b..92b79bd 100644
--- a/tests/device.rs
+++ b/tests/device.rs
@@ -153,6 +153,15 @@ fn disconnect(device: DeviceWrapper) {
assert_empty_serial_number();
}
+#[test_device]
+fn get_status(device: DeviceWrapper) {
+ let status = unwrap_ok!(device.get_status());
+ assert_ok!(status.firmware_version, device.get_firmware_version());
+ let serial_number = format!("{:08x}", status.serial_number);
+ assert_ok!(serial_number, device.get_serial_number());
+ assert_ok!(status.config, device.get_config());
+}
+
fn assert_valid_serial_number(serial_number: &str) {
assert!(serial_number.is_ascii());
assert!(serial_number.chars().all(|c| c.is_ascii_hexdigit()));