Commit 81fd7cff authored by Marcus Pedersén's avatar Marcus Pedersén
Browse files

Added functionality to erase slot

parent e08fb6f4
......@@ -25,7 +25,7 @@ extern crate rpassword;
extern crate chrono;
use clap::{Arg, App, ArgMatches};
use nitrokey::{Device, Pro, GenerateOtp, Authenticate};
use nitrokey::{Device, Pro, GenerateOtp, ConfigureOtp, Authenticate};
use chrono::Local;
use std::process::exit;
use std::collections::HashMap;
......@@ -89,6 +89,19 @@ fn main() {
Err(_) => exit(1),
}
}
else if matches.is_present("ERASETOTP") {
match erase_slot(device, CodeType::Totp) {
Ok(_) => (),
Err(_) => exit(1),
}
}
else if matches.is_present("ERASEHOTP") {
match erase_slot(device, CodeType::Hotp) {
Ok(_) => (),
Err(_) => exit(1),
}
}
}
......@@ -168,13 +181,13 @@ fn get_code( device: Pro, ctype: CodeType) -> Result<(), ()> {
let slot_no;
if ctype == CodeType::Totp {
slot_no = match get_slot_from_user(CodeType::Totp) {
slot_no = match get_slot_from_user(&CodeType::Totp) {
Ok(n) => n,
Err(_) => return Err(()),
};
}
else {
slot_no = match get_slot_from_user(CodeType::Hotp) {
slot_no = match get_slot_from_user(&CodeType::Hotp) {
Ok(n) => n,
Err(_) => return Err(()),
};
......@@ -311,14 +324,14 @@ fn get_code( device: Pro, ctype: CodeType) -> Result<(), ()> {
/// that value is within valid values
/// Different values if totp or hotp
/// Returns chosen slot
fn get_slot_from_user(t: CodeType) -> Result<u8, ()> {
fn get_slot_from_user(t: &CodeType) -> Result<u8, ()> {
let mut got_slot = false;
let mut slot_no: u8 = 0;
while !got_slot {
println!("");
if t == CodeType::Totp {
if *t == CodeType::Totp {
println!("Number of slot to get (1-15): ");
}
else {
......@@ -344,7 +357,7 @@ fn get_slot_from_user(t: CodeType) -> Result<u8, ()> {
},
}
if t == CodeType::Totp {
if *t == CodeType::Totp {
if slot_no > 15 || slot_no < 1 {
eprintln!("Integer must be between 1 and 15");
continue;
......@@ -519,6 +532,85 @@ fn unlock_user_pin(device: Pro) -> Result<(), ()> {
Ok(())
}
/// Erase slot from Nitrokey Pro
/// Totp or hotp is given as argument
fn erase_slot(device: Pro, t: CodeType) -> Result<(), ()> {
let mut got_pin = false;
let mut adm_pw: String = String::new();
let no_admin_retry = device.get_admin_retry_count();
println!("{} remaining authentication attempts (admin)", no_admin_retry);
while !got_pin {
adm_pw = match rpassword::prompt_password_stdout("Admin PIN: ") {
Ok(p) => p,
Err(e) => {
eprintln!("Error getting PIN from user: {}", e.to_string());
return Err(());
},
};
let pw_split: Vec<&str> = adm_pw.matches(char::is_numeric).collect();
if adm_pw.len() != pw_split.len() {
eprintln!("Error PIN is not only numeric, try again");
continue;
}
got_pin = true;
}
match device.authenticate_admin(adm_pw.as_str()) {
Ok(admin) => {
if let Ok(slot) = get_slot_from_user(&t) {
println!("Are you sure that you want to erase slot number {}: [Y/N]?", slot + 1);
let mut show_slot = String::new();
match io::stdin().read_line(&mut show_slot) {
Ok(_) => (),
Err(e) => {
eprintln!("Error reading from stdin: {}", e.to_string());
return Err(());
},
}
show_slot = show_slot.to_lowercase();
if show_slot.trim() == "y" || show_slot.trim() == "yes" {
if t == CodeType::Totp {
match admin.erase_totp_slot(slot) {
Ok(()) => println!("Slot {} successfully erased", slot + 1),
Err(e) => {
eprintln!("Error erasing slot {}: {}", slot + 1, e);
return Err(());
},
}
}
else {
match admin.erase_hotp_slot(slot) {
Ok(()) => println!("Slot {} successfully erased", slot + 1),
Err(e) => {
eprintln!("Error erasing slot {}: {}", slot + 1, e);
return Err(());
},
}
}
}
}
else {
return Err(());
}
},
Err(e) => {
eprintln!("Error authenticate admin: {:?}", e);
return Err(());
},
}
Ok(())
}
/// Asks user for new PIN
/// Erro checks and returns
/// a valid PIN
......@@ -595,33 +687,45 @@ fn arg_matches() -> ArgMatches<'static> {
.arg(Arg::with_name("TOTP")
.short("t")
.long("totp")
.conflicts_with_all(&["ADMINPIN", "HOTP", "USERPIN", "UNLOCKPIN"])
.conflicts_with_all(&["ADMINPIN", "HOTP", "USERPIN", "UNLOCKPIN", "ERASETOTP", "ERASEHOTP"])
.takes_value(false)
.help("Get totp code"))
.arg(Arg::with_name("HOTP")
.short("o")
.long("hotp")
.conflicts_with_all(&["ADMINPIN", "TOTP", "USERPIN", "UNLOCKPIN"])
.conflicts_with_all(&["ADMINPIN", "TOTP", "USERPIN", "UNLOCKPIN", "ERASETOTP", "ERASEHOTP"])
.takes_value(false)
.help("Get hotp code"))
.arg(Arg::with_name("USERPIN")
.short("u")
.long("user-pin")
.conflicts_with_all(&["TOTP", "HOTP", "ADMINPIN", "UNLOCKPIN"])
.conflicts_with_all(&["TOTP", "HOTP", "ADMINPIN", "UNLOCKPIN", "ERASETOTP", "ERASEHOTP"])
.takes_value(false)
.help("Change user pin"))
.arg(Arg::with_name("ADMINPIN")
.short("a")
.long("admin-pin")
.conflicts_with_all(&["TOTP", "HOTP", "USERPIN", "UNLOCKPIN"])
.conflicts_with_all(&["TOTP", "HOTP", "USERPIN", "UNLOCKPIN", "ERASETOTP", "ERASEHOTP"])
.takes_value(false)
.help("Change admin pin"))
.arg(Arg::with_name("UNLOCKPIN")
.short("l")
.long("unlock-pin")
.conflicts_with_all(&["TOTP", "HOTP", "USERPIN", "ADMINPIN"])
.conflicts_with_all(&["TOTP", "HOTP", "USERPIN", "ADMINPIN", "ERASETOTP", "ERASEHOTP"])
.takes_value(false)
.help("Unlocks user pin after three failed login attempts"))
.arg(Arg::with_name("ERASETOTP")
.short("e")
.long("erase-totp")
.conflicts_with_all(&["TOTP", "HOTP", "USERPIN", "ADMINPIN", "UNLOCKPIN", "ERASEHOTP"])
.takes_value(false)
.help("Erase totp slot"))
.arg(Arg::with_name("ERASEHOTP")
.short("d")
.long("erase-hotp")
.conflicts_with_all(&["TOTP", "HOTP", "USERPIN", "ADMINPIN", "UNLOCKPIN", "ERASETOTP"])
.takes_value(false)
.help("Erase hotp slot"))
.after_help(" With no argument get response if can connect to key
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment