1use anyhow::{Ok, Result};
10use clap::ValueEnum;
11use cryptoki::mechanism::rsa::{PkcsMgfType, PkcsOaepParams, PkcsOaepSource};
12use cryptoki::mechanism::vendor_defined::{CKM_VENDOR_DEFINED, VendorDefinedMechanism};
13use cryptoki::mechanism::{Mechanism, MechanismType};
14use cryptoki::object::{Attribute, ObjectHandle};
15use cryptoki::session::Session;
16use serde::{Deserialize, Serialize};
17use strum::{Display, EnumString};
18
19use crate::error::HsmError;
20use crate::util::attribute::{AttributeMap, AttributeType, KeyType, ObjectClass};
21use crate::util::helper;
22
23#[derive(
25 Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Display, EnumString, ValueEnum,
26)]
27#[strum(ascii_case_insensitive)]
28pub enum Wrap {
29 AesKeyWrap,
30 AesKeyWrapPad,
31 RsaPkcs,
32 RsaPkcsOaep,
33 VendorThalesAesKw,
34 VendorThalesAesKwp,
35}
36
37#[derive(
39 Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Display, EnumString, ValueEnum,
40)]
41#[strum(ascii_case_insensitive)]
42pub enum WrapPrivateKey {
43 AesKeyWrap,
44 AesKeyWrapPad,
45 VendorThalesAesKw,
46 VendorThalesAesKwp,
47}
48
49impl From<WrapPrivateKey> for Wrap {
50 fn from(wrap: WrapPrivateKey) -> Self {
51 match wrap {
52 WrapPrivateKey::AesKeyWrap => Wrap::AesKeyWrap,
53 WrapPrivateKey::AesKeyWrapPad => Wrap::AesKeyWrapPad,
54 WrapPrivateKey::VendorThalesAesKw => Wrap::VendorThalesAesKw,
55 WrapPrivateKey::VendorThalesAesKwp => Wrap::VendorThalesAesKwp,
56 }
57 }
58}
59
60impl Wrap {
61 const CKM_THALES_AES_KW: u64 = CKM_VENDOR_DEFINED | 0x00000170;
63 const CKM_THALES_AES_KWP: u64 = CKM_VENDOR_DEFINED | 0x00000171;
64
65 pub fn mechanism(&self) -> Result<Mechanism<'_>> {
66 match self {
67 Wrap::AesKeyWrap => Ok(Mechanism::AesKeyWrap),
68 Wrap::AesKeyWrapPad => Ok(Mechanism::AesKeyWrapPad),
69 Wrap::RsaPkcs => Ok(Mechanism::RsaPkcs),
70 Wrap::RsaPkcsOaep => Ok(Mechanism::RsaPkcsOaep(PkcsOaepParams::new(
71 MechanismType::SHA256,
72 PkcsMgfType::MGF1_SHA256,
73 PkcsOaepSource::empty(),
74 ))),
75 Wrap::VendorThalesAesKw => {
76 Ok(Mechanism::VendorDefined(VendorDefinedMechanism::new::<()>(
77 MechanismType::new_vendor_defined(Wrap::CKM_THALES_AES_KW)?,
78 None,
79 )))
80 }
81 Wrap::VendorThalesAesKwp => {
82 Ok(Mechanism::VendorDefined(VendorDefinedMechanism::new::<()>(
83 MechanismType::new_vendor_defined(Wrap::CKM_THALES_AES_KWP)?,
84 None,
85 )))
86 }
87 }
88 }
89
90 pub fn wrapping_key(&self, session: &Session, label: Option<&str>) -> Result<ObjectHandle> {
91 let mut attrs = helper::search_spec(None, label)?;
92 attrs.push(Attribute::Wrap(true));
93 match self {
94 Wrap::AesKeyWrap
95 | Wrap::AesKeyWrapPad
96 | Wrap::VendorThalesAesKw
97 | Wrap::VendorThalesAesKwp => {
98 attrs.push(Attribute::KeyType(KeyType::Aes.try_into()?));
99 attrs.push(Attribute::Class(ObjectClass::SecretKey.try_into()?));
100 helper::find_one_object(session, &attrs)
101 }
102 Wrap::RsaPkcs | Wrap::RsaPkcsOaep => {
103 attrs.push(Attribute::KeyType(KeyType::Rsa.try_into()?));
104 attrs.push(Attribute::Class(ObjectClass::PublicKey.try_into()?));
105 helper::find_one_object(session, &attrs)
106 }
107 }
108 }
109
110 pub fn unwrapping_key(&self, session: &Session, label: Option<&str>) -> Result<ObjectHandle> {
111 let mut attrs = helper::search_spec(None, label)?;
112 attrs.push(Attribute::Unwrap(true));
113 match self {
114 Wrap::AesKeyWrap
115 | Wrap::AesKeyWrapPad
116 | Wrap::VendorThalesAesKw
117 | Wrap::VendorThalesAesKwp => {
118 attrs.push(Attribute::KeyType(KeyType::Aes.try_into()?));
119 attrs.push(Attribute::Class(ObjectClass::SecretKey.try_into()?));
120 helper::find_one_object(session, &attrs)
121 }
122 Wrap::RsaPkcs | Wrap::RsaPkcsOaep => {
123 attrs.push(Attribute::KeyType(KeyType::Rsa.try_into()?));
124 attrs.push(Attribute::Class(ObjectClass::PrivateKey.try_into()?));
125 helper::find_one_object(session, &attrs)
126 }
127 }
128 }
129
130 pub fn check_key(&self, session: &Session, key: ObjectHandle) -> Result<()> {
131 let map = AttributeMap::from_object(session, key)?;
132
133 let extractable: bool = map
134 .get(&AttributeType::Extractable)
135 .ok_or_else(|| HsmError::KeyError("Key does not have an extractable attribute".into()))?
136 .try_into()
137 .map_err(HsmError::AttributeError)?;
138 if !extractable {
139 Err(HsmError::KeyError("Key is not extractable".into()))?;
140 }
141
142 let key_type: KeyType = map
143 .get(&AttributeType::KeyType)
144 .ok_or_else(|| HsmError::KeyError("Key does not have a key type attribute".into()))?
145 .try_into()
146 .map_err(HsmError::AttributeError)?;
147
148 if *self == Wrap::RsaPkcsOaep || *self == Wrap::RsaPkcs {
149 let result = match key_type {
150 KeyType::Aes => Ok(()),
151 KeyType::GenericSecret => Ok(()),
152 _ => Err(HsmError::KeyError(format!(
153 "Unsupported key type: {key_type:?}"
154 )))?,
155 };
156 result?;
157 }
158
159 Ok(())
160 }
161
162 pub fn wrap(
163 &self,
164 session: &Session,
165 key: ObjectHandle,
166 wrapping_key_label: Option<&str>,
167 ) -> Result<Vec<u8>> {
168 self.check_key(session, key)?;
169 let wrapping_key = self.wrapping_key(session, wrapping_key_label)?;
170 let mechanism = self.mechanism()?;
171 Ok(session.wrap_key(&mechanism, wrapping_key, key)?)
172 }
173
174 pub fn unwrap(
175 &self,
176 session: &Session,
177 wrapped_key: &[u8],
178 wrapping_key_label: Option<&str>,
179 template: &AttributeMap,
180 ) -> Result<ObjectHandle> {
181 let wrapping_key = self.unwrapping_key(session, wrapping_key_label)?;
182 let mechanism = self.mechanism()?;
183 Ok(session.unwrap_key(
184 &mechanism,
185 wrapping_key,
186 wrapped_key,
187 template.to_vec()?.as_slice(),
188 )?)
189 }
190}