diff options
author | Robin Krahl <robin.krahl@ireas.org> | 2018-12-30 18:39:31 +0100 |
---|---|---|
committer | Daniel Mueller <deso@posteo.net> | 2019-01-01 17:14:54 -0800 |
commit | fc4a8e12af694a40fe17bcebddd9e4617075400f (patch) | |
tree | 16d5be1bce14d26fafed93c89674948406d290eb /nitrocli/src | |
parent | 8a59f307a2e0b9fa398ac200da44d8e5725150a7 (diff) | |
download | nitrocli-fc4a8e12af694a40fe17bcebddd9e4617075400f.tar.gz nitrocli-fc4a8e12af694a40fe17bcebddd9e4617075400f.tar.bz2 |
Implement the pin unblock subcommand
This patch implements the pin unblock command that unblocks and resets
the user PIN. The name unblock is chosen over libnitrokey's unlock to
be consistent with the GnuPG terminology and to avoid confusion with the
unrelated lock command.
Diffstat (limited to 'nitrocli/src')
-rw-r--r-- | nitrocli/src/args.rs | 15 | ||||
-rw-r--r-- | nitrocli/src/commands.rs | 44 | ||||
-rw-r--r-- | nitrocli/src/pinentry.rs | 10 |
3 files changed, 67 insertions, 2 deletions
diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs index edfd811..4341235 100644 --- a/nitrocli/src/args.rs +++ b/nitrocli/src/args.rs @@ -278,12 +278,14 @@ impl From<OtpMode> for nitrokey::OtpMode { #[derive(Debug)] enum PinCommand { Clear, + Unblock, } impl PinCommand { fn execute(&self, args: Vec<String>) -> Result<()> { match *self { PinCommand::Clear => pin_clear(args), + PinCommand::Unblock => pin_unblock(args), } } } @@ -295,6 +297,7 @@ impl fmt::Display for PinCommand { "{}", match *self { PinCommand::Clear => "clear", + PinCommand::Unblock => "unblock", } ) } @@ -306,6 +309,7 @@ impl str::FromStr for PinCommand { fn from_str(s: &str) -> result::Result<Self, Self::Err> { match s { "clear" => Ok(PinCommand::Clear), + "unblock" => Ok(PinCommand::Unblock), _ => Err(()), } } @@ -689,7 +693,7 @@ fn pin(args: Vec<String>) -> Result<()> { let _ = parser.refer(&mut subcommand).required().add_argument( "subcommand", argparse::Store, - "The subcommand to execute (clear)", + "The subcommand to execute (clear|unblock)", ); let _ = parser.refer(&mut subargs).add_argument( "arguments", @@ -713,6 +717,15 @@ fn pin_clear(args: Vec<String>) -> Result<()> { commands::pin_clear() } +/// Unblock and reset the user PIN. +fn pin_unblock(args: Vec<String>) -> Result<()> { + let mut parser = argparse::ArgumentParser::new(); + parser.set_description("Unblocks and resets the user PIN"); + parse(&parser, args)?; + + commands::pin_unblock() +} + /// Parse the command-line arguments and return the selected command and /// the remaining arguments for the command. fn parse_arguments(args: Vec<String>) -> Result<(Command, Vec<String>)> { diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs index 7f25415..e3e2a14 100644 --- a/nitrocli/src/commands.rs +++ b/nitrocli/src/commands.rs @@ -474,6 +474,50 @@ pub fn pin_clear() -> Result<()> { Ok(()) } +fn check_pin(pintype: pinentry::PinType, pin: &str) -> Result<()> { + let minimum_length = match pintype { + pinentry::PinType::Admin => 8, + pinentry::PinType::User => 6, + }; + if pin.len() < minimum_length { + Err(Error::Error(format!( + "The PIN must be at least {} characters long", + minimum_length + ))) + } else { + Ok(()) + } +} + +fn choose_pin(pintype: pinentry::PinType) -> Result<String> { + pinentry::clear_passphrase(pintype)?; + let new_pin = pinentry::inquire_passphrase(pintype, pinentry::Mode::Choose, None)?; + pinentry::clear_passphrase(pintype)?; + let new_pin = String::from_utf8(new_pin)?; + check_pin(pintype, &new_pin)?; + + let confirm_pin = pinentry::inquire_passphrase(pintype, pinentry::Mode::Confirm, None)?; + pinentry::clear_passphrase(pintype)?; + let confirm_pin = String::from_utf8(confirm_pin)?; + + if new_pin != confirm_pin { + Err(Error::Error("Entered PINs do not match".to_string())) + } else { + Ok(new_pin) + } +} + +/// Unblock and reset the user PIN. +pub fn pin_unblock() -> Result<()> { + let device = get_device()?; + let user_pin = choose_pin(pinentry::PinType::User)?; + try_with_passphrase( + pinentry::PinType::Admin, + "Could not unblock the user PIN", + |admin_pin| device.unlock_user_pin(&admin_pin, &user_pin), + ) +} + #[cfg(test)] mod tests { use super::*; diff --git a/nitrocli/src/pinentry.rs b/nitrocli/src/pinentry.rs index 90986be..33b5266 100644 --- a/nitrocli/src/pinentry.rs +++ b/nitrocli/src/pinentry.rs @@ -51,9 +51,13 @@ impl PinType { fn description(self, mode: Mode) -> &'static str { match self { PinType::Admin => match mode { + Mode::Choose => "Please enter a new admin PIN", + Mode::Confirm => "Please confirm the new admin PIN", Mode::Query => "Please enter the admin PIN", }, PinType::User => match mode { + Mode::Choose => "Please enter a new user PIN", + Mode::Confirm => "Please confirm the new user PIN", Mode::Query => "Please enter the user PIN", }, } @@ -67,13 +71,17 @@ impl PinType { /// quality bar is shown. #[derive(Clone, Copy, Debug, PartialEq)] pub enum Mode { + /// Let the user choose a new PIN. + Choose, + /// Let the user confirm the previously chosen PIN. + Confirm, /// Query an existing PIN. Query, } impl Mode { fn show_quality_bar(self) -> bool { - false + self == Mode::Choose } } |