hsmtool/util/attribute/
data.rs1use std::convert::TryFrom;
6use std::sync::LazyLock;
7
8use cryptoki::types::Ulong;
9use regex::Regex;
10use serde::{Deserialize, Serialize};
11
12use crate::util::attribute::{
13 AttributeError, CertificateType, KeyType, MechanismType, ObjectClass,
14};
15use crate::util::escape::{as_hex, escape, unescape};
16
17#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
18pub enum Redacted {
19 RedactedByHsm,
20 RedactedByTool,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
24#[serde(untagged)]
25pub enum AttrData {
26 #[default]
27 None,
28 Bool(bool),
29 Ulong(u64),
30 CertificateType(CertificateType),
31 KeyType(KeyType),
32 MechanismType(MechanismType),
33 ObjectClass(ObjectClass),
34 Redacted(Redacted),
35 Str(String),
36 List(Vec<AttrData>),
37}
38
39impl From<bool> for AttrData {
40 fn from(v: bool) -> Self {
41 AttrData::Bool(v)
42 }
43}
44
45impl TryFrom<&AttrData> for bool {
46 type Error = AttributeError;
47 fn try_from(a: &AttrData) -> Result<Self, Self::Error> {
48 match a {
49 AttrData::Bool(v) => Ok(*v),
50 _ => Err(AttributeError::InvalidDataType),
51 }
52 }
53}
54
55impl From<u64> for AttrData {
56 fn from(v: u64) -> Self {
57 AttrData::Ulong(v)
58 }
59}
60
61impl From<Ulong> for AttrData {
62 fn from(v: Ulong) -> Self {
63 AttrData::Ulong(*v)
64 }
65}
66
67impl TryFrom<&AttrData> for u64 {
68 type Error = AttributeError;
69 fn try_from(a: &AttrData) -> Result<Self, Self::Error> {
70 match a {
71 AttrData::Ulong(v) => Ok(*v),
72 _ => Err(AttributeError::InvalidDataType),
73 }
74 }
75}
76
77impl TryFrom<&AttrData> for Ulong {
78 type Error = AttributeError;
79 fn try_from(a: &AttrData) -> Result<Self, Self::Error> {
80 match a {
81 AttrData::Ulong(v) => Ok(Ulong::from(*v)),
82 _ => Err(AttributeError::InvalidDataType),
83 }
84 }
85}
86
87impl From<&[u8]> for AttrData {
88 fn from(v: &[u8]) -> Self {
89 AttrData::Str(as_hex(v))
90 }
91}
92
93pub fn unhex(ch: u8) -> u8 {
94 match ch {
95 b'0'..=b'9' => ch - b'0',
96 b'A'..=b'F' => ch - b'A' + 10,
97 b'a'..=b'f' => ch - b'a' + 10,
98 _ => unreachable!(),
99 }
100}
101
102impl TryFrom<&AttrData> for Vec<u8> {
103 type Error = AttributeError;
104 fn try_from(a: &AttrData) -> Result<Self, Self::Error> {
105 static HEX: LazyLock<Regex> =
106 LazyLock::new(|| Regex::new("^[0-9A-Fa-f]{2}(:[0-9A-Fa-f]{2})*$").unwrap());
107 match a {
108 AttrData::Str(v) => {
109 if HEX.is_match(v) {
110 Ok(v.as_bytes()
115 .chunks(3)
116 .map(|ch| (unhex(ch[0]) << 4) | unhex(ch[1]))
117 .collect())
118 } else {
119 Ok(unescape(v).map_err(|_| AttributeError::EncodingError)?)
120 }
121 }
122 _ => Err(AttributeError::InvalidDataType),
123 }
124 }
125}
126
127impl AttrData {
128 pub fn is_none(&self) -> bool {
129 self == &AttrData::None
130 }
131 pub fn from_ascii_bytes(v: &[u8]) -> Self {
132 AttrData::Str(escape(v))
133 }
134
135 pub fn try_str(&self) -> Result<&str, AttributeError> {
136 match self {
137 AttrData::Str(v) => Ok(v.as_str()),
138 _ => Err(AttributeError::InvalidDataType),
139 }
140 }
141
142 pub fn try_string(&self) -> Result<String, AttributeError> {
143 match self {
144 AttrData::Str(v) => Ok(v.clone()),
145 _ => Err(AttributeError::InvalidDataType),
146 }
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153 use anyhow::Result;
154
155 #[test]
156 fn test_bool() -> Result<()> {
157 let b = AttrData::from(true);
158 assert!(bool::try_from(&b)?);
159 assert!(u64::try_from(&b).is_err());
160 assert!(Ulong::try_from(&b).is_err());
161 assert!(Vec::<u8>::try_from(&b).is_err());
162 assert!(b.try_str().is_err());
163 Ok(())
164 }
165
166 #[test]
167 fn test_ulong() -> Result<()> {
168 let b = AttrData::from(12345u64);
169 assert!(bool::try_from(&b).is_err());
170 assert_eq!(u64::try_from(&b)?, 12345);
171 assert_eq!(Ulong::try_from(&b)?, Ulong::from(12345));
172 assert!(Vec::<u8>::try_from(&b).is_err());
173 assert!(b.try_str().is_err());
174 Ok(())
175 }
176
177 #[test]
178 fn test_str() -> Result<()> {
179 let data = vec![0x12u8, 0x34u8, 0x56u8, 0x78u8];
180 let b = AttrData::from(data.as_slice());
181 assert!(bool::try_from(&b).is_err());
182 assert!(u64::try_from(&b).is_err());
183 assert!(Ulong::try_from(&b).is_err());
184 assert_eq!(Vec::<u8>::try_from(&b)?, &[0x12, 0x34, 0x56, 0x78]);
185 assert_eq!(b.try_str()?, "12:34:56:78");
186 Ok(())
187 }
188}