Merge branch 'heiko/attestation-key-status' into 'main'
opgpcard: Move attestation key metatdata into a separate KeySlotInfo struct See merge request openpgp-card/openpgp-card!27
This commit is contained in:
commit
19d7aa94bf
4 changed files with 102 additions and 31 deletions
|
@ -419,6 +419,18 @@ impl<'a> Card<Transaction<'a>> {
|
||||||
self.state.opt.attestation_certificate()
|
self.state.opt.attestation_certificate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn attestation_key_fingerprint(&mut self) -> Result<Option<Fingerprint>, Error> {
|
||||||
|
self.state.ard.attestation_key_fingerprint()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attestation_key_algorithm_attributes(&mut self) -> Result<Option<Algo>, Error> {
|
||||||
|
self.state.ard.attestation_key_algorithm_attributes()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attestation_key_generation_time(&mut self) -> Result<Option<KeyGenerationTime>, Error> {
|
||||||
|
self.state.ard.attestation_key_generation_time()
|
||||||
|
}
|
||||||
|
|
||||||
/// Firmware Version, YubiKey specific (?)
|
/// Firmware Version, YubiKey specific (?)
|
||||||
pub fn firmware_version(&mut self) -> Result<Vec<u8>, Error> {
|
pub fn firmware_version(&mut self) -> Result<Vec<u8>, Error> {
|
||||||
self.state.opt.firmware_version()
|
self.state.opt.firmware_version()
|
||||||
|
|
|
@ -168,7 +168,7 @@ impl ApplicationRelatedData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generation dates/times of key pairs
|
/// Generation dates/times of key pairs
|
||||||
pub fn key_generation_times(&self) -> Result<KeySet<KeyGenerationTime>, crate::Error> {
|
pub fn key_generation_times(&self) -> Result<KeySet<KeyGenerationTime>, Error> {
|
||||||
let kg = self.0.find(Tags::GenerationTimes);
|
let kg = self.0.find(Tags::GenerationTimes);
|
||||||
|
|
||||||
if let Some(kg) = kg {
|
if let Some(kg) = kg {
|
||||||
|
@ -219,6 +219,47 @@ impl ApplicationRelatedData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get Attestation key fingerprint.
|
||||||
|
pub fn attestation_key_fingerprint(&self) -> Result<Option<Fingerprint>, Error> {
|
||||||
|
match self.0.find(Tags::FingerprintAttestation) {
|
||||||
|
None => Ok(None),
|
||||||
|
Some(data) => {
|
||||||
|
// FIXME: move conversion logic to Fingerprint
|
||||||
|
if data.serialize().iter().any(|&b| b != 0) {
|
||||||
|
Ok(Some(Fingerprint::try_from(data.serialize().as_slice())?))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get Attestation key algorithm attributes.
|
||||||
|
pub fn attestation_key_algorithm_attributes(&mut self) -> Result<Option<Algo>, Error> {
|
||||||
|
match self.0.find(Tags::AlgorithmAttributesAttestation) {
|
||||||
|
None => Ok(None),
|
||||||
|
Some(data) => Ok(Some(Algo::try_from(data.serialize().as_slice())?)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get Attestation key generation time.
|
||||||
|
pub fn attestation_key_generation_time(&mut self) -> Result<Option<KeyGenerationTime>, Error> {
|
||||||
|
match self.0.find(Tags::GenerationTimeAttestation) {
|
||||||
|
None => Ok(None),
|
||||||
|
Some(data) => {
|
||||||
|
// FIXME: move conversion logic to KeyGenerationTime
|
||||||
|
|
||||||
|
// Generation time of key, binary. 4 bytes, Big Endian.
|
||||||
|
// Value shall be seconds since Jan 1, 1970. Default value is 00000000 (not specified).
|
||||||
|
assert_eq!(data.serialize().len(), 4);
|
||||||
|
match u32::from_be_bytes(data.serialize().try_into().unwrap()) {
|
||||||
|
0 => Ok(None),
|
||||||
|
kgt => Ok(Some(kgt.into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn uif_attestation(&self) -> Result<Option<UIF>, Error> {
|
pub fn uif_attestation(&self) -> Result<Option<UIF>, Error> {
|
||||||
let uif = self.0.find(Tags::UifAttestation);
|
let uif = self.0.find(Tags::UifAttestation);
|
||||||
|
|
||||||
|
|
|
@ -165,22 +165,40 @@ pub fn print_status(
|
||||||
}
|
}
|
||||||
output.authentication_key(authentication_key);
|
output.authentication_key(authentication_key);
|
||||||
|
|
||||||
// technical details about the card's state
|
let mut attestation_key = output::KeySlotInfo::default();
|
||||||
|
if let Ok(Some(fp)) = card.attestation_key_fingerprint() {
|
||||||
|
attestation_key.fingerprint(fp.to_spaced_hex());
|
||||||
|
}
|
||||||
|
if let Ok(Some(algo)) = card.attestation_key_algorithm_attributes() {
|
||||||
|
attestation_key.algorithm(format!("{}", algo));
|
||||||
|
}
|
||||||
|
if let Ok(Some(kgt)) = card.attestation_key_generation_time() {
|
||||||
|
attestation_key.created(format!("{}", kgt.to_datetime()));
|
||||||
|
}
|
||||||
|
if let Some(uif) = card.uif_attestation()? {
|
||||||
|
attestation_key.touch_policy(format!("{}", uif.touch_policy()));
|
||||||
|
attestation_key.touch_features(format!("{}", uif.features()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: get public key data for the attestation key from the card
|
||||||
|
// if command.pkm {
|
||||||
|
// if let Ok(pkm) = card.public_key(KeyType::Attestation) {
|
||||||
|
// attestation_key.public_key_material(pkm.to_string());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// TODO: clarify how to reliably map `card.key_information()` output into this field (see below)
|
||||||
|
// if let Some(ks) = ki.as_ref().map(|ki| ki.aut_status()) {
|
||||||
|
// attestation_key.status(format!("{}", ks));
|
||||||
|
// }
|
||||||
|
|
||||||
|
output.attestation_key(attestation_key);
|
||||||
|
|
||||||
|
// technical details about the card's state
|
||||||
output.user_pin_remaining_attempts(pws.err_count_pw1());
|
output.user_pin_remaining_attempts(pws.err_count_pw1());
|
||||||
output.admin_pin_remaining_attempts(pws.err_count_pw3());
|
output.admin_pin_remaining_attempts(pws.err_count_pw3());
|
||||||
output.reset_code_remaining_attempts(pws.err_count_rc());
|
output.reset_code_remaining_attempts(pws.err_count_rc());
|
||||||
|
|
||||||
// FIXME: Handle attestation key information as a separate
|
|
||||||
// KeySlotInfo! Attestation touch information should go into its
|
|
||||||
// own `Option<KeySlotInfo>`, and (if any information about the
|
|
||||||
// attestation key exists at all, which is not the case for most
|
|
||||||
// cards) it should be printed as a fourth KeySlot block.
|
|
||||||
if let Some(uif) = card.uif_attestation()? {
|
|
||||||
output.card_touch_policy(uif.touch_policy().to_string());
|
|
||||||
output.card_touch_features(uif.features().to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ki) = ki {
|
if let Some(ki) = ki {
|
||||||
let num = ki.num_additional();
|
let num = ki.num_additional();
|
||||||
for i in 0..num {
|
for i in 0..num {
|
||||||
|
|
|
@ -18,11 +18,10 @@ pub struct Status {
|
||||||
signature_count: u32,
|
signature_count: u32,
|
||||||
decryption_key: KeySlotInfo,
|
decryption_key: KeySlotInfo,
|
||||||
authentication_key: KeySlotInfo,
|
authentication_key: KeySlotInfo,
|
||||||
|
attestation_key: Option<KeySlotInfo>,
|
||||||
user_pin_remaining_attempts: u8,
|
user_pin_remaining_attempts: u8,
|
||||||
admin_pin_remaining_attempts: u8,
|
admin_pin_remaining_attempts: u8,
|
||||||
reset_code_remaining_attempts: u8,
|
reset_code_remaining_attempts: u8,
|
||||||
card_touch_policy: String,
|
|
||||||
card_touch_features: String,
|
|
||||||
key_statuses: Vec<(u8, String)>,
|
key_statuses: Vec<(u8, String)>,
|
||||||
ca_fingerprints: Vec<String>,
|
ca_fingerprints: Vec<String>,
|
||||||
}
|
}
|
||||||
|
@ -68,6 +67,10 @@ impl Status {
|
||||||
self.authentication_key = key;
|
self.authentication_key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn attestation_key(&mut self, key: KeySlotInfo) {
|
||||||
|
self.attestation_key = Some(key);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn user_pin_remaining_attempts(&mut self, count: u8) {
|
pub fn user_pin_remaining_attempts(&mut self, count: u8) {
|
||||||
self.user_pin_remaining_attempts = count;
|
self.user_pin_remaining_attempts = count;
|
||||||
}
|
}
|
||||||
|
@ -80,14 +83,6 @@ impl Status {
|
||||||
self.reset_code_remaining_attempts = count;
|
self.reset_code_remaining_attempts = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn card_touch_policy(&mut self, policy: String) {
|
|
||||||
self.card_touch_policy = policy;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn card_touch_features(&mut self, features: String) {
|
|
||||||
self.card_touch_features = features;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn key_status(&mut self, keyref: u8, status: String) {
|
pub fn key_status(&mut self, keyref: u8, status: String) {
|
||||||
self.key_statuses.push((keyref, status));
|
self.key_statuses.push((keyref, status));
|
||||||
}
|
}
|
||||||
|
@ -150,6 +145,18 @@ impl Status {
|
||||||
}
|
}
|
||||||
s.push('\n');
|
s.push('\n');
|
||||||
|
|
||||||
|
if self.verbose {
|
||||||
|
if let Some(attestation_key) = &self.attestation_key {
|
||||||
|
if attestation_key.touch_policy.is_some() || attestation_key.algorithm.is_some() {
|
||||||
|
s.push_str("Attestation key:\n");
|
||||||
|
for line in attestation_key.format(self.verbose) {
|
||||||
|
s.push_str(&format!(" {}\n", line));
|
||||||
|
}
|
||||||
|
s.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s.push_str(&format!(
|
s.push_str(&format!(
|
||||||
"Remaining PIN attempts: User: {}, Admin: {}, Reset Code: {}\n",
|
"Remaining PIN attempts: User: {}, Admin: {}, Reset Code: {}\n",
|
||||||
self.user_pin_remaining_attempts,
|
self.user_pin_remaining_attempts,
|
||||||
|
@ -158,11 +165,6 @@ impl Status {
|
||||||
));
|
));
|
||||||
|
|
||||||
if self.verbose {
|
if self.verbose {
|
||||||
s.push_str(&format!(
|
|
||||||
"Touch policy attestation: {}\n",
|
|
||||||
self.card_touch_policy
|
|
||||||
));
|
|
||||||
|
|
||||||
for (keyref, status) in self.key_statuses.iter() {
|
for (keyref, status) in self.key_statuses.iter() {
|
||||||
s.push_str(&format!("Key status (#{}): {}\n", keyref, status));
|
s.push_str(&format!("Key status (#{}): {}\n", keyref, status));
|
||||||
}
|
}
|
||||||
|
@ -183,11 +185,10 @@ impl Status {
|
||||||
signature_count: self.signature_count,
|
signature_count: self.signature_count,
|
||||||
decryption_key: self.decryption_key.clone(),
|
decryption_key: self.decryption_key.clone(),
|
||||||
authentication_key: self.authentication_key.clone(),
|
authentication_key: self.authentication_key.clone(),
|
||||||
|
attestation_key: self.attestation_key.clone(),
|
||||||
user_pin_remaining_attempts: self.user_pin_remaining_attempts,
|
user_pin_remaining_attempts: self.user_pin_remaining_attempts,
|
||||||
admin_pin_remaining_attempts: self.admin_pin_remaining_attempts,
|
admin_pin_remaining_attempts: self.admin_pin_remaining_attempts,
|
||||||
reset_code_remaining_attempts: self.reset_code_remaining_attempts,
|
reset_code_remaining_attempts: self.reset_code_remaining_attempts,
|
||||||
card_touch_policy: self.card_touch_policy.clone(),
|
|
||||||
card_touch_features: self.card_touch_features.clone(),
|
|
||||||
key_statuses: self.key_statuses.clone(),
|
key_statuses: self.key_statuses.clone(),
|
||||||
ca_fingerprints: self.ca_fingerprints.clone(),
|
ca_fingerprints: self.ca_fingerprints.clone(),
|
||||||
})
|
})
|
||||||
|
@ -232,11 +233,10 @@ pub struct StatusV0 {
|
||||||
signature_count: u32,
|
signature_count: u32,
|
||||||
decryption_key: KeySlotInfo,
|
decryption_key: KeySlotInfo,
|
||||||
authentication_key: KeySlotInfo,
|
authentication_key: KeySlotInfo,
|
||||||
|
attestation_key: Option<KeySlotInfo>,
|
||||||
user_pin_remaining_attempts: u8,
|
user_pin_remaining_attempts: u8,
|
||||||
admin_pin_remaining_attempts: u8,
|
admin_pin_remaining_attempts: u8,
|
||||||
reset_code_remaining_attempts: u8,
|
reset_code_remaining_attempts: u8,
|
||||||
card_touch_policy: String,
|
|
||||||
card_touch_features: String,
|
|
||||||
key_statuses: Vec<(u8, String)>,
|
key_statuses: Vec<(u8, String)>,
|
||||||
ca_fingerprints: Vec<String>,
|
ca_fingerprints: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue