summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md4
-rw-r--r--Cargo.toml2
-rw-r--r--README.md2
-rw-r--r--examples/list-devices.rs2
-rw-r--r--examples/otp.rs2
-rw-r--r--src/device/mod.rs69
6 files changed, 57 insertions, 24 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 54ee7d3..cba0e83 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,10 @@ Copyright (C) 2019-2020 Robin Krahl <robin.krahl@ireas.org>
SPDX-License-Identifier: CC0-1.0
-->
+# v0.5.1 (2020-01-15)
+- Fix serial number formatting for Nitrokey Pro devices with firmware 0.8 or
+ older in the `list_devices` function.
+
# v0.5.0 (2020-01-14)
- List these libnitrokey functions as unsupported:
- `NK_change_firmware_password_pro`
diff --git a/Cargo.toml b/Cargo.toml
index 727d47c..59af067 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,7 +3,7 @@
[package]
name = "nitrokey"
-version = "0.5.0"
+version = "0.5.1"
authors = ["Robin Krahl <robin.krahl@ireas.org>"]
edition = "2018"
homepage = "https://code.ireas.org/nitrokey-rs/"
diff --git a/README.md b/README.md
index 8ce093e..9001193 100644
--- a/README.md
+++ b/README.md
@@ -102,7 +102,7 @@ in the `LICENSES` directory. `libnitrokey` is licensed under the [LGPL-3.0][].
`nitrokey-rs` complies with [version 3.0 of the REUSE specification][reuse].
[API reference]: https://docs.rs/nitrokey
-[examples]: https://docs.rs/crate/nitrokey/0.4.0/source/examples/
+[examples]: https://git.ireas.org/nitrokey-rs/tree/examples
[`nitrocli`]: https://github.com/d-e-s-o/nitrocli/tree/master/nitrocli
[Nitrokey udev rules]: https://www.nitrokey.com/documentation/frequently-asked-questions-faq#openpgp-card-not-available
[`libnitrokey`]: https://github.com/nitrokey/libnitrokey
diff --git a/examples/list-devices.rs b/examples/list-devices.rs
index 9c14533..47fa054 100644
--- a/examples/list-devices.rs
+++ b/examples/list-devices.rs
@@ -1,5 +1,5 @@
// Copyright (C) 2020 Robin Krahl <robin.krahl@ireas.org>
-// SPDX-License-Identifier: CC-0
+// SPDX-License-Identifier: CC0-1.0
//! Enumerates all connected Nitrokey devices and prints some information about them.
diff --git a/examples/otp.rs b/examples/otp.rs
index 819de28..f2c6f3c 100644
--- a/examples/otp.rs
+++ b/examples/otp.rs
@@ -1,5 +1,5 @@
// Copyright (C) 2020 Robin Krahl <robin.krahl@ireas.org>
-// SPDX-License-Identifier: CC-0
+// SPDX-License-Identifier: CC0-1.0
//! Connects to a Nitrokey device, configures an TOTP slot and generates a one-time password from
//! it.
diff --git a/src/device/mod.rs b/src/device/mod.rs
index 16d6b11..0234bf0 100644
--- a/src/device/mod.rs
+++ b/src/device/mod.rs
@@ -5,7 +5,6 @@ mod pro;
mod storage;
mod wrapper;
-use std::cmp;
use std::convert::{TryFrom, TryInto};
use std::ffi;
use std::fmt;
@@ -120,21 +119,38 @@ impl fmt::Display for DeviceInfo {
/// Parses a serial number returned by hidapi and transforms it to the Nitrokey format.
///
-/// If the serial number is all zero, this function returns `None`. Otherwise, all leading zeros
-/// (except the last eight characters) are stripped and `Some(_)` is returned. If the serial
-/// number has less than eight characters, leading zeros are added.
+/// If the serial number is all zero, this function returns `None`. Otherwise, it uses the last
+/// eight characters. If these are all zero, the first eight characters are used instead. This
+/// function also makes sure that the returned string is lowercase, consistent with libnitrokey’s
+/// hex string formatting.
+///
+/// The reason for this behavior is that the Nitrokey Storage does not report its serial number at
+/// all (all zero value), while the Nitrokey Pro with firmware 0.9 or later writes its serial
+/// number to the last eight characters. Nitrokey Pro devices with firmware 0.8 or earlier wrote
+/// their serial number to the first eight characters.
fn get_hidapi_serial_number(serial_number: &str) -> Option<String> {
- let mut iter = serial_number.char_indices().skip_while(|(_, c)| *c == '0');
- let first_non_null = iter.next();
+ let len = serial_number.len();
+ if len < 8 {
+ // The serial number in the USB descriptor has 12 bytes, we need at least four of them
+ return None;
+ }
+
+ let iter = serial_number.char_indices().rev();
+ let first_non_null = iter.skip_while(|(_, c)| *c == '0').next();
if let Some((i, _)) = first_non_null {
- // keep at least the last 8 characters
- let len = serial_number.len();
- let cut = cmp::min(len.saturating_sub(8), i);
- let (_, suffix) = serial_number.split_at(cut);
- // if necessary, add leading zeros to reach 8 characters
- let fill = 8usize.saturating_sub(len);
- Some("0".repeat(fill) + suffix)
+ if len - i < 8 {
+ // The last eight characters contain at least one non-zero character --> use them
+ let mut serial_number = serial_number.split_at(len - 8).1.to_string();
+ serial_number.make_ascii_lowercase();
+ Some(serial_number)
+ } else {
+ // The last eight characters are all zero --> use the first eight
+ let mut serial_number = serial_number.split_at(8).0.to_string();
+ serial_number.make_ascii_lowercase();
+ Some(serial_number)
+ }
} else {
+ // The serial number is all zero
None
}
}
@@ -615,10 +631,7 @@ mod tests {
fn hidapi_serial_number() {
assert_eq!(None, get_hidapi_serial_number(""));
assert_eq!(None, get_hidapi_serial_number("00000000000000000"));
- assert_eq!(
- Some("00001234".to_string()),
- get_hidapi_serial_number("1234")
- );
+ assert_eq!(None, get_hidapi_serial_number("1234"));
assert_eq!(
Some("00001234".to_string()),
get_hidapi_serial_number("00001234")
@@ -628,12 +641,28 @@ mod tests {
get_hidapi_serial_number("000000001234")
);
assert_eq!(
- Some("100000001234".to_string()),
+ Some("00001234".to_string()),
get_hidapi_serial_number("100000001234")
);
assert_eq!(
- Some("10000001234".to_string()),
- get_hidapi_serial_number("010000001234")
+ Some("12340000".to_string()),
+ get_hidapi_serial_number("123400000000")
+ );
+ assert_eq!(
+ Some("00005678".to_string()),
+ get_hidapi_serial_number("000000000000000000005678")
+ );
+ assert_eq!(
+ Some("00001234".to_string()),
+ get_hidapi_serial_number("000012340000000000000000")
+ );
+ assert_eq!(
+ Some("0000ffff".to_string()),
+ get_hidapi_serial_number("00000000000000000000FFFF")
+ );
+ assert_eq!(
+ Some("0000ffff".to_string()),
+ get_hidapi_serial_number("00000000000000000000ffff")
);
}
}