aboutsummaryrefslogtreecommitdiff
path: root/nitrocli/src/nitrokey.rs
diff options
context:
space:
mode:
authorDaniel Mueller <deso@posteo.net>2017-03-30 21:25:59 -0700
committerDaniel Mueller <deso@posteo.net>2017-03-30 21:25:59 -0700
commit02d31ed3dc89528f5b46201abb0c03b6ef29cc16 (patch)
tree09db53fefb0729ae633c5b9ecada8ecfba965a69 /nitrocli/src/nitrokey.rs
parentc3b61ebe688e6e353b0fcd737f76851f78b8c74f (diff)
downloadnitrocli-02d31ed3dc89528f5b46201abb0c03b6ef29cc16.tar.gz
nitrocli-02d31ed3dc89528f5b46201abb0c03b6ef29cc16.tar.bz2
Receive command responses
By just sending a command to the nitrokey alone we have no idea of what actually happened on the side of the nitrokey. A command could simply be invalid in the current context or the stick could be busy or in a failure state. In order to determine the success of an operation, this change adds the logic to retrieve the response from the nitrokey as well.
Diffstat (limited to 'nitrocli/src/nitrokey.rs')
-rw-r--r--nitrocli/src/nitrokey.rs128
1 files changed, 128 insertions, 0 deletions
diff --git a/nitrocli/src/nitrokey.rs b/nitrocli/src/nitrokey.rs
index 37ba597..87283c0 100644
--- a/nitrocli/src/nitrokey.rs
+++ b/nitrocli/src/nitrokey.rs
@@ -27,6 +27,9 @@ pub const VID: u16 = 0x20A0;
// The Nitrokey Storage product ID.
pub const PID: u16 = 0x4109;
+// Magic number identifying a storage response.
+pub const MAGIC_NUMBER_STICK20_CONFIG: u16 = 0x3318;
+
#[derive(Debug)]
#[derive(PartialEq)]
@@ -36,6 +39,8 @@ pub enum Command {
EnableEncryptedVolume = 0x20,
// The command to disable the encrypted volume.
DisableEncryptedVolume = 0x21,
+ // Retrieve the device status.
+ GetDeviceStatus = 0x2E,
}
@@ -57,6 +62,22 @@ pub struct Report<Payload>
}
+impl<P> Report<P>
+ where P: AsRef<[u8]> + Default,
+{
+ pub fn new() -> Report<P> {
+ return Report {
+ data: P::default(),
+ crc: 0,
+ };
+ }
+
+ pub fn is_valid(&self) -> bool {
+ return self.crc == crc(self.data.as_ref());
+ }
+}
+
+
impl<P> AsRef<[u8]> for Report<P>
where P: AsRef<[u8]>,
{
@@ -79,6 +100,40 @@ impl<P> From<P> for Report<P>
}
+impl<P> AsMut<[u8]> for Report<P>
+ where P: AsRef<[u8]>,
+{
+ fn as_mut(&mut self) -> &mut [u8] {
+ unsafe { return mem::transmute::<&mut Report<P>, &mut [u8; 64]>(self) };
+ }
+}
+
+
+pub struct EmptyPayload {
+ pub data: [u8; 60],
+}
+
+impl Default for EmptyPayload {
+ fn default() -> EmptyPayload {
+ return EmptyPayload {
+ data: [0u8; 60],
+ };
+ }
+}
+
+impl AsRef<[u8]> for EmptyPayload {
+ fn as_ref(&self) -> &[u8] {
+ unsafe { return mem::transmute::<&EmptyPayload, &[u8; 60]>(self) };
+ }
+}
+
+impl<P> AsRef<Response<P>> for EmptyPayload {
+ fn as_ref(&self) -> &Response<P> {
+ unsafe { return mem::transmute::<&EmptyPayload, &Response<P>>(self) };
+ }
+}
+
+
macro_rules! defaultCommandType {
( $name:ident ) => {
#[allow(dead_code)]
@@ -157,6 +212,79 @@ impl EnableEncryptedVolumeCommand {
defaultPayloadAsRef!(EnableEncryptedVolumeCommand);
defaultCommand!(DisableEncryptedVolumeCommand, DisableEncryptedVolume);
+defaultCommand!(DeviceStatusCommand, GetDeviceStatus);
+
+
+#[allow(dead_code)]
+#[derive(Debug)]
+#[derive(PartialEq)]
+#[repr(u8)]
+pub enum CommandStatus {
+ Okay = 0,
+ WrongCrc = 1,
+ WrongSlot = 2,
+ SlotNotProgrammed = 3,
+ WrongPassword = 4,
+ NotAuthorized = 5,
+ TimestampWarning = 6,
+ NoNameError = 7,
+}
+
+
+#[allow(dead_code)]
+#[derive(PartialEq)]
+#[repr(u8)]
+pub enum StorageStatus {
+ Idle = 0,
+ Okay = 1,
+ Busy = 2,
+ WrongPassword = 3,
+ BusyProgressbar = 4,
+ PasswordMatrixReady = 5,
+ NoUserPasswordUnlock = 6,
+ SmartcardError = 7,
+ SecurityBitActive = 8,
+}
+
+
+#[repr(packed)]
+pub struct Response<Payload> {
+ pub device_status: StorageStatus,
+ pub command: Command,
+ pub command_crc: u32,
+ pub command_status: CommandStatus,
+ pub data: Payload,
+}
+
+impl<P> AsRef<[u8]> for Response<P> {
+ fn as_ref(&self) -> &[u8] {
+ unsafe { return mem::transmute::<&Response<P>, &[u8; 60]>(self) };
+ }
+}
+
+
+#[repr(packed)]
+pub struct DeviceStatusResponse {
+ pub padding0: [u8; 22],
+ pub magic: u16,
+ pub unencrypted_volume_read_only: u8,
+ pub encrypted_volume_read_only: u8,
+ pub padding1: u8,
+ pub version_major: u8,
+ pub padding2: u8,
+ pub version_minor: u8,
+ pub hidden_volume_read_only: u8,
+ pub firmware_locked: u8,
+ pub new_sdcard_found: u8,
+ pub sdcard_fill_with_random: u8,
+ pub active_sdcard_id: u32,
+ pub volume_active: u8,
+ pub new_smartcard_found: u8,
+ pub user_password_retry_count: u8,
+ pub admin_password_retry_count: u8,
+ pub active_smartcard_id: u32,
+ pub storage_keys_missing: u8,
+}
#[cfg(test)]