summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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()?;