From cb8f3c7cb1991ebcb2baf93780afba79bc776e90 Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Sun, 22 Aug 2021 01:20:14 +0200 Subject: [PATCH] Elaborate "PW status bytes", fix broken naming of members. Implement set_pw_status_bytes(). Add test code to card-functionality. --- card-functionality/src/other.rs | 10 +++++--- card-functionality/src/tests.rs | 25 ++++++++++++++++++ openpgp-card/src/apdu/commands.rs | 5 ++++ openpgp-card/src/card_app.rs | 24 ++++++++++++++++- openpgp-card/src/card_do/mod.rs | 16 ++++++++++-- openpgp-card/src/card_do/pw_status.rs | 37 ++++++++++++++++++++++++--- 6 files changed, 107 insertions(+), 10 deletions(-) diff --git a/card-functionality/src/other.rs b/card-functionality/src/other.rs index 71846b8..01c8936 100644 --- a/card-functionality/src/other.rs +++ b/card-functionality/src/other.rs @@ -36,9 +36,13 @@ fn main() -> Result<()> { // // panic!(); - print!("Verify"); - let verify_out = run_test(&mut card, test_verify, &[])?; - println!(" {:x?}", verify_out); + // print!("Verify"); + // let verify_out = run_test(&mut card, test_verify, &[])?; + // println!(" {:x?}", verify_out); + + print!("PW Status bytes"); + let pw_out = run_test(&mut card, test_pw_status, &[])?; + println!(" {:x?}", pw_out); println!(); } diff --git a/card-functionality/src/tests.rs b/card-functionality/src/tests.rs index 974197e..582a9a3 100644 --- a/card-functionality/src/tests.rs +++ b/card-functionality/src/tests.rs @@ -352,6 +352,31 @@ pub fn test_set_user_data( Ok(vec![]) } +pub fn test_pw_status( + ca: &mut CardApp, + _param: &[&str], +) -> Result { + let mut out = vec![]; + + let ard = ca.get_app_data()?; + let mut pws = ard.get_pw_status_bytes()?; + + println!("pws {:?}", pws); + + ca.verify_pw3("12345678")?; + + pws.set_pw1_cds_multi(true); + pws.set_pw1_pin_block(true); + + ca.set_pw_status_bytes(&pws, false)?; + + let ard = ca.get_app_data()?; + let pws = ard.get_pw_status_bytes()?; + println!("pws {:?}", pws); + + Ok(out) +} + /// Outputs: /// - verify pw3 (check) -> Status /// - verify pw1 (check) -> Status diff --git a/openpgp-card/src/apdu/commands.rs b/openpgp-card/src/apdu/commands.rs index 69a5965..aafeed1 100644 --- a/openpgp-card/src/apdu/commands.rs +++ b/openpgp-card/src/apdu/commands.rs @@ -118,6 +118,11 @@ pub(crate) fn put_url(url: Vec) -> Command { put_data(&[0x5f, 0x50], url) } +/// PUT DO "PW status bytes" +pub(crate) fn put_pw_status(data: Vec) -> Command { + put_data(&[0xc4], data) +} + /// Change PW1 (user pin). /// This can be used to reset the counter and set a pin. pub(crate) fn change_pw1(pin: Vec) -> Command { diff --git a/openpgp-card/src/card_app.rs b/openpgp-card/src/card_app.rs index ddce952..f14fe7f 100644 --- a/openpgp-card/src/card_app.rs +++ b/openpgp-card/src/card_app.rs @@ -11,7 +11,7 @@ use anyhow::{anyhow, Result}; use crate::algorithm::{Algo, AlgoInfo, AlgoSimple, RsaAttrs}; use crate::apdu::{commands, response::Response}; use crate::card_do::{ - ApplicationRelatedData, Cardholder, SecuritySupportTemplate, Sex, + ApplicationRelatedData, Cardholder, PWStatus, SecuritySupportTemplate, Sex, }; use crate::crypto_data::{ CardUploadableKey, Cryptogram, EccType, Hash, PublicKeyMaterial, @@ -450,6 +450,28 @@ impl CardApp { apdu::send_command(self.card(), fp_cmd, false)?.try_into() } + /// Set PW Status Bytes. + /// + /// If `long` is false, send 1 byte to the card, otherwise 4. + /// According to the spec, length information should not be changed. + /// + /// So, effectively, with 'long == false' the setting `pw1_cds_multi` + /// can be changed. + /// With 'long == true', the settings `pw1_pin_block` and `pw3_pin_block` + /// can also be changed. + /// + /// (See OpenPGP card spec, pg. 28) + pub fn set_pw_status_bytes( + &mut self, + pw_status: &PWStatus, + long: bool, + ) -> Result { + let data = pw_status.serialize_for_put(long); + + let cmd = commands::put_pw_status(data); + apdu::send_command(self.card(), cmd, false)?.try_into() + } + /// Set algorithm attributes [4.4.3.9 Algorithm Attributes] pub fn set_algorithm_attributes( &mut self, diff --git a/openpgp-card/src/card_do/mod.rs b/openpgp-card/src/card_do/mod.rs index 9003108..79f3c5a 100644 --- a/openpgp-card/src/card_do/mod.rs +++ b/openpgp-card/src/card_do/mod.rs @@ -319,16 +319,28 @@ impl From for Sex { #[derive(Debug)] pub struct PWStatus { pub(crate) pw1_cds_multi: bool, - pub(crate) pw1_derived: bool, + pub(crate) pw1_pin_block: bool, pub(crate) pw1_len: u8, pub(crate) rc_len: u8, - pub(crate) pw3_derived: bool, + pub(crate) pw3_pin_block: bool, pub(crate) pw3_len: u8, pub(crate) err_count_pw1: u8, pub(crate) err_count_rst: u8, pub(crate) err_count_pw3: u8, } +impl PWStatus { + pub fn set_pw1_cds_multi(&mut self, val: bool) { + self.pw1_cds_multi = val; + } + pub fn set_pw1_pin_block(&mut self, val: bool) { + self.pw1_pin_block = val; + } + pub fn set_pw3_pin_block(&mut self, val: bool) { + self.pw3_pin_block = val; + } +} + /// Fingerprint #[derive(Clone, Eq, PartialEq)] pub struct Fingerprint([u8; 20]); diff --git a/openpgp-card/src/card_do/pw_status.rs b/openpgp-card/src/card_do/pw_status.rs index 7c56dbf..7aca0b6 100644 --- a/openpgp-card/src/card_do/pw_status.rs +++ b/openpgp-card/src/card_do/pw_status.rs @@ -10,10 +10,10 @@ impl PWStatus { pub fn try_from(input: &[u8]) -> Result { if input.len() == 7 { let pw1_cds_multi = input[0] == 0x01; - let pw1_derived = input[1] & 0x80 != 0; + let pw1_pin_block = input[1] & 0x80 != 0; let pw1_len = input[1] & 0x7f; let rc_len = input[2]; - let pw3_derived = input[3] & 0x80 != 0; + let pw3_pin_block = input[3] & 0x80 != 0; let pw3_len = input[3] & 0x7f; let err_count_pw1 = input[4]; let err_count_rst = input[5]; @@ -21,10 +21,10 @@ impl PWStatus { Ok(Self { pw1_cds_multi, - pw1_derived, + pw1_pin_block, pw1_len, rc_len, - pw3_derived, + pw3_pin_block, pw3_len, err_count_pw1, err_count_rst, @@ -37,4 +37,33 @@ impl PWStatus { ))) } } + + /// PUT DO for PW Status Bytes accepts either 1 or 4 bytes of data. + /// This method generates the 1 byte version for 'long==false' and the + /// 4 bytes version for 'long==true'. + /// + /// (See OpenPGP card spec, pg. 28) + pub fn serialize_for_put(&self, long: bool) -> Vec { + let mut data = vec![]; + + data.push(if !self.pw1_cds_multi { 0 } else { 1 }); + + if long { + let mut b2 = self.pw1_len; + if self.pw1_pin_block { + b2 |= 0x80; + } + data.push(b2); + + data.push(self.rc_len); + + let mut b4 = self.pw3_len; + if self.pw3_pin_block { + b4 |= 0x80; + } + data.push(b4); + } + + data + } }