aboutsummaryrefslogtreecommitdiff
path: root/nitrocli/src
diff options
context:
space:
mode:
Diffstat (limited to 'nitrocli/src')
-rw-r--r--nitrocli/src/args.rs10
-rw-r--r--nitrocli/src/commands.rs26
2 files changed, 36 insertions, 0 deletions
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)?;