1use crate::error::{HsmError, HsmResult};
4use crate::key::{HsmKeyPair, KeyAlgorithm, MlDsaLevel, MlKemLevel, PqcMechanismIds};
5use cryptoki::mechanism::{Mechanism, MechanismType};
6use cryptoki::object::ObjectHandle;
7use cryptoki::session::Session;
8
9pub trait HsmSigner {
11 fn sign(&self, key: &HsmKeyPair, digest: &[u8]) -> HsmResult<Vec<u8>>;
22
23 fn sign_with_mechanism(
25 &self,
26 key: &HsmKeyPair,
27 digest: &[u8],
28 mechanism: &Mechanism,
29 ) -> HsmResult<Vec<u8>>;
30
31 fn wrap_key_aes(
35 &self,
36 session: &Session,
37 wrapping_key: ObjectHandle,
38 key_to_wrap: ObjectHandle,
39 ) -> HsmResult<Vec<u8>>;
40
41 fn wrap_key_rsa_oaep(
43 &self,
44 session: &Session,
45 wrapping_key: ObjectHandle,
46 key_to_wrap: ObjectHandle,
47 ) -> HsmResult<Vec<u8>>;
48
49 fn ml_kem_encapsulate(
60 &self,
61 session: &Session,
62 public_key: ObjectHandle,
63 pqc_mechanisms: &PqcMechanismIds,
64 ) -> HsmResult<(Vec<u8>, Vec<u8>)>;
65
66 fn ml_kem_decapsulate(
78 &self,
79 session: &Session,
80 private_key: ObjectHandle,
81 ciphertext: &[u8],
82 pqc_mechanisms: &PqcMechanismIds,
83 ) -> HsmResult<Vec<u8>>;
84}
85
86pub struct DefaultHsmSigner;
88
89impl HsmSigner for DefaultHsmSigner {
90 fn sign(&self, key: &HsmKeyPair, digest: &[u8]) -> HsmResult<Vec<u8>> {
91 let mechanism = match key.algorithm() {
92 KeyAlgorithm::Rsa(_bits) => {
93 Mechanism::Sha256RsaPkcs
95 }
96 KeyAlgorithm::Ecdsa(_curve) => {
97 Mechanism::Ecdsa
99 }
100 KeyAlgorithm::MlDsa(_level) => {
101 return Err(HsmError::PqcNotSupported(
103 "ML-DSA signing requires explicit mechanism ID".to_string(),
104 ));
105 }
106 KeyAlgorithm::MlKem(_level) => {
107 return Err(HsmError::UnsupportedMechanism(
108 "ML-KEM is for encapsulation, not signing".to_string(),
109 ));
110 }
111 };
112
113 self.sign_with_mechanism(key, digest, &mechanism)
114 }
115
116 fn sign_with_mechanism(
117 &self,
118 key: &HsmKeyPair,
119 digest: &[u8],
120 mechanism: &Mechanism,
121 ) -> HsmResult<Vec<u8>> {
122 let session = key.session();
123 let private_key = key.private_key();
124
125 session
126 .sign(mechanism, private_key, digest)
127 .map_err(|e| HsmError::SigningFailure(format!("Sign operation failed: {e}")))
128 }
129
130 fn wrap_key_aes(
131 &self,
132 session: &Session,
133 wrapping_key: ObjectHandle,
134 key_to_wrap: ObjectHandle,
135 ) -> HsmResult<Vec<u8>> {
136 let mechanism = Mechanism::AesKeyWrap;
137
138 session
139 .wrap_key(&mechanism, wrapping_key, key_to_wrap)
140 .map_err(|e| HsmError::KeyWrap(format!("AES key wrap failed: {e}")))
141 }
142
143 fn wrap_key_rsa_oaep(
144 &self,
145 _session: &Session,
146 _wrapping_key: ObjectHandle,
147 _key_to_wrap: ObjectHandle,
148 ) -> HsmResult<Vec<u8>> {
149 Err(HsmError::KeyWrap(
152 "RSA-OAEP key wrap not yet implemented for cryptoki 0.7".to_string(),
153 ))
154 }
155
156 fn ml_kem_encapsulate(
157 &self,
158 _session: &Session,
159 _public_key: ObjectHandle,
160 _pqc_mechanisms: &PqcMechanismIds,
161 ) -> HsmResult<(Vec<u8>, Vec<u8>)> {
162 Err(HsmError::PqcNotSupported(
165 "ML-KEM encapsulate not yet implemented (requires vendor extensions)".to_string(),
166 ))
167 }
168
169 fn ml_kem_decapsulate(
170 &self,
171 _session: &Session,
172 _private_key: ObjectHandle,
173 _ciphertext: &[u8],
174 _pqc_mechanisms: &PqcMechanismIds,
175 ) -> HsmResult<Vec<u8>> {
176 Err(HsmError::PqcNotSupported(
178 "ML-KEM decapsulate not yet implemented (requires vendor extensions)".to_string(),
179 ))
180 }
181}
182
183pub fn sign_rsa_pkcs1(
185 key: &HsmKeyPair,
186 digest: &[u8],
187 hash_algorithm: RsaHashAlgorithm,
188) -> HsmResult<Vec<u8>> {
189 let mechanism = match hash_algorithm {
190 RsaHashAlgorithm::Sha256 => Mechanism::Sha256RsaPkcs,
191 RsaHashAlgorithm::Sha384 => Mechanism::Sha384RsaPkcs,
192 RsaHashAlgorithm::Sha512 => Mechanism::Sha512RsaPkcs,
193 };
194
195 let signer = DefaultHsmSigner;
196 signer.sign_with_mechanism(key, digest, &mechanism)
197}
198
199pub fn sign_rsa_pss(
201 _key: &HsmKeyPair,
202 _digest: &[u8],
203 _hash_algorithm: RsaHashAlgorithm,
204) -> HsmResult<Vec<u8>> {
205 Err(HsmError::UnsupportedMechanism(
208 "RSA-PSS signing not yet implemented for cryptoki 0.7".to_string(),
209 ))
210}
211
212pub fn sign_ecdsa(key: &HsmKeyPair, digest: &[u8]) -> HsmResult<Vec<u8>> {
214 let mechanism = Mechanism::Ecdsa;
215 let signer = DefaultHsmSigner;
216 signer.sign_with_mechanism(key, digest, &mechanism)
217}
218
219pub fn sign_ml_dsa(
224 _key: &HsmKeyPair,
225 _message: &[u8],
226 level: MlDsaLevel,
227 pqc_mechanisms: &PqcMechanismIds,
228) -> HsmResult<Vec<u8>> {
229 let mechanism_id = match level {
230 MlDsaLevel::L2 => pqc_mechanisms.ml_dsa_44,
231 MlDsaLevel::L3 => pqc_mechanisms.ml_dsa_65,
232 MlDsaLevel::L5 => pqc_mechanisms.ml_dsa_87,
233 }
234 .ok_or_else(|| {
235 HsmError::PqcNotSupported(format!("ML-DSA level {level:?} mechanism not configured"))
236 })?;
237
238 tracing::warn!(
239 "Attempting ML-DSA signing with vendor mechanism ID 0x{:08x}",
240 mechanism_id
241 );
242
243 Err(HsmError::PqcNotSupported(
246 "ML-DSA signing requires vendor-specific PKCS#11 extensions not available in cryptoki 0.7"
247 .to_string(),
248 ))
249}
250
251#[derive(Debug, Clone, Copy, PartialEq, Eq)]
253pub enum RsaHashAlgorithm {
254 Sha256,
255 Sha384,
256 Sha512,
257}
258
259pub struct SoftwarePqcFallback;
264
265impl SoftwarePqcFallback {
266 pub fn is_hsm_supported(
268 mechanism_type: MechanismType,
269 provider_mechanisms: &[MechanismType],
270 ) -> bool {
271 provider_mechanisms.contains(&mechanism_type)
272 }
273
274 pub fn sign_ml_dsa_software(
278 _message: &[u8],
279 _private_key_bytes: &[u8],
280 _level: MlDsaLevel,
281 ) -> HsmResult<Vec<u8>> {
282 Err(HsmError::PqcNotSupported(
284 "Software ML-DSA fallback not yet implemented".to_string(),
285 ))
286 }
287
288 pub fn ml_kem_encapsulate_software(
290 _public_key_bytes: &[u8],
291 _level: MlKemLevel,
292 ) -> HsmResult<(Vec<u8>, Vec<u8>)> {
293 Err(HsmError::PqcNotSupported(
295 "Software ML-KEM encapsulate fallback not yet implemented".to_string(),
296 ))
297 }
298
299 pub fn ml_kem_decapsulate_software(
301 _private_key_bytes: &[u8],
302 _ciphertext: &[u8],
303 _level: MlKemLevel,
304 ) -> HsmResult<Vec<u8>> {
305 Err(HsmError::PqcNotSupported(
307 "Software ML-KEM decapsulate fallback not yet implemented".to_string(),
308 ))
309 }
310}
311
312#[cfg(test)]
313mod tests {
314 use super::*;
315
316 #[test]
317 fn test_software_fallback_detection() {
318 let mechanisms = vec![
319 MechanismType::RSA_PKCS,
320 MechanismType::ECDSA,
321 MechanismType::AES_KEY_WRAP,
322 ];
323
324 assert!(SoftwarePqcFallback::is_hsm_supported(
325 MechanismType::RSA_PKCS,
326 &mechanisms
327 ));
328 assert!(!SoftwarePqcFallback::is_hsm_supported(
329 MechanismType::ECDSA_SHA256,
330 &mechanisms
331 ));
332 }
333}