1use std::collections::HashSet;
6use std::str::FromStr;
7use std::sync::LazyLock;
8
9use anyhow::Result;
10use cryptoki::object::{Attribute, AttributeInfo, ObjectHandle, ParameterSetType};
11use cryptoki::session::Session;
12use cryptoki::types::Ulong;
13use indexmap::IndexMap;
14use serde::{Deserialize, Serialize};
15use strum::IntoEnumIterator;
16
17use super::AttributeError;
18use super::AttributeType;
19use super::CertificateType;
20use super::Date;
21use super::KeyType;
22use super::MechanismType;
23use super::ObjectClass;
24use super::{AttrData, Redacted};
25
26fn into_kv(attr: &Attribute) -> Result<(AttributeType, AttrData)> {
30 match attr {
31 Attribute::AlwaysAuthenticate(b)
33 | Attribute::AlwaysSensitive(b)
34 | Attribute::Copyable(b)
35 | Attribute::Decrypt(b)
36 | Attribute::Derive(b)
37 | Attribute::Destroyable(b)
38 | Attribute::Encrypt(b)
39 | Attribute::Extractable(b)
40 | Attribute::Local(b)
41 | Attribute::Modifiable(b)
42 | Attribute::NeverExtractable(b)
43 | Attribute::Private(b)
44 | Attribute::Sensitive(b)
45 | Attribute::Sign(b)
46 | Attribute::SignRecover(b)
47 | Attribute::Token(b)
48 | Attribute::Trusted(b)
49 | Attribute::Unwrap(b)
50 | Attribute::Verify(b)
51 | Attribute::VerifyRecover(b)
52 | Attribute::Wrap(b)
53 | Attribute::WrapWithTrusted(b) => Ok((
54 AttributeType::from(attr.attribute_type()),
55 AttrData::from(*b),
56 )),
57 Attribute::ModulusBits(val) | Attribute::ValueLen(val) => Ok((
59 AttributeType::from(attr.attribute_type()),
60 AttrData::from(*val),
61 )),
62 Attribute::Application(bytes) | Attribute::Label(bytes) | Attribute::Url(bytes) => Ok((
64 AttributeType::from(attr.attribute_type()),
65 AttrData::from_ascii_bytes(bytes.as_slice()),
66 )),
67 Attribute::AcIssuer(bytes)
69 | Attribute::AttrTypes(bytes)
70 | Attribute::Base(bytes)
71 | Attribute::CheckValue(bytes)
72 | Attribute::Coefficient(bytes)
73 | Attribute::EcParams(bytes)
74 | Attribute::EcPoint(bytes)
75 | Attribute::Exponent1(bytes)
76 | Attribute::Exponent2(bytes)
77 | Attribute::HashOfIssuerPublicKey(bytes)
78 | Attribute::HashOfSubjectPublicKey(bytes)
79 | Attribute::Issuer(bytes)
80 | Attribute::ObjectId(bytes)
81 | Attribute::Prime(bytes)
82 | Attribute::Prime1(bytes)
83 | Attribute::Prime2(bytes)
84 | Attribute::PrivateExponent(bytes)
85 | Attribute::PublicExponent(bytes)
86 | Attribute::PublicKeyInfo(bytes)
87 | Attribute::Modulus(bytes)
88 | Attribute::Owner(bytes)
89 | Attribute::SerialNumber(bytes)
90 | Attribute::Subject(bytes)
91 | Attribute::Value(bytes)
92 | Attribute::Id(bytes) => Ok((
93 AttributeType::from(attr.attribute_type()),
94 AttrData::from(bytes.as_slice()),
95 )),
96 Attribute::CertificateType(certificate_type) => {
98 let val = CertificateType::from(*certificate_type);
99 Ok((
100 AttributeType::from(attr.attribute_type()),
101 AttrData::from(val),
102 ))
103 }
104 Attribute::ParameterSet(val) => Ok((
105 AttributeType::from(attr.attribute_type()),
106 AttrData::from(**val),
107 )),
108 Attribute::Class(object_class) => {
109 let val = ObjectClass::from(*object_class);
110 Ok((
111 AttributeType::from(attr.attribute_type()),
112 AttrData::from(val),
113 ))
114 }
115 Attribute::KeyGenMechanism(mech) => {
116 let val = MechanismType::from(*mech);
117 Ok((
118 AttributeType::from(attr.attribute_type()),
119 AttrData::from(val),
120 ))
121 }
122 Attribute::KeyType(key_type) => {
123 let val = KeyType::from(*key_type);
124 Ok((
125 AttributeType::from(attr.attribute_type()),
126 AttrData::from(val),
127 ))
128 }
129 Attribute::AllowedMechanisms(mechanisms) => {
130 let val = mechanisms
131 .iter()
132 .map(|m| AttrData::from(MechanismType::from(*m)))
133 .collect::<Vec<_>>();
134 Ok((
135 AttributeType::from(attr.attribute_type()),
136 AttrData::List(val),
137 ))
138 }
139 Attribute::EndDate(date) | Attribute::StartDate(date) => {
140 let val = Date::from(*date);
141 Ok((
142 AttributeType::from(attr.attribute_type()),
143 AttrData::Str(val.into()),
144 ))
145 }
146 _ => Err(AttributeError::UnknownAttribute(attr.clone()).into()),
147 }
148}
149
150fn from_kv(atype: AttributeType, data: &AttrData) -> Result<Attribute> {
154 match atype {
155 AttributeType::AcIssuer => Ok(Attribute::AcIssuer(data.try_into()?)),
156 AttributeType::AllowedMechanisms => match data {
157 AttrData::List(v) => {
158 let mechs = v
159 .iter()
160 .map(|a| Ok(MechanismType::try_from(a)?.try_into()?))
161 .collect::<Result<Vec<cryptoki::mechanism::MechanismType>>>()?;
162 Ok(Attribute::AllowedMechanisms(mechs))
163 }
164 _ => Err(AttributeError::InvalidDataType.into()),
165 },
166 AttributeType::AlwaysAuthenticate => Ok(Attribute::AlwaysAuthenticate(data.try_into()?)),
167 AttributeType::AlwaysSensitive => Ok(Attribute::AlwaysSensitive(data.try_into()?)),
168 AttributeType::Application => Ok(Attribute::Application(data.try_into()?)),
169 AttributeType::AttrTypes => Ok(Attribute::AttrTypes(data.try_into()?)),
170 AttributeType::Base => Ok(Attribute::Base(data.try_into()?)),
171 AttributeType::CertificateType => Ok(Attribute::CertificateType(
172 CertificateType::try_from(data)?.try_into()?,
173 )),
174 AttributeType::CheckValue => Ok(Attribute::CheckValue(data.try_into()?)),
175 AttributeType::Class => Ok(Attribute::Class(ObjectClass::try_from(data)?.try_into()?)),
176 AttributeType::Coefficient => Ok(Attribute::Coefficient(data.try_into()?)),
177 AttributeType::Copyable => Ok(Attribute::Copyable(data.try_into()?)),
178 AttributeType::Decrypt => Ok(Attribute::Decrypt(data.try_into()?)),
179 AttributeType::Derive => Ok(Attribute::Derive(data.try_into()?)),
180 AttributeType::Destroyable => Ok(Attribute::Destroyable(data.try_into()?)),
181 AttributeType::EcParams => Ok(Attribute::EcParams(data.try_into()?)),
182 AttributeType::EcPoint => Ok(Attribute::EcPoint(data.try_into()?)),
183 AttributeType::Encrypt => Ok(Attribute::Encrypt(data.try_into()?)),
184 AttributeType::EndDate => Ok(Attribute::EndDate(Date::try_from(data)?.try_into()?)),
185 AttributeType::Exponent1 => Ok(Attribute::Exponent1(data.try_into()?)),
186 AttributeType::Exponent2 => Ok(Attribute::Exponent2(data.try_into()?)),
187 AttributeType::Extractable => Ok(Attribute::Extractable(data.try_into()?)),
188 AttributeType::HashOfIssuerPublicKey => {
189 Ok(Attribute::HashOfIssuerPublicKey(data.try_into()?))
190 }
191 AttributeType::HashOfSubjectPublicKey => {
192 Ok(Attribute::HashOfSubjectPublicKey(data.try_into()?))
193 }
194 AttributeType::Id => Ok(Attribute::Id(data.try_into()?)),
195 AttributeType::Issuer => Ok(Attribute::Issuer(data.try_into()?)),
196 AttributeType::KeyGenMechanism => Ok(Attribute::KeyGenMechanism(
197 MechanismType::try_from(data)?.try_into()?,
198 )),
199 AttributeType::KeyType => Ok(Attribute::KeyType(KeyType::try_from(data)?.try_into()?)),
200 AttributeType::Label => Ok(Attribute::Label(data.try_into()?)),
201 AttributeType::Local => Ok(Attribute::Local(data.try_into()?)),
202 AttributeType::Modifiable => Ok(Attribute::Modifiable(data.try_into()?)),
203 AttributeType::Modulus => Ok(Attribute::Modulus(data.try_into()?)),
204 AttributeType::ModulusBits => Ok(Attribute::ModulusBits(data.try_into()?)),
205 AttributeType::NeverExtractable => Ok(Attribute::NeverExtractable(data.try_into()?)),
206 AttributeType::ObjectId => Ok(Attribute::ObjectId(data.try_into()?)),
207 AttributeType::Owner => Ok(Attribute::Owner(data.try_into()?)),
208 AttributeType::ParameterSet => {
209 let val = u64::try_from(data)?;
211 match ParameterSetType::try_from(Ulong::from(val)) {
212 Ok(p) => Ok(Attribute::ParameterSet(p)),
213 Err(e) => {
214 log::error!("ParameterSetType conversion failed for {}: {:?}", val, e);
215 Err(AttributeError::InvalidDataType.into())
216 }
217 }
218 }
219 AttributeType::Prime => Ok(Attribute::Prime(data.try_into()?)),
220 AttributeType::Prime1 => Ok(Attribute::Prime1(data.try_into()?)),
221 AttributeType::Prime2 => Ok(Attribute::Prime2(data.try_into()?)),
222 AttributeType::Private => Ok(Attribute::Private(data.try_into()?)),
223 AttributeType::PrivateExponent => Ok(Attribute::PrivateExponent(data.try_into()?)),
224 AttributeType::PublicExponent => Ok(Attribute::PublicExponent(data.try_into()?)),
225 AttributeType::PublicKeyInfo => Ok(Attribute::PublicKeyInfo(data.try_into()?)),
226 AttributeType::Sensitive => Ok(Attribute::Sensitive(data.try_into()?)),
227 AttributeType::SerialNumber => Ok(Attribute::SerialNumber(data.try_into()?)),
228 AttributeType::Sign => Ok(Attribute::Sign(data.try_into()?)),
229 AttributeType::SignRecover => Ok(Attribute::SignRecover(data.try_into()?)),
230 AttributeType::StartDate => Ok(Attribute::StartDate(Date::try_from(data)?.try_into()?)),
231 AttributeType::Subject => Ok(Attribute::Subject(data.try_into()?)),
232 AttributeType::Token => Ok(Attribute::Token(data.try_into()?)),
233 AttributeType::Trusted => Ok(Attribute::Trusted(data.try_into()?)),
234 AttributeType::Unwrap => Ok(Attribute::Unwrap(data.try_into()?)),
235 AttributeType::Url => Ok(Attribute::Url(data.try_into()?)),
236 AttributeType::Value => Ok(Attribute::Value(data.try_into()?)),
237 AttributeType::ValueLen => Ok(Attribute::ValueLen(data.try_into()?)),
238 AttributeType::Verify => Ok(Attribute::Verify(data.try_into()?)),
239 AttributeType::VerifyRecover => Ok(Attribute::VerifyRecover(data.try_into()?)),
240 AttributeType::Wrap => Ok(Attribute::Wrap(data.try_into()?)),
241 AttributeType::WrapWithTrusted => Ok(Attribute::WrapWithTrusted(data.try_into()?)),
242 _ => Err(AttributeError::UnknownAttributeType(atype).into()),
243 }
244}
245
246#[derive(Clone, Debug, Default, Serialize, Deserialize)]
247pub struct AttributeMap(IndexMap<AttributeType, AttrData>);
248
249impl From<&[Attribute]> for AttributeMap {
250 fn from(a: &[Attribute]) -> Self {
251 AttributeMap(
252 a.iter()
253 .map(|a| into_kv(a).expect("convert from attribute"))
254 .collect(),
255 )
256 }
257}
258
259impl AttributeMap {
260 pub fn all() -> &'static [cryptoki::object::AttributeType] {
266 static VALID_TYPES: LazyLock<Vec<cryptoki::object::AttributeType>> = LazyLock::new(|| {
267 AttributeType::iter()
268 .filter(|&a| a != AttributeType::KeyGenMechanism)
272 .map(|a| Ok(a.try_into()?))
273 .filter(|a| a.is_ok())
274 .collect::<Result<Vec<_>>>()
275 .unwrap()
276 });
277
278 VALID_TYPES.as_slice()
279 }
280
281 pub fn sensitive_attrs() -> &'static [cryptoki::object::AttributeType] {
286 &[
287 cryptoki::object::AttributeType::Value,
289 cryptoki::object::AttributeType::PrivateExponent,
291 cryptoki::object::AttributeType::Prime1,
292 cryptoki::object::AttributeType::Prime2,
293 cryptoki::object::AttributeType::Exponent1,
294 cryptoki::object::AttributeType::Exponent2,
295 cryptoki::object::AttributeType::Coefficient,
296 ]
297 }
298
299 pub fn insert(&mut self, key: AttributeType, value: AttrData) -> Option<AttrData> {
302 self.0.insert(key, value)
303 }
304
305 pub fn get(&self, key: &AttributeType) -> Option<&AttrData> {
307 self.0.get(key)
308 }
309
310 pub fn is_empty(&self) -> bool {
312 self.0.is_empty()
313 }
314
315 pub fn to_vec(&self) -> Result<Vec<Attribute>> {
317 self.0.iter().map(|(k, v)| from_kv(*k, v)).collect()
318 }
319
320 pub fn merge(&mut self, other: AttributeMap) {
322 for (k, v) in other.0 {
323 self.insert(k, v);
324 }
325 }
326
327 pub fn redact(&mut self, redactions: &HashSet<AttributeType>) {
328 for (k, v) in self.0.iter_mut() {
329 if redactions.contains(k) && !matches!(v, AttrData::Redacted(_)) {
330 *v = AttrData::Redacted(Redacted::RedactedByTool);
331 }
332 }
333 }
334
335 pub fn from_object(session: &Session, object: ObjectHandle) -> Result<Self> {
337 let all = Self::all();
338 let sensitive_attrs = Self::sensitive_attrs();
339 let info = session.get_attribute_info(object, all)?;
340 let mut atypes = Vec::new();
341 let mut sensitive_types = Vec::new();
342 for (&a, i) in all.iter().zip(info.iter()) {
343 if a == cryptoki::object::AttributeType::AllowedMechanisms {
346 continue;
347 }
348
349 if sensitive_attrs.contains(&a) {
354 sensitive_types.push(a);
355 continue;
356 }
357
358 if matches!(i, AttributeInfo::Available(_)) {
359 atypes.push(a);
360 }
361 }
362
363 let attrs = session.get_attributes(object, &atypes)?;
364 let mut map = AttributeMap::from(attrs.as_slice());
365
366 let sensitive = map.get(&AttributeType::Sensitive);
367 let object_sensitive = matches!(sensitive, Some(AttrData::Bool(true)));
368
369 sensitive_types.iter().for_each(|&attr| {
373 if object_sensitive {
374 map.insert(
375 AttributeType::Value,
376 AttrData::Redacted(Redacted::RedactedByHsm),
377 );
378 } else if let Ok(attrs) = session.get_attributes(object, &[attr])
379 && let Some(attr_obj) = attrs.into_iter().next()
380 && let Ok((ty, val)) = into_kv(&attr_obj)
381 {
382 map.insert(ty, val);
383 }
384 });
385
386 for (&a, i) in all.iter().zip(info.iter()) {
389 if matches!(i, AttributeInfo::Sensitive) {
390 map.insert(a.into(), AttrData::Redacted(Redacted::RedactedByHsm));
391 }
392 }
393 Ok(map)
394 }
395}
396
397impl FromStr for AttributeMap {
398 type Err = anyhow::Error;
399
400 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
402 if let Some(path) = s.strip_prefix('@') {
403 let data = std::fs::read_to_string(path)?;
404 Ok(serde_annotate::from_str(&data)?)
405 } else {
406 Ok(serde_annotate::from_str(s)?)
407 }
408 }
409}
410
411#[cfg(test)]
412mod tests {
413 use super::*;
414
415 #[test]
416 fn test_attribute_to_kv() -> Result<()> {
417 let a = Attribute::Copyable(true);
418 let (ty, data) = into_kv(&a)?;
419 assert_eq!(ty, AttributeType::Copyable);
420 assert_eq!(data, AttrData::Bool(true));
421 Ok(())
422 }
423
424 #[test]
425 fn test_kv_to_attribute() -> Result<()> {
426 let a = from_kv(AttributeType::Copyable, &AttrData::Bool(true))?;
427 assert!(matches!(a, Attribute::Copyable(true)));
428 Ok(())
429 }
430
431 const ATTR_MAP: &str = r#"{
432 "CKA_COPYABLE": true,
433 "CKA_MODULUS_BITS": 3072,
434 "CKA_LABEL": "foo",
435 "CKA_OBJECT_ID": "12:34:56:78",
436 "CKA_CERTIFICATE_TYPE": "CKC_X_509",
437 "CKA_CLASS": "CKO_CERTIFICATE",
438 "CKA_KEY_TYPE": "CKK_RSA",
439 "CKA_KEY_GEN_MECHANISM": "CKM_RSA_PKCS",
440 "CKA_ALLOWED_MECHANISMS": [
441 "CKM_RSA_PKCS",
442 "CKM_RSA_PKCS_KEY_PAIR_GEN"
443 ],
444 "CKA_START_DATE": "2023-02-15"
445}"#;
446
447 #[test]
448 fn test_to_attribute_map() -> Result<()> {
449 let a = [
450 Attribute::Copyable(true),
451 Attribute::ModulusBits(3072u64.into()),
452 Attribute::Label(vec![b'f', b'o', b'o']),
453 Attribute::ObjectId(vec![0x12, 0x34, 0x56, 0x78]),
454 Attribute::CertificateType(CertificateType::X509.try_into()?),
455 Attribute::Class(ObjectClass::Certificate.try_into()?),
456 Attribute::KeyType(KeyType::Rsa.try_into()?),
457 Attribute::KeyGenMechanism(MechanismType::RsaPkcs.try_into()?),
458 Attribute::AllowedMechanisms(vec![
459 MechanismType::RsaPkcs.try_into()?,
460 MechanismType::RsaPkcsKeyPairGen.try_into()?,
461 ]),
462 Attribute::StartDate(Date::from("2023-02-15").try_into()?),
463 ];
464 let am = AttributeMap::from(a.as_slice());
465 let json = serde_json::to_string_pretty(&am)?;
466 assert_eq!(json, ATTR_MAP);
467 Ok(())
468 }
469
470 #[test]
471 fn test_from_attribute_map() -> Result<()> {
472 let map = serde_json::from_str::<AttributeMap>(ATTR_MAP)?;
473 let a = map.to_vec()?;
474 let result = format!("{:x?}", a);
477 assert_eq!(
478 result,
479 "[Copyable(true), ModulusBits(Ulong { val: c00 }), Label([66, 6f, 6f]), ObjectId([12, 34, 56, 78]), CertificateType(CertificateType { val: 0 }), Class(ObjectClass { val: 1 }), KeyType(KeyType { val: 0 }), KeyGenMechanism(MechanismType { val: 1 }), AllowedMechanisms([MechanismType { val: 1 }, MechanismType { val: 0 }]), StartDate(Date { date: CK_DATE { year: [32, 30, 32, 33], month: [30, 32], day: [31, 35] } })]"
480 );
481 Ok(())
482 }
483}