Elaborate "PW status bytes", fix broken naming of members.

Implement set_pw_status_bytes().
Add test code to card-functionality.
This commit is contained in:
Heiko Schaefer 2021-08-22 01:20:14 +02:00
parent c14664b9d5
commit cb8f3c7cb1
6 changed files with 107 additions and 10 deletions

View file

@ -36,9 +36,13 @@ fn main() -> Result<()> {
// //
// panic!(); // panic!();
print!("Verify"); // print!("Verify");
let verify_out = run_test(&mut card, test_verify, &[])?; // let verify_out = run_test(&mut card, test_verify, &[])?;
println!(" {:x?}", verify_out); // println!(" {:x?}", verify_out);
print!("PW Status bytes");
let pw_out = run_test(&mut card, test_pw_status, &[])?;
println!(" {:x?}", pw_out);
println!(); println!();
} }

View file

@ -352,6 +352,31 @@ pub fn test_set_user_data(
Ok(vec![]) Ok(vec![])
} }
pub fn test_pw_status(
ca: &mut CardApp,
_param: &[&str],
) -> Result<TestOutput, TestError> {
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: /// Outputs:
/// - verify pw3 (check) -> Status /// - verify pw3 (check) -> Status
/// - verify pw1 (check) -> Status /// - verify pw1 (check) -> Status

View file

@ -118,6 +118,11 @@ pub(crate) fn put_url(url: Vec<u8>) -> Command {
put_data(&[0x5f, 0x50], url) put_data(&[0x5f, 0x50], url)
} }
/// PUT DO "PW status bytes"
pub(crate) fn put_pw_status(data: Vec<u8>) -> Command {
put_data(&[0xc4], data)
}
/// Change PW1 (user pin). /// Change PW1 (user pin).
/// This can be used to reset the counter and set a pin. /// This can be used to reset the counter and set a pin.
pub(crate) fn change_pw1(pin: Vec<u8>) -> Command { pub(crate) fn change_pw1(pin: Vec<u8>) -> Command {

View file

@ -11,7 +11,7 @@ use anyhow::{anyhow, Result};
use crate::algorithm::{Algo, AlgoInfo, AlgoSimple, RsaAttrs}; use crate::algorithm::{Algo, AlgoInfo, AlgoSimple, RsaAttrs};
use crate::apdu::{commands, response::Response}; use crate::apdu::{commands, response::Response};
use crate::card_do::{ use crate::card_do::{
ApplicationRelatedData, Cardholder, SecuritySupportTemplate, Sex, ApplicationRelatedData, Cardholder, PWStatus, SecuritySupportTemplate, Sex,
}; };
use crate::crypto_data::{ use crate::crypto_data::{
CardUploadableKey, Cryptogram, EccType, Hash, PublicKeyMaterial, CardUploadableKey, Cryptogram, EccType, Hash, PublicKeyMaterial,
@ -450,6 +450,28 @@ impl CardApp {
apdu::send_command(self.card(), fp_cmd, false)?.try_into() 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<Response, OpenpgpCardError> {
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] /// Set algorithm attributes [4.4.3.9 Algorithm Attributes]
pub fn set_algorithm_attributes( pub fn set_algorithm_attributes(
&mut self, &mut self,

View file

@ -319,16 +319,28 @@ impl From<u8> for Sex {
#[derive(Debug)] #[derive(Debug)]
pub struct PWStatus { pub struct PWStatus {
pub(crate) pw1_cds_multi: bool, pub(crate) pw1_cds_multi: bool,
pub(crate) pw1_derived: bool, pub(crate) pw1_pin_block: bool,
pub(crate) pw1_len: u8, pub(crate) pw1_len: u8,
pub(crate) rc_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) pw3_len: u8,
pub(crate) err_count_pw1: u8, pub(crate) err_count_pw1: u8,
pub(crate) err_count_rst: u8, pub(crate) err_count_rst: u8,
pub(crate) err_count_pw3: 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 /// Fingerprint
#[derive(Clone, Eq, PartialEq)] #[derive(Clone, Eq, PartialEq)]
pub struct Fingerprint([u8; 20]); pub struct Fingerprint([u8; 20]);

View file

@ -10,10 +10,10 @@ impl PWStatus {
pub fn try_from(input: &[u8]) -> Result<Self, OpenpgpCardError> { pub fn try_from(input: &[u8]) -> Result<Self, OpenpgpCardError> {
if input.len() == 7 { if input.len() == 7 {
let pw1_cds_multi = input[0] == 0x01; 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 pw1_len = input[1] & 0x7f;
let rc_len = input[2]; 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 pw3_len = input[3] & 0x7f;
let err_count_pw1 = input[4]; let err_count_pw1 = input[4];
let err_count_rst = input[5]; let err_count_rst = input[5];
@ -21,10 +21,10 @@ impl PWStatus {
Ok(Self { Ok(Self {
pw1_cds_multi, pw1_cds_multi,
pw1_derived, pw1_pin_block,
pw1_len, pw1_len,
rc_len, rc_len,
pw3_derived, pw3_pin_block,
pw3_len, pw3_len,
err_count_pw1, err_count_pw1,
err_count_rst, 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<u8> {
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
}
} }