Implement, document PIN management in opgpcard
This commit is contained in:
parent
fbdb9e87b2
commit
99e0c6caaf
4 changed files with 417 additions and 71 deletions
190
tools/README.md
190
tools/README.md
|
@ -5,8 +5,8 @@ SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
# OpenPGP card tools
|
# OpenPGP card tools
|
||||||
|
|
||||||
This crate contains two tools for inspecting, configuring and using OpenPGP
|
This crate contains the `opgpcard` tool for inspecting, configuring and using OpenPGP
|
||||||
cards: `opgpcard` and `opgpcard-pin`.
|
cards.
|
||||||
|
|
||||||
# Install
|
# Install
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ binaries.
|
||||||
## opgpcard
|
## opgpcard
|
||||||
|
|
||||||
A tool to inspect, configure and use OpenPGP cards. All calls of this tool are
|
A tool to inspect, configure and use OpenPGP cards. All calls of this tool are
|
||||||
usable in a non-interactive way (this tool is designed to be easily usable from
|
usable in a non-interactive way (this tool is designed both for interactive use, and to be easily usable from
|
||||||
shell-scripts).
|
shell-scripts).
|
||||||
|
|
||||||
Alternatively, PINs can be entered interactively on the host computer, or via a pinpad on the smartcard reader,
|
Alternatively, PINs can be entered interactively on the host computer, or via a pinpad on the smartcard reader,
|
||||||
|
@ -413,6 +413,120 @@ or interactively
|
||||||
$ opgpcard decrypt -c ABCD:01234567 -r <cert-file> <input-file>
|
$ opgpcard decrypt -c ABCD:01234567 -r <cert-file> <input-file>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### PIN management
|
||||||
|
|
||||||
|
OpenPGP cards use PINs (numerical passwords) to verify that a user is allowed to perform an operation.
|
||||||
|
|
||||||
|
To use the cryptographic operations on a card (such as decryption or signing), the *User PIN* is required.
|
||||||
|
|
||||||
|
To configure a card (for example to import OpenPGP key material into the card's key slots), the *Admin PIN* is needed.
|
||||||
|
|
||||||
|
By default, on unconfigured (or factory reset) cards, the User PIN is typically set to `123456`,
|
||||||
|
and the Admin PIN is set to `12345678`.
|
||||||
|
|
||||||
|
#### Blocked cards and resetting
|
||||||
|
|
||||||
|
When a user has entered a wrong User PIN too often, the card goes into a blocked state, in which presenting the
|
||||||
|
User PIN successfully is not possible anymore. The purpose of this is to prevent attackers from trying all possible
|
||||||
|
PINs (e.g. after stealing a card).
|
||||||
|
|
||||||
|
To be able to use the card again, the user PIN must be "reset".
|
||||||
|
|
||||||
|
A user PIN reset can be performed by presenting the Admin PIN.
|
||||||
|
|
||||||
|
#### The resetting code
|
||||||
|
|
||||||
|
OpenPGP cards offer an additional, optional, *Resetting Code* mechanism.
|
||||||
|
|
||||||
|
The resetting code may be configured on a card and used to reset the User PIN if it has been forgotten or blocked.
|
||||||
|
When unblocking a card with the Resetting Code, the Admin PIN is not needed.
|
||||||
|
|
||||||
|
The Resetting Code mechanism is only useful in scenarios where a user doesn't have access to (or prefers not to use)
|
||||||
|
the Admin PIN (e.g. in some corporate settings, users might not be given the Admin PIN for
|
||||||
|
their cards. Instead, an admin may define a resetting code and give that code to the user).
|
||||||
|
|
||||||
|
On unconfigured (or factory reset) cards, the Resetting Code is typically unset.
|
||||||
|
|
||||||
|
|
||||||
|
#### Set a new user PIN
|
||||||
|
|
||||||
|
Setting a new user PIN requires the admin PIN:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opgpcard pin -c ABCD:01234567 set-user
|
||||||
|
```
|
||||||
|
|
||||||
|
For non-interactive PIN change:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opgpcard pin -c ABCD:01234567 set-user -p <old-user-pin-file> -q <new-user-pin-file>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Set new admin PIN
|
||||||
|
|
||||||
|
This requires the (previous) admin PIN.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opgpcard pin -c ABCD:01234567 set-admin
|
||||||
|
```
|
||||||
|
|
||||||
|
For non-interactive PIN change:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opgpcard pin -c ABCD:01234567 set-admin -p <old-admin-pin-file> -q <new-admin-pin-file>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Reset user PIN with admin PIN
|
||||||
|
|
||||||
|
The user PIN can be reset to a different (or the same) PIN by providing the admin PIN.
|
||||||
|
This is possible at any time, including when a wrong user PIN has been entered too often, and the card refuses to accept the user PIN any more.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opgpcard pin -c ABCD:01234567 reset-user
|
||||||
|
```
|
||||||
|
|
||||||
|
For non-interactive PIN change:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opgpcard pin -c ABCD:01234567 reset-user -P <admin-pin-file> -p <new-user-pin-file>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Configuring the resetting code
|
||||||
|
|
||||||
|
The resetting code is an alternative mechanism to recover from a lost or locked user PIN.
|
||||||
|
|
||||||
|
You can set the resetting code after verifying the admin PIN. Once a resetting code is configured on your card,
|
||||||
|
you can use that code to reset the user PIN without needing the admin PIN.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opgpcard pin -c 0006:16019180 set-reset
|
||||||
|
```
|
||||||
|
|
||||||
|
To non-interactively set the resetting code:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opgpcard pin -c 0006:16019180 set-reset -P <admin-pin-file> -r <resetting-code-file>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Reset user PIN with the resetting code
|
||||||
|
|
||||||
|
If a resetting code is configured on a card, you can use that code to reset the user PIN:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opgpcard pin -c 0006:16019180 reset-user-rc
|
||||||
|
Enter resetting code:
|
||||||
|
Enter new user PIN:
|
||||||
|
Repeat the new user PIN:
|
||||||
|
|
||||||
|
User PIN has been set.
|
||||||
|
```
|
||||||
|
|
||||||
|
To non-interactively use the resetting code:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opgpcard pin -c 0006:16019180 reset-user-rc -r <resetting-code-file> -p <new-user-pin-file>
|
||||||
|
```
|
||||||
|
|
||||||
### Factory reset
|
### Factory reset
|
||||||
|
|
||||||
Factory reset:
|
Factory reset:
|
||||||
|
@ -427,7 +541,7 @@ NOTE: you do not need a PIN to reset a card!
|
||||||
|
|
||||||
When using a shell like
|
When using a shell like
|
||||||
[bash](https://www.gnu.org/software/bash/manual/html_node/Redirections.html#Here-Strings)
|
[bash](https://www.gnu.org/software/bash/manual/html_node/Redirections.html#Here-Strings)
|
||||||
, you can pass user and/or admin PINs via file-descriptors:
|
, you can pass user and/or admin PINs via file-descriptors (instead of from a file on disk):
|
||||||
|
|
||||||
```
|
```
|
||||||
$ opgpcard sign --detached -c ABCD:01234567 -p /dev/fd/3 -s <cert-file> 3<<<123456
|
$ opgpcard sign --detached -c ABCD:01234567 -p /dev/fd/3 -s <cert-file> 3<<<123456
|
||||||
|
@ -440,70 +554,6 @@ $ opgpcard admin -c ABCD:01234567 -P /dev/fd/3 generate -p /dev/fd/4 -o <output-
|
||||||
### Directly entering PINs on card readers with pinpad
|
### Directly entering PINs on card readers with pinpad
|
||||||
|
|
||||||
If your OpenPGP card is inserted in a card reader with a pinpad, this tool
|
If your OpenPGP card is inserted in a card reader with a pinpad, this tool
|
||||||
offers you the option to use the pinpad to enter the user- or admin-PINs.
|
offers you the option to use the pinpad to enter the User- or Admin PINs.
|
||||||
To do this, you can omit the `-p` and/or '`-P`' parameters - then you will
|
To do this, you can omit the `-p` and/or `-P` parameters. Then you will
|
||||||
be prompted to enter the user or admin PINs where needed.
|
be prompted to enter the user or admin PINs where needed.
|
||||||
|
|
||||||
## opgpcard-pin
|
|
||||||
|
|
||||||
An interactive tool to set the admin and user PINs, and to reset the user PIN
|
|
||||||
on OpenPGP cards.
|
|
||||||
|
|
||||||
### Set a new user PIN
|
|
||||||
|
|
||||||
Setting a new user PIN requires the admin PIN:
|
|
||||||
|
|
||||||
```
|
|
||||||
opgpcard-pin -c ABCD:01234567 set-user-pin
|
|
||||||
```
|
|
||||||
(The default admin PIN on unconfigured cards is typically `12345678`)
|
|
||||||
|
|
||||||
### Set new admin PIN
|
|
||||||
|
|
||||||
This requires the (previous) admin PIN.
|
|
||||||
|
|
||||||
```
|
|
||||||
opgpcard-pin -c ABCD:01234567 set-admin-pin
|
|
||||||
```
|
|
||||||
|
|
||||||
(The default admin PIN on unconfigured cards is typically `12345678`)
|
|
||||||
|
|
||||||
### Recover from blocked user PIN (using the admin PIN)
|
|
||||||
|
|
||||||
When a user has entered a wrong user PIN too often, the card goes into a blocked state, in which presenting the
|
|
||||||
user PIN is not possible anymore. The purpose of this is to prevent attackers from trying all possible PINs
|
|
||||||
(e.g. after stealing a card).
|
|
||||||
|
|
||||||
To be able to use the card again, the user PIN must be "reset".
|
|
||||||
|
|
||||||
Reset user PIN after it has been blocked (requires admin PIN):
|
|
||||||
|
|
||||||
```
|
|
||||||
opgpcard-pin -c ABCD:01234567 reset-user-pin -a
|
|
||||||
```
|
|
||||||
|
|
||||||
### Recover from blocked user PIN (using the resetting code)
|
|
||||||
|
|
||||||
The resetting code is an optional/alternative method to recover from a blocked user PIN.
|
|
||||||
|
|
||||||
Context: in some (e.g. corporate) settings, users might not be given the admin PIN for their cards.
|
|
||||||
Instead, an admin may define a resetting code and give that code to the user.
|
|
||||||
|
|
||||||
Set resetting code (requires admin PIN):
|
|
||||||
|
|
||||||
```
|
|
||||||
opgpcard-pin -c ABCD:01234567 set-reset-code
|
|
||||||
```
|
|
||||||
|
|
||||||
Once a reset code has been defined, the user can
|
|
||||||
reset the blocked user PIN, using the resetting code:
|
|
||||||
|
|
||||||
```
|
|
||||||
opgpcard-pin -c ABCD:01234567 reset-user-pin
|
|
||||||
```
|
|
||||||
|
|
||||||
### Directly entering PINs on card readers with pinpad
|
|
||||||
|
|
||||||
If your OpenPGP card is inserted in a card reader with a pinpad, this tool
|
|
||||||
assumes you will want to enter all PINs via that pinpad. It will prompt
|
|
||||||
you to enter PINs accordingly.
|
|
|
@ -63,6 +63,13 @@ pub enum Command {
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
cmd: AdminCommand,
|
cmd: AdminCommand,
|
||||||
},
|
},
|
||||||
|
Pin {
|
||||||
|
#[clap(name = "card ident", short = 'c', long = "card")]
|
||||||
|
ident: String,
|
||||||
|
|
||||||
|
#[clap(subcommand)]
|
||||||
|
cmd: PinCommand,
|
||||||
|
},
|
||||||
Decrypt {
|
Decrypt {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(name = "card ident", short = 'c', long = "card")]
|
||||||
ident: String,
|
ident: String,
|
||||||
|
@ -144,3 +151,51 @@ pub enum AdminCommand {
|
||||||
algo: Option<String>,
|
algo: Option<String>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
pub enum PinCommand {
|
||||||
|
/// Set User PIN
|
||||||
|
SetUser {
|
||||||
|
#[clap(name = "User PIN file old", short = 'p', long = "user-pin-old")]
|
||||||
|
user_pin_old: Option<PathBuf>,
|
||||||
|
|
||||||
|
#[clap(name = "User PIN file new", short = 'q', long = "user-pin-new")]
|
||||||
|
user_pin_new: Option<PathBuf>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Set Admin PIN
|
||||||
|
SetAdmin {
|
||||||
|
#[clap(name = "Admin PIN file old", short = 'P', long = "admin-pin-old")]
|
||||||
|
admin_pin_old: Option<PathBuf>,
|
||||||
|
|
||||||
|
#[clap(name = "Admin PIN file new", short = 'Q', long = "admin-pin-new")]
|
||||||
|
admin_pin_new: Option<PathBuf>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Reset User PIN with admin PIN
|
||||||
|
ResetUser {
|
||||||
|
#[clap(name = "Admin PIN file", short = 'P', long = "admin-pin")]
|
||||||
|
admin_pin: Option<PathBuf>,
|
||||||
|
|
||||||
|
#[clap(name = "User PIN file new", short = 'p', long = "user-pin-new")]
|
||||||
|
user_pin_new: Option<PathBuf>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Set Resetting Code
|
||||||
|
SetReset {
|
||||||
|
#[clap(name = "Admin PIN file", short = 'P', long = "admin-pin")]
|
||||||
|
admin_pin: Option<PathBuf>,
|
||||||
|
|
||||||
|
#[clap(name = "Resetting code file", short = 'r', long = "reset-code")]
|
||||||
|
reset_code: Option<PathBuf>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Reset User PIN with 'resetting code'
|
||||||
|
ResetUserRc {
|
||||||
|
#[clap(name = "Resetting code file", short = 'r', long = "reset-code")]
|
||||||
|
reset_code: Option<PathBuf>,
|
||||||
|
|
||||||
|
#[clap(name = "User PIN file new", short = 'p', long = "user-pin-new")]
|
||||||
|
user_pin_new: Option<PathBuf>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ use openpgp_card_sequoia::util::{
|
||||||
};
|
};
|
||||||
use openpgp_card_sequoia::{sq_util, PublicKey};
|
use openpgp_card_sequoia::{sq_util, PublicKey};
|
||||||
|
|
||||||
|
use crate::util::{load_pin, print_gnuk_note};
|
||||||
use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm};
|
use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
|
@ -141,6 +142,210 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cli::Command::Pin { ident, cmd } => {
|
||||||
|
let mut card = util::open_card(&ident)?;
|
||||||
|
let mut pgp = OpenPgp::new(&mut card);
|
||||||
|
let pgpt = pgp.transaction()?;
|
||||||
|
|
||||||
|
let pinpad_modify = pgpt.feature_pinpad_modify();
|
||||||
|
|
||||||
|
let mut open = Open::new(pgpt)?;
|
||||||
|
|
||||||
|
match cmd {
|
||||||
|
cli::PinCommand::SetUser {
|
||||||
|
user_pin_old,
|
||||||
|
user_pin_new,
|
||||||
|
} => {
|
||||||
|
let res = if !pinpad_modify {
|
||||||
|
// get current user pin
|
||||||
|
let user_pin1 = util::get_pin(&mut open, user_pin_old, ENTER_USER_PIN)
|
||||||
|
.expect("this should never be None");
|
||||||
|
|
||||||
|
// verify pin
|
||||||
|
open.verify_user(&user_pin1)?;
|
||||||
|
println!("PIN was accepted by the card.\n");
|
||||||
|
|
||||||
|
let pin_new = match user_pin_new {
|
||||||
|
None => {
|
||||||
|
// ask user for new user pin
|
||||||
|
util::input_pin_twice(
|
||||||
|
"Enter new user PIN: ",
|
||||||
|
"Repeat the new user PIN: ",
|
||||||
|
)?
|
||||||
|
}
|
||||||
|
Some(path) => load_pin(&path)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
// set new user pin
|
||||||
|
open.change_user_pin(&user_pin1, &pin_new)
|
||||||
|
} else {
|
||||||
|
// set new user pin via pinpad
|
||||||
|
open.change_user_pin_pinpad(&|| {
|
||||||
|
println!(
|
||||||
|
"Enter old user PIN on card reader pinpad, then new user PIN (twice)."
|
||||||
|
)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
if res.is_err() {
|
||||||
|
println!("\nFailed to change the user PIN!");
|
||||||
|
println!("{:?}", res);
|
||||||
|
|
||||||
|
if let Err(err) = res {
|
||||||
|
print_gnuk_note(err, &open)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("\nUser PIN has been set.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cli::PinCommand::SetAdmin {
|
||||||
|
admin_pin_old,
|
||||||
|
admin_pin_new,
|
||||||
|
} => {
|
||||||
|
if !pinpad_modify {
|
||||||
|
// get current admin pin
|
||||||
|
let admin_pin1 = util::get_pin(&mut open, admin_pin_old, ENTER_ADMIN_PIN)
|
||||||
|
.expect("this should never be None");
|
||||||
|
|
||||||
|
// verify pin
|
||||||
|
open.verify_admin(&admin_pin1)?;
|
||||||
|
println!("PIN was accepted by the card.\n");
|
||||||
|
|
||||||
|
let pin_new = match admin_pin_new {
|
||||||
|
None => {
|
||||||
|
// ask user for new admin pin
|
||||||
|
util::input_pin_twice(
|
||||||
|
"Enter new admin PIN: ",
|
||||||
|
"Repeat the new admin PIN: ",
|
||||||
|
)?
|
||||||
|
}
|
||||||
|
Some(path) => load_pin(&path)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
// set new admin pin
|
||||||
|
open.change_admin_pin(&admin_pin1, &pin_new)?;
|
||||||
|
} else {
|
||||||
|
// set new admin pin via pinpad
|
||||||
|
open.change_admin_pin_pinpad(&|| {
|
||||||
|
println!(
|
||||||
|
"Enter old admin PIN on card reader pinpad, then new admin PIN (twice)."
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("\nAdmin PIN has been set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
cli::PinCommand::ResetUser {
|
||||||
|
admin_pin,
|
||||||
|
user_pin_new,
|
||||||
|
} => {
|
||||||
|
// verify admin pin
|
||||||
|
match util::get_pin(&mut open, admin_pin, ENTER_ADMIN_PIN) {
|
||||||
|
Some(admin_pin) => {
|
||||||
|
// verify pin
|
||||||
|
open.verify_admin(&admin_pin)?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
open.verify_admin_pinpad(&|| println!("Enter admin PIN on pinpad."))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("PIN was accepted by the card.\n");
|
||||||
|
|
||||||
|
// ask user for new user pin
|
||||||
|
let pin = match user_pin_new {
|
||||||
|
None => util::input_pin_twice(
|
||||||
|
"Enter new user PIN: ",
|
||||||
|
"Repeat the new user PIN: ",
|
||||||
|
)?,
|
||||||
|
Some(path) => load_pin(&path)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = if let Some(mut admin) = open.admin_card() {
|
||||||
|
admin.reset_user_pin(&pin)
|
||||||
|
} else {
|
||||||
|
return Err(anyhow::anyhow!("Failed to use card in admin-mode.").into());
|
||||||
|
};
|
||||||
|
|
||||||
|
if res.is_err() {
|
||||||
|
println!("\nFailed to change the user PIN!");
|
||||||
|
if let Err(err) = res {
|
||||||
|
print_gnuk_note(err, &open)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("\nUser PIN has been set.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cli::PinCommand::SetReset {
|
||||||
|
admin_pin,
|
||||||
|
reset_code,
|
||||||
|
} => {
|
||||||
|
// verify admin pin
|
||||||
|
match util::get_pin(&mut open, admin_pin, ENTER_ADMIN_PIN) {
|
||||||
|
Some(admin_pin) => {
|
||||||
|
// verify pin
|
||||||
|
open.verify_admin(&admin_pin)?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
open.verify_admin_pinpad(&|| println!("Enter admin PIN on pinpad."))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("PIN was accepted by the card.\n");
|
||||||
|
|
||||||
|
// ask user for new resetting code
|
||||||
|
let code = match reset_code {
|
||||||
|
None => util::input_pin_twice(
|
||||||
|
"Enter new resetting code: ",
|
||||||
|
"Repeat the new resetting code: ",
|
||||||
|
)?,
|
||||||
|
Some(path) => load_pin(&path)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(mut admin) = open.admin_card() {
|
||||||
|
admin.set_resetting_code(&code)?;
|
||||||
|
println!("\nResetting code has been set.");
|
||||||
|
} else {
|
||||||
|
return Err(anyhow::anyhow!("Failed to use card in admin-mode.").into());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
cli::PinCommand::ResetUserRc {
|
||||||
|
reset_code,
|
||||||
|
user_pin_new,
|
||||||
|
} => {
|
||||||
|
// reset by presenting resetting code
|
||||||
|
|
||||||
|
let rst = if let Some(path) = reset_code {
|
||||||
|
// load resetting code from file
|
||||||
|
load_pin(&path)?
|
||||||
|
} else {
|
||||||
|
// input resetting code
|
||||||
|
rpassword::read_password_from_tty(Some("Enter resetting code: "))?
|
||||||
|
.as_bytes()
|
||||||
|
.to_vec()
|
||||||
|
};
|
||||||
|
|
||||||
|
// ask user for new user pin
|
||||||
|
let pin = match user_pin_new {
|
||||||
|
None => util::input_pin_twice(
|
||||||
|
"Enter new user PIN: ",
|
||||||
|
"Repeat the new user PIN: ",
|
||||||
|
)?,
|
||||||
|
Some(path) => load_pin(&path)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
// reset to new user pin
|
||||||
|
match open.reset_user_pin(&rst, &pin) {
|
||||||
|
Err(err) => {
|
||||||
|
println!("\nFailed to change the user PIN!");
|
||||||
|
print_gnuk_note(err, &open)?;
|
||||||
|
}
|
||||||
|
Ok(_) => println!("\nUser PIN has been set."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use openpgp_card::algorithm::{Algo, Curve};
|
use openpgp_card::algorithm::{Algo, Curve};
|
||||||
use openpgp_card::crypto_data::{EccType, PublicKeyMaterial};
|
use openpgp_card::crypto_data::{EccType, PublicKeyMaterial};
|
||||||
use openpgp_card::{CardBackend, Error};
|
use openpgp_card::{CardBackend, Error, StatusBytes};
|
||||||
use openpgp_card_pcsc::PcscBackend;
|
use openpgp_card_pcsc::PcscBackend;
|
||||||
use openpgp_card_sequoia::card::{Admin, Open, Sign, User};
|
use openpgp_card_sequoia::card::{Admin, Open, Sign, User};
|
||||||
|
|
||||||
|
@ -37,6 +37,19 @@ pub(crate) fn get_pin(open: &mut Open, pin_file: Option<PathBuf>, msg: &str) ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Let the user input a PIN twice, return PIN if both entries match, error otherwise
|
||||||
|
pub(crate) fn input_pin_twice(msg1: &str, msg2: &str) -> Result<Vec<u8>> {
|
||||||
|
// get new user pin
|
||||||
|
let newpin1 = rpassword::read_password_from_tty(Some(msg1))?;
|
||||||
|
let newpin2 = rpassword::read_password_from_tty(Some(msg2))?;
|
||||||
|
|
||||||
|
if newpin1 != newpin2 {
|
||||||
|
Err(anyhow::anyhow!("PINs do not match."))
|
||||||
|
} else {
|
||||||
|
Ok(newpin1.as_bytes().to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn verify_to_user<'app, 'open>(
|
pub(crate) fn verify_to_user<'app, 'open>(
|
||||||
open: &'open mut Open<'app>,
|
open: &'open mut Open<'app>,
|
||||||
pin: Option<&[u8]>,
|
pin: Option<&[u8]>,
|
||||||
|
@ -195,3 +208,26 @@ pub(crate) fn get_ssh_pubkey_string(pkm: &PublicKeyMaterial, ident: String) -> R
|
||||||
|
|
||||||
Ok(s.trim().into())
|
Ok(s.trim().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gnuk doesn't allow the User password (pw1) to be changed while no
|
||||||
|
/// private key material exists on the card.
|
||||||
|
///
|
||||||
|
/// This fn checks for Gnuk's Status code and the case that no keys exist
|
||||||
|
/// on the card, and prints a note to the user, pointing out that the
|
||||||
|
/// absence of keys on the card might be the reason for the error they get.
|
||||||
|
pub(crate) fn print_gnuk_note(err: Error, card: &Open) -> Result<()> {
|
||||||
|
if matches!(
|
||||||
|
err,
|
||||||
|
Error::CardStatus(StatusBytes::ConditionOfUseNotSatisfied)
|
||||||
|
) {
|
||||||
|
// check if no keys exist on the card
|
||||||
|
let fps = card.fingerprints()?;
|
||||||
|
if fps.signature() == None && fps.decryption() == None && fps.authentication() == None {
|
||||||
|
println!(
|
||||||
|
"\nNOTE: Some cards (e.g. Gnuk) don't allow \
|
||||||
|
User PIN change while no keys exist on the card."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue