diff options
| author | Robin Krahl <robin.krahl@ireas.org> | 2019-01-14 15:26:02 +0000 | 
|---|---|---|
| committer | Robin Krahl <robin.krahl@ireas.org> | 2019-01-14 16:28:58 +0100 | 
| commit | 0262ed2e614e9222b69970289a32ddb3683b3535 (patch) | |
| tree | 6fe55a9854e8c61daf7bdec9b636260aa2b92253 | |
| parent | 6ea73f29daa5db0215663a0a38334b764863671d (diff) | |
| download | nitrokey-rs-0262ed2e614e9222b69970289a32ddb3683b3535.tar.gz nitrokey-rs-0262ed2e614e9222b69970289a32ddb3683b3535.tar.bz2 | |
Add the get_production_info method to the Storage struct
The get_production_info method maps to the NK_get_production_info
function of libnitrokey.  The Storage firmware supports two query modes:
with or without a write test.  libnitrokey only performs the query
without write test, so the fields that are only set for the write test
are ignored in our implementation.  This affects:
- user and admin retry counts
- smart card ID
- SD card size
| -rw-r--r-- | CHANGELOG.md | 3 | ||||
| -rw-r--r-- | TODO.md | 1 | ||||
| -rw-r--r-- | src/device.rs | 93 | ||||
| -rw-r--r-- | src/lib.rs | 4 | ||||
| -rw-r--r-- | tests/device.rs | 21 | 
5 files changed, 119 insertions, 3 deletions
| diff --git a/CHANGELOG.md b/CHANGELOG.md index 72e6986..7281f78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- Add the `get_production_info` method to the `Storage` struct. +  # v0.3.2 (2019-01-12)  - Make three additional error codes known: `CommandError::StringTooLong`,    `CommandError::InvalidHexString` and `CommandError::TargetBufferTooSmall`. @@ -7,7 +7,6 @@      - `NK_get_progress_bar_value`      - `NK_list_devices_by_cpuID`      - `NK_connect_with_ID` -    - `NK_get_storage_production_info`  - Fix timing issues with the `totp_no_pin` and `totp_pin` test cases.  - Clear passwords from memory.  - Find a nicer syntax for the `write_config` test. diff --git a/src/device.rs b/src/device.rs index f247f58..4032db6 100644 --- a/src/device.rs +++ b/src/device.rs @@ -208,6 +208,38 @@ pub struct VolumeStatus {      pub active: bool,  } +/// Information about the SD card in a Storage device. +#[derive(Debug)] +pub struct SdCardData { +    /// The serial number of the SD card. +    pub serial_number: u32, +    /// The size of the SD card in GB. +    pub size: u8, +    /// The year the card was manufactured, e. g. 17 for 2017. +    pub manufacturing_year: u8, +    /// The month the card was manufactured. +    pub manufacturing_month: u8, +    /// The OEM ID. +    pub oem: u16, +    /// The manufacturer ID. +    pub manufacturer: u8, +} + +#[derive(Debug)] +/// Production information for a Storage device. +pub struct StorageProductionInfo { +    /// The major firmware version, e. g. 0 in v0.40. +    pub firmware_version_major: u8, +    /// The minor firmware version, e. g. 40 in v0.40. +    pub firmware_version_minor: u8, +    /// The internal firmware version. +    pub firmware_version_internal: u8, +    /// The serial number of the CPU. +    pub serial_number_cpu: u32, +    /// Information about the SD card. +    pub sd_card: SdCardData, +} +  /// The status of a Nitrokey Storage device.  #[derive(Debug)]  pub struct StorageStatus { @@ -1166,6 +1198,48 @@ impl Storage {          result.and(Ok(StorageStatus::from(raw_status)))      } +    /// Returns the production information for the connected storage device. +    /// +    /// # Example +    /// +    /// ```no_run +    /// # use nitrokey::CommandError; +    /// +    /// fn use_volume() {} +    /// +    /// # fn try_main() -> Result<(), CommandError> { +    /// let device = nitrokey::Storage::connect()?; +    /// match device.get_production_info() { +    ///     Ok(data) => { +    ///         println!("SD card ID:   {:#x}", data.sd_card.serial_number); +    ///         println!("SD card size: {} GB", data.sd_card.size); +    ///     }, +    ///     Err(err) => println!("Could not get Storage production info: {}", err), +    /// }; +    /// #     Ok(()) +    /// # } +    /// ``` +    pub fn get_production_info(&self) -> Result<StorageProductionInfo, CommandError> { +        let mut raw_data = nitrokey_sys::NK_storage_ProductionTest { +            FirmwareVersion_au8: [0, 2], +            FirmwareVersionInternal_u8: 0, +            SD_Card_Size_u8: 0, +            CPU_CardID_u32: 0, +            SmartCardID_u32: 0, +            SD_CardID_u32: 0, +            SC_UserPwRetryCount: 0, +            SC_AdminPwRetryCount: 0, +            SD_Card_ManufacturingYear_u8: 0, +            SD_Card_ManufacturingMonth_u8: 0, +            SD_Card_OEM_u16: 0, +            SD_WriteSpeed_u16: 0, +            SD_Card_Manufacturer_u8: 0, +        }; +        let raw_result = unsafe { nitrokey_sys::NK_get_storage_production_info(&mut raw_data) }; +        let result = get_command_result(raw_result); +        result.and(Ok(StorageProductionInfo::from(raw_data))) +    } +      /// Blinks the red and green LED alternatively and infinitely until the device is reconnected.      pub fn wink(&self) -> Result<(), CommandError> {          get_command_result(unsafe { nitrokey_sys::NK_wink() }) @@ -1209,6 +1283,25 @@ impl Device for Storage {  impl GenerateOtp for Storage {} +impl From<nitrokey_sys::NK_storage_ProductionTest> for StorageProductionInfo { +    fn from(data: nitrokey_sys::NK_storage_ProductionTest) -> Self { +        Self { +            firmware_version_major: data.FirmwareVersion_au8[0], +            firmware_version_minor: data.FirmwareVersion_au8[1], +            firmware_version_internal: data.FirmwareVersionInternal_u8, +            serial_number_cpu: data.CPU_CardID_u32, +            sd_card: SdCardData { +                serial_number: data.SD_CardID_u32, +                size: data.SD_Card_Size_u8, +                manufacturing_year: data.SD_Card_ManufacturingYear_u8, +                manufacturing_month: data.SD_Card_ManufacturingMonth_u8, +                oem: data.SD_Card_OEM_u16, +                manufacturer: data.SD_Card_Manufacturer_u8, +            } +        } +    } +} +  impl From<nitrokey_sys::NK_storage_status> for StorageStatus {      fn from(status: nitrokey_sys::NK_storage_status) -> Self {          StorageStatus { @@ -98,8 +98,8 @@ use nitrokey_sys;  pub use crate::auth::{Admin, Authenticate, User};  pub use crate::config::Config;  pub use crate::device::{ -    connect, connect_model, Device, DeviceWrapper, Model, Pro, Storage, StorageStatus, VolumeMode, -    VolumeStatus, +    connect, connect_model, Device, DeviceWrapper, Model, Pro, SdCardData, Storage, +    StorageProductionInfo, StorageStatus, VolumeMode, VolumeStatus,  };  pub use crate::otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData};  pub use crate::pws::{GetPasswordSafe, PasswordSafe, SLOT_COUNT}; diff --git a/tests/device.rs b/tests/device.rs index e40ae12..915bd3a 100644 --- a/tests/device.rs +++ b/tests/device.rs @@ -439,6 +439,27 @@ fn get_storage_status(device: Storage) {  }  #[test_device] +fn get_production_info(device: Storage) { +    let info = device.get_production_info().unwrap(); +    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 = device.get_status().unwrap(); +    assert_eq!(status.firmware_version_major, info.firmware_version_major); +    assert_eq!(status.firmware_version_minor, info.firmware_version_minor); +    assert_eq!(status.serial_number_sd_card, info.sd_card.serial_number); +} + +#[test_device]  fn export_firmware(device: Storage) {      assert_eq!(          Err(CommandError::WrongPassword), | 
