openpgp_card/ocard/data/
key_generation_times.rs

1// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Generation date/time of key pair (see spec pg. 24)
5
6use std::convert::TryFrom;
7
8use chrono::{DateTime, Utc};
9use nom::{combinator, number::complete as number, sequence};
10
11use crate::ocard::data::{KeyGenerationTime, KeySet};
12use crate::Error;
13
14impl From<&KeyGenerationTime> for DateTime<Utc> {
15    fn from(kg: &KeyGenerationTime) -> Self {
16        #[allow(clippy::expect_used)]
17        DateTime::from_timestamp(kg.0 as i64, 0).expect("kg.0 is u32")
18    }
19}
20
21impl From<&KeyGenerationTime> for u32 {
22    fn from(kg: &KeyGenerationTime) -> Self {
23        kg.0
24    }
25}
26
27impl From<u32> for KeyGenerationTime {
28    fn from(data: u32) -> Self {
29        Self(data)
30    }
31}
32
33fn gen_time(input: &[u8]) -> nom::IResult<&[u8], u32> {
34    (number::be_u32)(input)
35}
36
37fn key_generation(input: &[u8]) -> nom::IResult<&[u8], Option<KeyGenerationTime>> {
38    combinator::map(gen_time, |kg| match kg {
39        0 => None,
40        kg => Some(KeyGenerationTime(kg)),
41    })(input)
42}
43
44fn key_generation_set(input: &[u8]) -> nom::IResult<&[u8], KeySet<KeyGenerationTime>> {
45    combinator::into(sequence::tuple((
46        key_generation,
47        key_generation,
48        key_generation,
49    )))(input)
50}
51
52impl TryFrom<&[u8]> for KeySet<KeyGenerationTime> {
53    type Error = Error;
54
55    fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
56        // List of generation dates/times of key pairs, binary.
57        // 4 bytes, Big Endian each for Sig, Dec and Aut. Each
58        // value shall be seconds since Jan 1, 1970. Default
59        // value is 00000000 (not specified).
60
61        log::trace!(
62            "Key generation times from input: {:x?}, len {}",
63            input,
64            input.len()
65        );
66
67        // The input may be longer than 3 key generation times, don't fail if it
68        // hasn't been completely consumed.
69        self::key_generation_set(input)
70            .map(|res| res.1)
71            .map_err(|_err| Error::ParseError("Parsing failed".to_string()))
72    }
73}
74
75#[cfg(test)]
76mod test {
77    use std::convert::TryInto;
78
79    use super::*;
80
81    #[test]
82    fn test() {
83        let data3 = [
84            0x60, 0xf3, 0xff, 0x71, 0x60, 0xf3, 0xff, 0x72, 0x60, 0xf3, 0xff, 0x83,
85        ];
86
87        let fp_set: KeySet<KeyGenerationTime> = (&data3[..])
88            .try_into()
89            .expect("failed to parse KeyGenerationTime set");
90
91        assert_eq!(fp_set.signature().unwrap().get(), 0x60f3ff71);
92        assert_eq!(fp_set.decryption().unwrap().get(), 0x60f3ff72);
93        assert_eq!(fp_set.authentication().unwrap().get(), 0x60f3ff83);
94    }
95}