diff options
| -rw-r--r-- | nitrocli/src/main.rs | 7 | ||||
| -rw-r--r-- | nitrocli/src/pinentry.rs | 55 | 
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()?; | 
