From c4457576335d6937defff56a8cc5f3cdd61d30ba Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Wed, 14 Jul 2021 21:59:33 +0200 Subject: [PATCH] Implement get_key_generation_times() --- openpgp-card/src/card_app.rs | 19 +++++- openpgp-card/src/key_upload.rs | 1 + .../src/parse/key_generation_times.rs | 61 +++++++++++++++++++ openpgp-card/src/parse/mod.rs | 1 + 4 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 openpgp-card/src/parse/key_generation_times.rs diff --git a/openpgp-card/src/card_app.rs b/openpgp-card/src/card_app.rs index ea7c05b..941bde5 100644 --- a/openpgp-card/src/card_app.rs +++ b/openpgp-card/src/card_app.rs @@ -16,11 +16,12 @@ use anyhow::{anyhow, Result}; use crate::apdu::{commands, response::Response}; use crate::errors::OpenpgpCardError; +use crate::parse::key_generation_times::KeyGeneration; use crate::parse::{ algo_attrs::Algo, algo_info::AlgoInfo, application_id::ApplicationId, cardholder::CardHolder, extended_cap::ExtendedCap, extended_length_info::ExtendedLengthInfo, fingerprint, - historical::Historical, pw_status::PWStatus, KeySet, + historical::Historical, key_generation_times, pw_status::PWStatus, KeySet, }; use crate::tlv::{tag::Tag, Tlv, TlvEntry}; use crate::{ @@ -236,8 +237,20 @@ impl CardApp { unimplemented!() } - pub fn get_key_generation_times() { - unimplemented!() + pub fn get_key_generation_times( + ard: &Tlv, + ) -> Result, OpenpgpCardError> { + let kg = ard.find(&Tag::from([0xCD])); + + if let Some(kg) = kg { + let kg = key_generation_times::from(&kg.serialize())?; + + log::debug!("Key generation: {:x?}", kg); + + Ok(kg) + } else { + Err(anyhow!("Failed to get key generation times.").into()) + } } pub fn get_key_information() { diff --git a/openpgp-card/src/key_upload.rs b/openpgp-card/src/key_upload.rs index 27aea12..c24099c 100644 --- a/openpgp-card/src/key_upload.rs +++ b/openpgp-card/src/key_upload.rs @@ -387,6 +387,7 @@ fn copy_key_to_card( .copied() .collect(); + // Generation date/time let time_cmd = commands::put_data(&[key_type.get_timestamp_put_tag()], time_value); diff --git a/openpgp-card/src/parse/key_generation_times.rs b/openpgp-card/src/parse/key_generation_times.rs new file mode 100644 index 0000000..b1ce671 --- /dev/null +++ b/openpgp-card/src/parse/key_generation_times.rs @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2021 Heiko Schaefer +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use anyhow::anyhow; +use nom::{ + bytes::complete as bytes, combinator, number::complete as number, sequence, +}; +use std::fmt; + +use crate::errors::OpenpgpCardError; +use crate::parse::KeySet; + +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct KeyGeneration(u32); + +impl From for KeyGeneration { + fn from(data: u32) -> Self { + Self(data) + } +} + +fn gen_time(input: &[u8]) -> nom::IResult<&[u8], u32> { + (number::be_u32)(input) +} + +fn key_generation(input: &[u8]) -> nom::IResult<&[u8], Option> { + combinator::map(gen_time, |kg| match kg { + 0 => None, + kg => Some(KeyGeneration(kg)), + })(input) +} + +fn key_generation_set( + input: &[u8], +) -> nom::IResult<&[u8], KeySet> { + combinator::into(sequence::tuple(( + key_generation, + key_generation, + key_generation, + )))(input) +} + +pub fn from(input: &[u8]) -> Result, OpenpgpCardError> { + // List of generation dates/times of key pairs, binary. + // 4 bytes, Big Endian each for Sig, Dec and Aut. Each + // value shall be seconds since Jan 1, 1970. Default + // value is 00000000 (not specified). + + log::trace!( + "Key generation times from input: {:x?}, len {}", + input, + input.len() + ); + + // The input may be longer than 3 key generation times, don't fail if it + // hasn't been completely consumed. + self::key_generation_set(input) + .map(|res| res.1) + .map_err(|err| anyhow!("Parsing failed: {:?}", err)) + .map_err(OpenpgpCardError::InternalError) +} diff --git a/openpgp-card/src/parse/mod.rs b/openpgp-card/src/parse/mod.rs index 2da0124..1b01b13 100644 --- a/openpgp-card/src/parse/mod.rs +++ b/openpgp-card/src/parse/mod.rs @@ -12,6 +12,7 @@ pub mod extended_cap; pub mod extended_length_info; pub mod fingerprint; pub mod historical; +pub mod key_generation_times; pub mod pw_status; use anyhow::{anyhow, Error};