aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nitrocli/README.md3
-rw-r--r--nitrocli/doc/nitrocli.18
-rw-r--r--nitrocli/src/args.rs23
-rw-r--r--nitrocli/src/commands.rs14
-rw-r--r--nitrocli/src/pinentry.rs27
5 files changed, 72 insertions, 3 deletions
diff --git a/nitrocli/README.md b/nitrocli/README.md
index ed5e4e4..ac6710f 100644
--- a/nitrocli/README.md
+++ b/nitrocli/README.md
@@ -15,8 +15,6 @@ The following commands are currently supported:
- config: Access the Nitrokey's configuration
- get: Read the current configuration.
- set: Change the configuration.
-- pin: Change the Nitrokey’s PINs
- - unblock: Unblock and reset the user PIN.
- storage: Work with the Nitrokey's storage.
- open: Open the encrypted volume. The user PIN needs to be entered.
- close: Close the encrypted volume.
@@ -28,6 +26,7 @@ The following commands are currently supported:
- clear: Delete an OTP slot.
- pin: Manage the Nitrokey's PINs.
- clear: Remove the user and admin PIN from gpg-agent's cache.
+ - set: Change the admin or the user PIN.
- unblock: Unblock and reset the user PIN.
### *Note:*
diff --git a/nitrocli/doc/nitrocli.1 b/nitrocli/doc/nitrocli.1
index bec9a15..4e59352 100644
--- a/nitrocli/doc/nitrocli.1
+++ b/nitrocli/doc/nitrocli.1
@@ -139,6 +139,14 @@ Use the \fBstatus\fR command to check the retry counters.
Clear the PINs cached by the other commands.
.TP
+\fBnitrocli pin set \fItype\fR
+Change a PIN.
+\fItype\fR is the type of the PIN that will be changed: \fBadmin\fR to change
+the admin PIN or \fBuser\fR to change the user PIN.
+This command only works if the retry counter for the PIN type is at least one.
+(Use the \fBstatus\fR command to check the retry counters.)
+
+.TP
.B nitrocli pin unblock
Unblock and reset the user PIN.
This command requires the admin PIN.
diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs
index 4341235..f00ac2a 100644
--- a/nitrocli/src/args.rs
+++ b/nitrocli/src/args.rs
@@ -24,6 +24,7 @@ use std::str;
use crate::commands;
use crate::error::Error;
+use crate::pinentry;
type Result<T> = result::Result<T, Error>;
@@ -278,6 +279,7 @@ impl From<OtpMode> for nitrokey::OtpMode {
#[derive(Debug)]
enum PinCommand {
Clear,
+ Set,
Unblock,
}
@@ -285,6 +287,7 @@ impl PinCommand {
fn execute(&self, args: Vec<String>) -> Result<()> {
match *self {
PinCommand::Clear => pin_clear(args),
+ PinCommand::Set => pin_set(args),
PinCommand::Unblock => pin_unblock(args),
}
}
@@ -297,6 +300,7 @@ impl fmt::Display for PinCommand {
"{}",
match *self {
PinCommand::Clear => "clear",
+ PinCommand::Set => "set",
PinCommand::Unblock => "unblock",
}
)
@@ -309,6 +313,7 @@ impl str::FromStr for PinCommand {
fn from_str(s: &str) -> result::Result<Self, Self::Err> {
match s {
"clear" => Ok(PinCommand::Clear),
+ "set" => Ok(PinCommand::Set),
"unblock" => Ok(PinCommand::Unblock),
_ => Err(()),
}
@@ -693,7 +698,7 @@ fn pin(args: Vec<String>) -> Result<()> {
let _ = parser.refer(&mut subcommand).required().add_argument(
"subcommand",
argparse::Store,
- "The subcommand to execute (clear|unblock)",
+ "The subcommand to execute (clear|set|unblock)",
);
let _ = parser.refer(&mut subargs).add_argument(
"arguments",
@@ -717,6 +722,22 @@ fn pin_clear(args: Vec<String>) -> Result<()> {
commands::pin_clear()
}
+/// Change a PIN.
+fn pin_set(args: Vec<String>) -> Result<()> {
+ let mut pintype = pinentry::PinType::User;
+ let mut parser = argparse::ArgumentParser::new();
+ parser.set_description("Changes a PIN");
+ let _ = parser.refer(&mut pintype).required().add_argument(
+ "type",
+ argparse::Store,
+ "The PIN type to change (admin|user)",
+ );
+ parse(&parser, args)?;
+ drop(parser);
+
+ commands::pin_set(pintype)
+}
+
/// Unblock and reset the user PIN.
fn pin_unblock(args: Vec<String>) -> Result<()> {
let mut parser = argparse::ArgumentParser::new();
diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs
index e3e2a14..b018a58 100644
--- a/nitrocli/src/commands.rs
+++ b/nitrocli/src/commands.rs
@@ -507,6 +507,20 @@ fn choose_pin(pintype: pinentry::PinType) -> Result<String> {
}
}
+/// Change a PIN.
+pub fn pin_set(pintype: pinentry::PinType) -> Result<()> {
+ let device = get_device()?;
+ let new_pin = choose_pin(pintype)?;
+ try_with_passphrase(
+ pintype,
+ "Could not change the PIN",
+ |current_pin| match pintype {
+ pinentry::PinType::Admin => device.change_admin_pin(&current_pin, &new_pin),
+ pinentry::PinType::User => device.change_user_pin(&current_pin, &new_pin),
+ },
+ )
+}
+
/// Unblock and reset the user PIN.
pub fn pin_unblock() -> Result<()> {
let device = get_device()?;
diff --git a/nitrocli/src/pinentry.rs b/nitrocli/src/pinentry.rs
index 33b5266..0d9fc5f 100644
--- a/nitrocli/src/pinentry.rs
+++ b/nitrocli/src/pinentry.rs
@@ -17,7 +17,9 @@
// * along with this program. If not, see <http://www.gnu.org/licenses/>. *
// *************************************************************************
+use std::fmt;
use std::process;
+use std::str;
use crate::error::Error;
@@ -33,6 +35,31 @@ pub enum PinType {
User,
}
+impl fmt::Display for PinType {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "{}",
+ match *self {
+ PinType::Admin => "admin",
+ PinType::User => "user",
+ }
+ )
+ }
+}
+
+impl str::FromStr for PinType {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "admin" => Ok(PinType::Admin),
+ "user" => Ok(PinType::User),
+ _ => Err(()),
+ }
+ }
+}
+
impl PinType {
fn cache_id(self) -> &'static str {
match self {