summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Krahl <me@robin-krahl.de>2018-12-11 12:09:32 +0100
committerDaniel Müller <d-e-s-o@users.noreply.github.com>2018-12-11 17:34:18 -0800
commit324016494904ce3d53bbfb63a76f67e220e0685c (patch)
tree8af8d53a97dc9439834de9322ddbbdbe6a071bbc
parentc67ecea7e22b890a3014a884585d801a2fcc3293 (diff)
downloadnitrocli-324016494904ce3d53bbfb63a76f67e220e0685c.tar.gz
nitrocli-324016494904ce3d53bbfb63a76f67e220e0685c.tar.bz2
Add support for multiple PIN types
Currently, the pinentry module only supports querying the user PIN. The Nitrokey devices also have an admin PIN. This patch adds support for querying multiple PIN types to the pinentry module. While this is currently not used, it will be needed to add support for administrative commands like unlocking the device or changeing the user PIN.
-rw-r--r--nitrocli/src/main.rs7
-rw-r--r--nitrocli/src/pinentry.rs55
2 files changed, 48 insertions, 14 deletions
diff --git a/nitrocli/src/main.rs b/nitrocli/src/main.rs
index 0ba232f..ebc0589 100644
--- a/nitrocli/src/main.rs
+++ b/nitrocli/src/main.rs
@@ -42,6 +42,7 @@ type Result<T> = result::Result<T, Error>;
type NitroFunc = Fn(&mut libhid::Handle) -> Result<()>;
+const PIN_TYPE: pinentry::PinType = pinentry::PinType::User;
const SEND_TRY_COUNT: i8 = 3;
const RECV_TRY_COUNT: i8 = 40;
const SEND_RECV_DELAY_MS: u64 = 200;
@@ -255,7 +256,7 @@ fn open() -> Result<()> {
let mut retry = 3;
let mut error_msg: Option<&str> = None;
loop {
- let passphrase = pinentry::inquire_passphrase(error_msg)?;
+ let passphrase = pinentry::inquire_passphrase(PIN_TYPE, error_msg)?;
let payload = nitrokey::EnableEncryptedVolumeCommand::new(&passphrase);
let report = nitrokey::Report::from(payload);
@@ -264,7 +265,7 @@ fn open() -> Result<()> {
let mut status = response.data.storage_status;
if status == nitrokey::StorageStatus::WrongPassword {
- pinentry::clear_passphrase()?;
+ pinentry::clear_passphrase(PIN_TYPE)?;
retry -= 1;
if retry > 0 {
@@ -328,7 +329,7 @@ fn close() -> Result<()> {
/// Clear the PIN stored when opening the nitrokey's encrypted volume.
fn clear() -> Result<()> {
- pinentry::clear_passphrase()
+ pinentry::clear_passphrase(PIN_TYPE)
}
diff --git a/nitrocli/src/pinentry.rs b/nitrocli/src/pinentry.rs
index 6cf3093..0553b8e 100644
--- a/nitrocli/src/pinentry.rs
+++ b/nitrocli/src/pinentry.rs
@@ -21,7 +21,41 @@ use error::Error;
use std::process;
-const CACHE_ID: &str = "nitrocli:user";
+/// PIN type requested from pinentry.
+///
+/// The available PIN types correspond to the PIN types used by the Nitrokey devices: user and
+/// admin.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum PinType {
+ /// The admin PIN.
+ Admin,
+ /// The user PIN.
+ User,
+}
+
+
+impl PinType {
+ fn cache_id(self) -> &'static str {
+ match self {
+ PinType::Admin => "nitrocli:admin",
+ PinType::User => "nitrocli:user",
+ }
+ }
+
+ fn prompt(self) -> &'static str {
+ match self {
+ PinType::Admin => "Admin PIN",
+ PinType::User => "User PIN",
+ }
+ }
+
+ fn description(self) -> &'static str {
+ match self {
+ PinType::Admin => "Please enter admin PIN",
+ PinType::User => "Please enter user PIN",
+ }
+ }
+}
fn parse_pinentry_passphrase(response: Vec<u8>) -> Result<Vec<u8>, Error> {
@@ -49,14 +83,13 @@ fn parse_pinentry_passphrase(response: Vec<u8>) -> Result<Vec<u8>, Error> {
}
-pub fn inquire_passphrase(error_msg: Option<&str>) -> Result<Vec<u8>, Error> {
- const PINENTRY_ERROR_MSG_EMPTY: &str = "+";
- const PINENTRY_PROMPT: &str = "PIN";
- const PINENTRY_DESCR: &str = "Please+enter+user+PIN";
+pub fn inquire_passphrase(pin_type: PinType, error_msg: Option<&str>) -> Result<Vec<u8>, Error> {
+ let cache_id = pin_type.cache_id();
+ let error_msg = error_msg.map(|msg| msg.replace(" ", "+")).unwrap_or(String::from("+"));
+ let prompt = pin_type.prompt();
+ let description = pin_type.description().replace(" ", "+");
- let error_msg = error_msg.map(|msg| msg.replace(" ", "+"))
- .unwrap_or(PINENTRY_ERROR_MSG_EMPTY.to_string());
- let args = vec![CACHE_ID, &error_msg, PINENTRY_PROMPT, PINENTRY_DESCR].join(" ");
+ let args = vec![cache_id, &error_msg, prompt, &description].join(" ");
let command = "GET_PASSPHRASE --data ".to_string() + &args;
// We could also use the --data parameter here to have a more direct
// representation of the passphrase but the resulting response was
@@ -83,9 +116,9 @@ fn parse_pinentry_response(response: Vec<u8>) -> Result<(), Error> {
}
-/// Clear the cached passphrase.
-pub fn clear_passphrase() -> Result<(), Error> {
- let command = "CLEAR_PASSPHRASE ".to_string() + CACHE_ID;
+/// Clear the cached passphrase of the given type.
+pub fn clear_passphrase(pin_type: PinType) -> Result<(), Error> {
+ let command = "CLEAR_PASSPHRASE ".to_string() + pin_type.cache_id();
let output = process::Command::new("gpg-connect-agent").arg(command)
.arg("/bye")
.output()?;