diff options
Diffstat (limited to 'nitrokey/src')
-rw-r--r-- | nitrokey/src/device.rs | 91 | ||||
-rw-r--r-- | nitrokey/src/lib.rs | 43 | ||||
-rw-r--r-- | nitrokey/src/util.rs | 14 |
3 files changed, 146 insertions, 2 deletions
diff --git a/nitrokey/src/device.rs b/nitrokey/src/device.rs index 2eee08e..f247f58 100644 --- a/nitrokey/src/device.rs +++ b/nitrokey/src/device.rs @@ -33,6 +33,24 @@ impl fmt::Display for Model { } } +/// The access mode of a volume on the Nitrokey Storage. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum VolumeMode { + /// A read-only volume. + ReadOnly, + /// A read-write volume. + ReadWrite, +} + +impl fmt::Display for VolumeMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + VolumeMode::ReadOnly => f.write_str("read-only"), + VolumeMode::ReadWrite => f.write_str("read-write"), + } + } +} + /// A wrapper for a Nitrokey device of unknown type. /// /// Use the function [`connect`][] to obtain a wrapped instance. The wrapper implements all traits @@ -89,7 +107,6 @@ impl fmt::Display for Model { /// ``` /// /// [`connect`]: fn.connect.html -// TODO: add example for Storage-specific code #[derive(Debug)] pub enum DeviceWrapper { /// A Nitrokey Storage device. @@ -1059,6 +1076,52 @@ impl Storage { } } + /// Sets the access mode of the unencrypted volume. + /// + /// This command will reconnect the unencrypted volume so buffers should be flushed before + /// calling it. Since firmware version v0.51, this command requires the admin PIN. Older + /// firmware versions are not supported. + /// + /// # Errors + /// + /// - [`InvalidString`][] if the provided password contains a null byte + /// - [`WrongPassword`][] if the provided admin password is wrong + /// + /// # Example + /// + /// ```no_run + /// # use nitrokey::CommandError; + /// use nitrokey::VolumeMode; + /// + /// # fn try_main() -> Result<(), CommandError> { + /// let device = nitrokey::Storage::connect()?; + /// match device.set_unencrypted_volume_mode("123456", VolumeMode::ReadWrite) { + /// Ok(()) => println!("Set the unencrypted volume to read-write mode."), + /// Err(err) => println!("Could not set the unencrypted volume to read-write mode: {}", err), + /// }; + /// # Ok(()) + /// # } + /// ``` + /// + /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString + /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword + pub fn set_unencrypted_volume_mode( + &self, + admin_pin: &str, + mode: VolumeMode, + ) -> Result<(), CommandError> { + let admin_pin = get_cstring(admin_pin)?; + let result = match mode { + VolumeMode::ReadOnly => unsafe { + nitrokey_sys::NK_set_unencrypted_read_only_admin(admin_pin.as_ptr()) + }, + VolumeMode::ReadWrite => unsafe { + nitrokey_sys::NK_set_unencrypted_read_write_admin(admin_pin.as_ptr()) + }, + }; + get_command_result(result) + } + /// Returns the status of the connected storage device. /// /// # Example @@ -1102,6 +1165,32 @@ impl Storage { let result = get_command_result(raw_result); result.and(Ok(StorageStatus::from(raw_status))) } + + /// 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() }) + } + + /// Exports the firmware to the unencrypted volume. + /// + /// This command requires the admin PIN. The unencrypted volume must be in read-write mode + /// when this command is executed. Otherwise, it will still return `Ok` but not write the + /// firmware. + /// + /// This command unmounts the unencrypted volume if it has been mounted, so all buffers should + /// be flushed. The firmware is written to the `firmware.bin` file on the unencrypted volume. + /// + /// # Errors + /// + /// - [`InvalidString`][] if one of the provided passwords contains a null byte + /// - [`WrongPassword`][] if the admin password is wrong + /// + /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString + /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword + pub fn export_firmware(&self, admin_pin: &str) -> Result<(), CommandError> { + let admin_pin_string = get_cstring(admin_pin)?; + get_command_result(unsafe { nitrokey_sys::NK_export_firmware(admin_pin_string.as_ptr()) }) + } } impl Drop for Storage { diff --git a/nitrokey/src/lib.rs b/nitrokey/src/lib.rs index bb34870..c50b713 100644 --- a/nitrokey/src/lib.rs +++ b/nitrokey/src/lib.rs @@ -98,12 +98,32 @@ 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, VolumeStatus, + connect, connect_model, Device, DeviceWrapper, Model, Pro, Storage, StorageStatus, VolumeMode, + VolumeStatus, }; pub use crate::otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData}; pub use crate::pws::{GetPasswordSafe, PasswordSafe, SLOT_COUNT}; pub use crate::util::{CommandError, LogLevel}; +/// A version of the libnitrokey library. +/// +/// Use the [`get_library_version`](fn.get_library_version.html) function to query the library +/// version. +#[derive(Clone, Debug, PartialEq)] +pub struct Version { + /// The library version as a string. + /// + /// The library version is the output of `git describe --always` at compile time, for example + /// `v3.3` or `v3.4.1`. If the library has not been built from a release, the version string + /// contains the number of commits since the last release and the hash of the current commit, for + /// example `v3.3-19-gaee920b`. + pub git: String, + /// The major library version. + pub major: u32, + /// The minor library version. + pub minor: u32, +} + /// Enables or disables debug output. Calling this method with `true` is equivalent to setting the /// log level to `Debug`; calling it with `false` is equivalent to the log level `Error` (see /// [`set_log_level`][]). @@ -125,3 +145,24 @@ pub fn set_log_level(level: LogLevel) { nitrokey_sys::NK_set_debug_level(level.into()); } } + +/// Returns the libnitrokey library version. +/// +/// # Example +/// +/// ``` +/// let version = nitrokey::get_library_version(); +/// println!("Using libnitrokey {}", version.git); +/// ``` +pub fn get_library_version() -> Version { + // NK_get_library_version returns a static string, so we don’t have to free the pointer. + let git = unsafe { nitrokey_sys::NK_get_library_version() }; + let git = if git.is_null() { + String::new() + } else { + util::owned_str_from_ptr(git) + }; + let major = unsafe { nitrokey_sys::NK_get_major_library_version() }; + let minor = unsafe { nitrokey_sys::NK_get_minor_library_version() }; + Version { git, major, minor } +} diff --git a/nitrokey/src/util.rs b/nitrokey/src/util.rs index 1ecc0b7..cb109d0 100644 --- a/nitrokey/src/util.rs +++ b/nitrokey/src/util.rs @@ -36,8 +36,14 @@ pub enum CommandError { Undefined, /// You passed a string containing a null byte. InvalidString, + /// A supplied string exceeded a length limit. + StringTooLong, /// You passed an invalid slot. InvalidSlot, + /// The supplied string was not in hexadecimal format. + InvalidHexString, + /// The target buffer was smaller than the source. + TargetBufferTooSmall, } /// Log level for libnitrokey. @@ -134,7 +140,12 @@ impl CommandError { } CommandError::Undefined => "An unspecified error occurred".into(), CommandError::InvalidString => "You passed a string containing a null byte".into(), + CommandError::StringTooLong => "The supplied string is too long".into(), CommandError::InvalidSlot => "The given slot is invalid".into(), + CommandError::InvalidHexString => { + "The supplied string is not in hexadecimal format".into() + } + CommandError::TargetBufferTooSmall => "The target buffer is too small".into(), } } } @@ -158,7 +169,10 @@ impl From<c_int> for CommandError { 8 => CommandError::NotSupported, 9 => CommandError::UnknownCommand, 10 => CommandError::AesDecryptionFailed, + 200 => CommandError::StringTooLong, 201 => CommandError::InvalidSlot, + 202 => CommandError::InvalidHexString, + 203 => CommandError::TargetBufferTooSmall, x => CommandError::Unknown(x.into()), } } |