From f9d69dbefb06a81e9058bea00412696fdb70bae2 Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Sun, 29 May 2022 21:27:52 +0200 Subject: [PATCH] Implement 'opgpcard admin touch' to set the touch confirmation policy. --- tools/README.md | 33 ++++++++++++++++++++++++++++++++- tools/src/bin/opgpcard/cli.rs | 13 +++++++++++++ tools/src/bin/opgpcard/main.rs | 29 +++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/tools/README.md b/tools/README.md index 0d0717b..cf7edfd 100644 --- a/tools/README.md +++ b/tools/README.md @@ -127,7 +127,7 @@ Authentication key Remaining PIN attempts: User: 3, Admin: 3, Reset Code: 0 -Touch policy attestation: Cached [Features: Button] +Touch policy attestation: Cached [Features: Button] Key Status (#129): imported ``` @@ -291,6 +291,37 @@ for non-interactive use. Alternatively, the PIN can be entered interactively on the host computer, or via a pinpad if the OpenPGP card is used in a smartcard reader that has a pinpad. +#### Set touch policy + +Cards can require a type of confirmation before cryptographic operations are performed +(the feature is often implemented as a mechanical button on the card). + +Not all cards implement this feature. + +Rationale: when the card requires touch confirmation, an attacker who gains control of the user's host computer +cannot perform cryptographic operations on the card at will - even after they learn the user's PINs. + +This feature is configured per key slot. The user can choose to require (or not require) touch confirmation separately +for signing, decryption, authentication and attestation operations. + +E.g., when the touch policy is set to `On` for the `SIG` key slot, then every signing operation requires a touch button +confirmation: + +``` +opgpcard admin -c ABCD:01234567 touch --key SIG --policy On +``` + +Valid values for the key slot are: `SIG`, `DEC`, `AUT`, `ATT` (some cards only support the first three). + +Available policies can include: `Off`, `On`, `Fixed`, `Cached`, `CachedFixed`. +Some cards only support a subset of these. + +- `Off` means that no touch confirmation is required. +- `On` means that each operation requires on touch confirmation. +- The `Fixed` policies are like `On`, but the policies cannot be changed without performing a factory reset on the card. +- With the `Cached` policies, a touch confirmation is valid for multiple operations within 15 seconds. + + #### Set cardholder name Set cardholder name, with pin file: diff --git a/tools/src/bin/opgpcard/cli.rs b/tools/src/bin/opgpcard/cli.rs index 31efbfc..7e52926 100644 --- a/tools/src/bin/opgpcard/cli.rs +++ b/tools/src/bin/opgpcard/cli.rs @@ -182,6 +182,19 @@ pub enum AdminCommand { #[clap()] algo: Option, }, + + /// Set touch policy + Touch { + #[clap(name = "Key slot (SIG|DEC|AUT|ATT)", short = 'k', long = "key")] + key: String, + + #[clap( + name = "Policy (Off|On|Fixed|Cached|Cached-Fixed)", + short = 'p', + long = "policy" + )] + policy: String, + }, } #[derive(Parser, Debug)] diff --git a/tools/src/bin/opgpcard/main.rs b/tools/src/bin/opgpcard/main.rs index 5243bed..148c93c 100644 --- a/tools/src/bin/opgpcard/main.rs +++ b/tools/src/bin/opgpcard/main.rs @@ -12,7 +12,7 @@ use sequoia_openpgp::serialize::SerializeInto; use sequoia_openpgp::Cert; use openpgp_card::algorithm::AlgoSimple; -use openpgp_card::card_do::Sex; +use openpgp_card::card_do::{Sex, TouchPolicy}; use openpgp_card::{CardBackend, KeyType, OpenPgp}; use openpgp_card_sequoia::card::{Admin, Open}; use openpgp_card_sequoia::util::{ @@ -221,6 +221,31 @@ fn main() -> Result<(), Box> { algo, )?; } + cli::AdminCommand::Touch { key, policy } => { + let kt = match key.as_str() { + "SIG" => KeyType::Signing, + "DEC" => KeyType::Decryption, + "AUT" => KeyType::Authentication, + "ATT" => KeyType::Attestation, + _ => { + return Err(anyhow!("Unexpected Key Type {}", key).into()); + } + }; + let pol = match policy.as_str() { + "Off" => TouchPolicy::Off, + "On" => TouchPolicy::On, + "Fixed" => TouchPolicy::Fixed, + "Cached" => TouchPolicy::Cached, + "Cached-Fixed" => TouchPolicy::CachedFixed, + _ => { + return Err(anyhow!("Unexpected Policy {}", policy).into()); + } + }; + + let mut admin = util::verify_to_admin(&mut open, admin_pin.as_deref())?; + + let _ = admin.set_uif(kt, pol)?; + } } } cli::Command::Pin { ident, cmd } => { @@ -667,7 +692,7 @@ fn print_status(ident: Option, verbose: bool, pkm: bool) -> Result<()> { if let Some(uif) = ard.uif_attestation()? { println!( - "Touch policy attestation: {} [Features: {}]", + "Touch policy attestation: {} [Features: {}]", uif.touch_policy(), uif.features() );