~ireas/nitrokey-rs

b2aedd0c6a6e848335948a867e13461051c2e783 — Robin Krahl 8 months ago 944773f
Use NK_config struct for configuration handling

Previously, the Nitrokey configuration was represented as an array in
libnitrokey.  libnitrokey 3.6 added the NK_config struct and the
NK_{read,write}_config_struct for type-safe configuration handling.
This patch replaces the old functions with the new versions using the
NK_config struct.  This makes the RawConfig struct obsolete as it is
identical to NK_config.
5 files changed, 42 insertions(+), 61 deletions(-)

M CHANGELOG.md
M TODO.md
M src/auth.rs
M src/config.rs
M src/device/mod.rs
M CHANGELOG.md => CHANGELOG.md +1 -0
@@ 15,6 15,7 @@ SPDX-License-Identifier: CC0-1.0
    in `Device::get_serial_number`.
  - Use `NK_free_password_safe_slot_status` to free the pointer returned by
    `NK_get_password_safe_slot_status` in `PasswordSafe::get_slot_status`.
  - Use the `NK_config` struct for configuration handling.

# v0.7.1 (2020-08-30)
- Remove the custom `std::error::Error::source` implementation for

M TODO.md => TODO.md +0 -6
@@ 11,11 11,5 @@ SPDX-License-Identifier: CC0-1.0
- Update to libnitrokey 3.6:
  - New constants:
    - `NK_LIBREM` (`NK_device_model` enum)
  - New structures:
    - `NK_config`
  - New functions:
    - `NK_write_config_struct`
    - `NK_free_config`
    - `NK_read_config_struct`

[nitrokey-storage-firmware issue 65]: https://github.com/Nitrokey/nitrokey-storage-firmware/issues/65

M src/auth.rs => src/auth.rs +3 -11
@@ 1,14 1,14 @@
// Copyright (C) 2018-2019 Robin Krahl <robin.krahl@ireas.org>
// SPDX-License-Identifier: MIT

use std::convert::TryFrom as _;
use std::convert::TryInto as _;
use std::ffi::CString;
use std::marker;
use std::ops;
use std::os::raw::c_char;
use std::os::raw::c_int;

use crate::config::{Config, RawConfig};
use crate::config::Config;
use crate::device::{Device, DeviceWrapper, Pro, Storage};
use crate::error::Error;
use crate::otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData, RawOtpSlotData};


@@ 304,16 304,8 @@ impl<'a, T: Device<'a>> Admin<'a, T> {
    ///
    /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
    pub fn write_config(&mut self, config: Config) -> Result<(), Error> {
        let raw_config = RawConfig::try_from(config)?;
        get_command_result(unsafe {
            nitrokey_sys::NK_write_config(
                raw_config.num_lock,
                raw_config.caps_lock,
                raw_config.scroll_lock,
                raw_config.user_password,
                false,
                self.temp_password.as_ptr(),
            )
            nitrokey_sys::NK_write_config_struct(config.try_into()?, self.temp_password.as_ptr())
        })
    }
}

M src/config.rs => src/config.rs +33 -31
@@ 25,14 25,6 @@ pub struct Config {
    pub user_password: bool,
}

#[derive(Debug)]
pub struct RawConfig {
    pub num_lock: u8,
    pub caps_lock: u8,
    pub scroll_lock: u8,
    pub user_password: bool,
}

fn config_otp_slot_to_option(value: u8) -> Option<u8> {
    if value < 3 {
        Some(value)


@@ 68,39 60,49 @@ impl Config {
            user_password,
        }
    }

    fn from_raw(numlock: u8, capslock: u8, scrollock: u8, user_password: bool) -> Config {
        Config {
            num_lock: config_otp_slot_to_option(numlock),
            caps_lock: config_otp_slot_to_option(capslock),
            scroll_lock: config_otp_slot_to_option(scrollock),
            user_password,
        }
    }
}

impl convert::TryFrom<Config> for RawConfig {
impl convert::TryFrom<Config> for nitrokey_sys::NK_config {
    type Error = Error;

    fn try_from(config: Config) -> Result<RawConfig, Error> {
        Ok(RawConfig {
            num_lock: option_to_config_otp_slot(config.num_lock)?,
            caps_lock: option_to_config_otp_slot(config.caps_lock)?,
            scroll_lock: option_to_config_otp_slot(config.scroll_lock)?,
            user_password: config.user_password,
    fn try_from(config: Config) -> Result<nitrokey_sys::NK_config, Error> {
        Ok(nitrokey_sys::NK_config {
            numlock: option_to_config_otp_slot(config.num_lock)?,
            capslock: option_to_config_otp_slot(config.caps_lock)?,
            scrolllock: option_to_config_otp_slot(config.scroll_lock)?,
            enable_user_password: config.user_password,
            disable_user_password: false,
        })
    }
}

impl From<&nitrokey_sys::NK_status> for RawConfig {
    fn from(status: &nitrokey_sys::NK_status) -> Self {
        Self {
            num_lock: status.config_numlock,
            caps_lock: status.config_capslock,
            scroll_lock: status.config_scrolllock,
            user_password: status.otp_user_password,
        }
impl From<&nitrokey_sys::NK_config> for Config {
    fn from(config: &nitrokey_sys::NK_config) -> Config {
        Config::from_raw(
            config.numlock,
            config.capslock,
            config.scrolllock,
            config.enable_user_password,
        )
    }
}

impl Into<Config> for RawConfig {
    fn into(self) -> Config {
        Config {
            num_lock: config_otp_slot_to_option(self.num_lock),
            caps_lock: config_otp_slot_to_option(self.caps_lock),
            scroll_lock: config_otp_slot_to_option(self.scroll_lock),
            user_password: self.user_password,
        }
impl From<&nitrokey_sys::NK_status> for Config {
    fn from(status: &nitrokey_sys::NK_status) -> Config {
        Config::from_raw(
            status.config_numlock,
            status.config_capslock,
            status.config_scrolllock,
            status.otp_user_password,
        )
    }
}

M src/device/mod.rs => src/device/mod.rs +5 -13
@@ 11,7 11,7 @@ use std::fmt;
use std::str;

use crate::auth::Authenticate;
use crate::config::{Config, RawConfig};
use crate::config::Config;
use crate::error::{CommunicationError, Error, LibraryError};
use crate::otp::GenerateOtp;
use crate::pws::GetPasswordSafe;


@@ 272,7 272,7 @@ impl From<nitrokey_sys::NK_status> for Status {
                minor: status.firmware_version_minor,
            },
            serial_number: SerialNumber::new(status.serial_number_smart_card),
            config: RawConfig::from(&status).into(),
            config: Config::from(&status),
        }
    }
}


@@ 469,17 469,9 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # }
    /// ```
    fn get_config(&self) -> Result<Config, 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(RawConfig::from(&raw_status).into())
        let mut raw_config = nitrokey_sys::NK_config::default();
        get_command_result(unsafe { nitrokey_sys::NK_read_config_struct(&mut raw_config) })?;
        Ok(Config::from(&raw_config))
    }

    /// Changes the administrator PIN.