diff --git a/src/lib.rs b/src/lib.rs index e8fdac5..4ec58ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -202,12 +202,17 @@ where YubicoPivExtension::Reset => { let this = self.load()?; + if this.state.persistent.remaining_pin_retries(this.trussed) != 0 { + return Err(Status::ConditionsOfUseNotSatisfied); + } // TODO: find out what all needs resetting :) for location in [Location::Volatile, Location::External, Location::Internal] { try_syscall!(this.trussed.delete_all(location)).ok(); try_syscall!(this.trussed.remove_dir_all(location, PathBuf::new())).ok(); } + try_syscall!(this.trussed.delete_all_pins()).ok(); + self.state.persistent = None; } YubicoPivExtension::SetManagementKey(touch_policy) => { diff --git a/tests/command_response.ron b/tests/command_response.ron index d1489dd..1c61dec 100644 --- a/tests/command_response.ron +++ b/tests/command_response.ron @@ -5,8 +5,9 @@ IoTest( name: "Verify", cmd_resp: [ - VerifyDefaultApplicationPin(), - VerifyDefaultGlobalPin(expected_status: FunctionNotSupported) + VerifyApplicationPin(), + VerifyApplicationPin(pin: "FFEEDDCCBBAA9988", expected_status: RemainingRetries(2)), + VerifyGlobalPin(expected_status: FunctionNotSupported) ] ), IoTest( @@ -126,5 +127,17 @@ output: Data("7e 10 000102030405060708090A0B0C0D0E0F") ), ] - ) + ), + IoTest( + name: "RESET FAILED", + cmd_resp: [ + Reset( + expected_status: ConditionsOfUseNotSatisfied, + ), + VerifyApplicationPin(pin: "FFEEDDCCBBAA9988", expected_status: RemainingRetries(2)), + VerifyApplicationPin(pin: "FFEEDDCCBBAA9988", expected_status: RemainingRetries(1)), + VerifyApplicationPin(pin: "FFEEDDCCBBAA9988", expected_status: RemainingRetries(0)), + Reset(), + ] + ), ] diff --git a/tests/command_response.rs b/tests/command_response.rs index 14f8da5..f3ff73c 100644 --- a/tests/command_response.rs +++ b/tests/command_response.rs @@ -1,6 +1,6 @@ // Copyright (C) 2022 Nicolas Stalder AND Nitrokey GmbH // SPDX-License-Identifier: LGPL-3.0-only -#![cfg(feature = "vpicc")] +#![cfg(feature = "virt")] mod setup; @@ -39,6 +39,13 @@ enum Status { UnspecifiedCheckingError, } +impl From for Status { + fn from(value: iso7816::Status) -> Self { + let tmp: u16 = value.into(); + tmp.try_into().unwrap() + } +} + #[derive(Clone, Copy, Eq, PartialEq, Debug, Deserialize)] pub enum Algorithm { Tdes = 0x3, @@ -243,6 +250,10 @@ struct ManagementKey { key: String, } +fn default_app_pin() -> String { + "313233343536FFFF".into() +} + #[derive(Deserialize, Debug)] #[serde(deny_unknown_fields)] enum IoCmd { @@ -267,11 +278,15 @@ enum IoCmd { #[serde(default)] expected_status: Status, }, - VerifyDefaultApplicationPin { + VerifyApplicationPin { + #[serde(default = "default_app_pin")] + pin: String, #[serde(default)] expected_status: Status, }, - VerifyDefaultGlobalPin { + VerifyGlobalPin { + #[serde(default = "default_app_pin")] + pin: String, #[serde(default)] expected_status: Status, }, @@ -288,6 +303,10 @@ enum IoCmd { expected_status_response: Status, }, Select, + Reset { + #[serde(default)] + expected_status: Status, + }, } const MATCH_EMPTY: OutputMatcher = OutputMatcher::Len(0); @@ -311,12 +330,14 @@ impl IoCmd { output, expected_status, } => Self::run_put_data(input, output, *expected_status, card), - Self::VerifyDefaultApplicationPin { expected_status } => { - Self::run_verify_default_application_pin(*expected_status, card) - } - Self::VerifyDefaultGlobalPin { expected_status } => { - Self::run_verify_default_global_pin(*expected_status, card) - } + Self::VerifyApplicationPin { + pin, + expected_status, + } => Self::run_verify_application_pin(pin, *expected_status, card), + Self::VerifyGlobalPin { + pin, + expected_status, + } => Self::run_verify_global_pin(pin, *expected_status, card), Self::AuthenticateManagement { key, expected_status_challenge, @@ -333,6 +354,7 @@ impl IoCmd { expected_status, } => Self::run_set_administration_key(key.algorithm, &key.key, *expected_status, card), Self::Select => Self::run_select(card), + Self::Reset { expected_status } => Self::run_reset(*expected_status, card), } } @@ -369,7 +391,7 @@ impl IoCmd { let status: Status = card .respond(&cmd, &mut rep) .err() - .map(|s| TryFrom::::try_from(s.into()).unwrap()) + .map(Into::into) .unwrap_or_default(); println!("Output: {:?}\nStatus: {status:?}", hex::encode(&rep)); @@ -456,18 +478,18 @@ impl IoCmd { Self::run_bytes(&command, &MATCH_ANY, expected_status_response, card); } - fn run_verify_default_global_pin(expected_status: Status, card: &mut setup::Piv) { + fn run_verify_application_pin(pin: &str, expected_status: Status, card: &mut setup::Piv) { Self::run_bytes( - &hex!("00 20 00 00 08 313233343536FFFF"), + &build_command(0x00, 0x20, 0x00, 0x80, &parse_hex(pin), 0), &MATCH_EMPTY, expected_status, card, ); } - fn run_verify_default_application_pin(expected_status: Status, card: &mut setup::Piv) { + fn run_verify_global_pin(pin: &str, expected_status: Status, card: &mut setup::Piv) { Self::run_bytes( - &hex!("00 20 00 80 08 313233343536FFFF"), + &build_command(0x00, 0x20, 0x00, 0x00, &parse_hex(pin), 0), &MATCH_EMPTY, expected_status, card, @@ -505,6 +527,9 @@ impl IoCmd { card, ); } + fn run_reset(expected_status: Status, card: &mut setup::Piv) { + Self::run_bytes(&hex!("00 FB 00 00"), &MATCH_EMPTY, expected_status, card); + } } #[test_log::test]