summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Krahl <robin.krahl@ireas.org>2019-01-16 01:03:30 +0000
committerDaniel Mueller <deso@posteo.net>2019-01-26 23:35:09 -0800
commitf038b53dfaf68be0d52d1d8aa3d2df922aabd787 (patch)
tree2e725b3bff52b843a776ba1db40e50007e5ff44d
parent274ae17ca0fc86ebfcbaa3a6cb4201e2cfd0f622 (diff)
downloadnitrocli-f038b53dfaf68be0d52d1d8aa3d2df922aabd787.tar.gz
nitrocli-f038b53dfaf68be0d52d1d8aa3d2df922aabd787.tar.bz2
Add the reset command to perform a factory reset
After performing the factory reset, we also build the AES key so that the device is fully usable. Due to timing issue, we have to add a delay between the factory reset and building the AES key.
-rw-r--r--nitrocli/CHANGELOG.md1
-rw-r--r--nitrocli/doc/nitrocli.112
-rw-r--r--nitrocli/doc/nitrocli.1.pdfbin17334 -> 17751 bytes
-rw-r--r--nitrocli/src/args.rs10
-rw-r--r--nitrocli/src/commands.rs26
5 files changed, 48 insertions, 1 deletions
diff --git a/nitrocli/CHANGELOG.md b/nitrocli/CHANGELOG.md
index 9eb8f17..8e70530 100644
--- a/nitrocli/CHANGELOG.md
+++ b/nitrocli/CHANGELOG.md
@@ -1,5 +1,6 @@
Unreleased
----------
+- Added the `reset` command to perform a factory reset
- Added the `-V`/`--version` option to print the program's version
diff --git a/nitrocli/doc/nitrocli.1 b/nitrocli/doc/nitrocli.1
index 74fd635..66d73f9 100644
--- a/nitrocli/doc/nitrocli.1
+++ b/nitrocli/doc/nitrocli.1
@@ -41,6 +41,16 @@ Lock the Nitrokey.
This command locks the password safe (see the Password safe section). On the
Nitrokey Storage, it will also close any active encrypted or hidden volumes (see
the Storage section).
+.TP
+.B nitrocli reset
+Perform a factory reset on the Nitrokey.
+This command performs a factory reset on the OpenPGP smart card, clears the
+flash storage and builds a new AES key.
+The user PIN is reset to 123456, the admin PIN to 12345678.
+
+This command requires the admin PIN.
+To avoid accidental calls of this command, the user has to enter the PIN even
+if it has been cached.
.SS Storage
The Nitrokey Storage comes with a storage area. This area is comprised of an
@@ -226,7 +236,7 @@ The initial retry counter is three.
If the retry counter for the user PIN is zero, you can use the
\fBpin unblock\fR command to unblock and reset the user PIN.
If the retry counter for the admin PIN is zero, you have to perform a factory
-reset using \fBgpg\fR(1).
+reset using the \fBreset\fR command or \fBgpg\fR(1).
Use the \fBstatus\fR command to check the retry counters.
.TP
.B nitrocli pin clear
diff --git a/nitrocli/doc/nitrocli.1.pdf b/nitrocli/doc/nitrocli.1.pdf
index 32cf085..ff72f94 100644
--- a/nitrocli/doc/nitrocli.1.pdf
+++ b/nitrocli/doc/nitrocli.1.pdf
Binary files differ
diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs
index 3b89bf1..43f866d 100644
--- a/nitrocli/src/args.rs
+++ b/nitrocli/src/args.rs
@@ -81,6 +81,7 @@ Enum! {Command, [
Otp => ("otp", otp),
Pin => ("pin", pin),
Pws => ("pws", pws),
+ Reset => ("reset", reset),
Status => ("status", status),
Storage => ("storage", storage)
]}
@@ -192,6 +193,15 @@ fn status(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
commands::status(ctx)
}
+/// Perform a factory reset.
+fn reset(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
+ let mut parser = argparse::ArgumentParser::new();
+ parser.set_description("Performs a factory reset");
+ parse(ctx, &parser, args)?;
+
+ commands::reset(ctx)
+}
+
Enum! {StorageCommand, [
Close => ("close", storage_close),
Hidden => ("hidden", storage_hidden),
diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs
index 989abbf..aed0319 100644
--- a/nitrocli/src/commands.rs
+++ b/nitrocli/src/commands.rs
@@ -19,6 +19,7 @@
use std::fmt;
use std::result;
+use std::thread;
use std::time;
use std::u8;
@@ -33,6 +34,8 @@ use crate::error::Error;
use crate::pinentry;
use crate::Result;
+const NITROKEY_DEFAULT_ADMIN_PIN: &str = "12345678";
+
/// Create an `error::Error` with an error message of the format `msg: err`.
fn get_error(msg: &'static str, err: nitrokey::CommandError) -> Error {
Error::CommandError(Some(msg), err)
@@ -291,6 +294,29 @@ pub fn status(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
print_status(ctx, model, &device)
}
+/// Perform a factory reset.
+pub fn reset(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
+ let device = get_device(ctx)?;
+ let pin_entry = pinentry::PinEntry::from(pinentry::PinType::Admin, &device)?;
+
+ // To force the user to enter the admin PIN before performing a
+ // factory reset, we clear the pinentry cache for the admin PIN.
+ pinentry::clear(&pin_entry)?;
+
+ try_with_pin(ctx, &pin_entry, "Factory reset failed", |pin| {
+ device.factory_reset(&pin)?;
+ // Work around for a timing issue between factory_reset and
+ // build_aes_key, see
+ // https://github.com/Nitrokey/nitrokey-storage-firmware/issues/80
+ thread::sleep(time::Duration::from_secs(3));
+ // Another work around for spurious WrongPassword returns of
+ // build_aes_key after a factory reset on Pro devices.
+ // https://github.com/Nitrokey/nitrokey-pro-firmware/issues/57
+ let _ = device.get_user_retry_count();
+ device.build_aes_key(NITROKEY_DEFAULT_ADMIN_PIN)
+ })
+}
+
/// Open the encrypted volume on the nitrokey.
pub fn storage_open(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
let device = get_storage_device(ctx)?;