hsmtool/util/attribute/
date.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use cryptoki::types;
6use cryptoki_sys::*;
7use std::convert::TryFrom;
8
9use crate::util::attribute::{AttrData, AttributeError};
10
11pub struct Date(pub String);
12
13fn parse(s: &[u8]) -> u32 {
14    let mut result = 0;
15    for &byte in s.iter() {
16        let ch = byte as char;
17        if ch.is_ascii_whitespace() || ch == '\0' {
18            // do nothing
19        } else if ch.is_ascii_digit() {
20            result *= 10;
21            result += (byte - b'0') as u32;
22        } else {
23            panic!("Expected digit or whitespace in {:?}", s);
24        }
25    }
26    result
27}
28
29impl From<types::Date> for Date {
30    fn from(val: types::Date) -> Self {
31        let val = CK_DATE::from(val);
32        let year = parse(&val.year);
33        let month = parse(&val.month);
34        let day = parse(&val.day);
35        Date(format!("{:04}-{:02}-{:02}", year, month, day))
36    }
37}
38
39impl From<&str> for Date {
40    fn from(val: &str) -> Self {
41        Date(val.to_string())
42    }
43}
44
45impl From<Date> for String {
46    fn from(val: Date) -> Self {
47        val.0
48    }
49}
50
51impl TryFrom<Date> for types::Date {
52    type Error = cryptoki::error::Error;
53    fn try_from(val: Date) -> Result<Self, Self::Error> {
54        if val.0.len() == 8 {
55            // Date in the form YYYYMMDD.
56            types::Date::new_from_str_slice(&val.0[0..4], &val.0[4..6], &val.0[6..8])
57        } else if val.0.len() == 10 {
58            // Date in the form YYYY-MM-DD.
59            types::Date::new_from_str_slice(&val.0[0..4], &val.0[5..7], &val.0[8..10])
60        } else {
61            Err(cryptoki::error::Error::InvalidValue)
62        }
63    }
64}
65
66impl TryFrom<&AttrData> for Date {
67    type Error = AttributeError;
68    fn try_from(val: &AttrData) -> Result<Self, Self::Error> {
69        Ok(Self::from(val.try_str()?))
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use anyhow::Result;
77
78    #[test]
79    fn test_convert_to_cryptoki_date() -> Result<()> {
80        let d = Date::from("2023-02-01");
81        let k = types::Date::try_from(d)?;
82        assert_eq!(k.to_string(), "Month: 02\nDay: 01\nYear: 2023");
83
84        let d = Date::from("20230504");
85        let k = types::Date::try_from(d)?;
86        assert_eq!(k.to_string(), "Month: 05\nDay: 04\nYear: 2023");
87
88        let d = Date::from("1234");
89        assert!(types::Date::try_from(d).is_err());
90        Ok(())
91    }
92
93    #[test]
94    fn test_convert_from_cryptoki_date() -> Result<()> {
95        let k = types::Date::from(CK_DATE {
96            year: *b"2023",
97            month: *b"02",
98            day: *b"01",
99        });
100        let d = Date::from(k);
101        assert_eq!(String::from(d), "2023-02-01");
102
103        let k = types::Date::from(CK_DATE {
104            year: *b"2023",
105            month: *b" 5",
106            day: *b"4 ",
107        });
108        let d = Date::from(k);
109        assert_eq!(String::from(d), "2023-05-04");
110
111        Ok(())
112    }
113}