Skip to content

Commit 03ad4cf

Browse files
committed
Add test coverage for slh_dsa
Signed-off-by: Jakub Jelen <[email protected]>
1 parent a7bee1b commit 03ad4cf

File tree

1 file changed

+364
-0
lines changed

1 file changed

+364
-0
lines changed

cryptoki/tests/slh_dsa.rs

Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
// Copyright 2025 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
mod common;
4+
5+
use crate::common::{init_pins, USER_PIN};
6+
use cryptoki::context::Function;
7+
use cryptoki::error::{Error, RvError};
8+
use cryptoki::mechanism::dsa::{HashSignAdditionalContext, HedgeType, SignAdditionalContext};
9+
use cryptoki::mechanism::{Mechanism, MechanismType};
10+
use cryptoki::object::{Attribute, AttributeType, SlhDsaParameterSetType};
11+
use cryptoki::session::UserType;
12+
use cryptoki::types::AuthPin;
13+
use serial_test::serial;
14+
15+
use testresult::TestResult;
16+
17+
#[test]
18+
#[serial]
19+
fn slh_dsa() -> TestResult {
20+
let (pkcs11, slot) = init_pins();
21+
// PKCS#11 3.2 API is not supported by this token. Skip
22+
if !pkcs11.is_fn_supported(Function::VerifySignature) {
23+
/* return Ignore(); */
24+
print!("SKIP: The PKCS#11 module does not support VerifySignature API");
25+
return Ok(());
26+
}
27+
28+
// open a session
29+
let session = pkcs11.open_rw_session(slot)?;
30+
31+
// log in the session
32+
session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?;
33+
34+
let mechanism = Mechanism::SlhDsaKeyPairGen;
35+
36+
// pub key template
37+
let pub_key_template = vec![
38+
Attribute::Token(true),
39+
Attribute::ParameterSet(SlhDsaParameterSetType::SHA2_256F.into()),
40+
Attribute::Verify(true),
41+
];
42+
43+
// priv key template
44+
let priv_key_template = vec![Attribute::Token(true), Attribute::Sign(true)];
45+
46+
// generate a key pair
47+
let (public, private) =
48+
session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?;
49+
50+
// without optional context
51+
let mechanism = Mechanism::SlhDsa(SignAdditionalContext::new(HedgeType::Preferred, None));
52+
53+
// data to sign
54+
let data = [0xFF, 0x55, 0xDD];
55+
56+
let signature1 = session.sign(&mechanism, private, &data)?;
57+
58+
session.verify(&mechanism, public, &data, &signature1)?;
59+
60+
// also using the new API
61+
session.verify_signature_init(&mechanism, public, &signature1)?;
62+
session.verify_signature(&data)?;
63+
64+
// With Context + Deterministic Hedge
65+
let context = [
66+
0xEE, 0x0B, 0x3F, 0x67, 0x9F, 0xB5, 0x0F, 0x59, 0xAD, 0x31, 0x32, 0x8A, 0xAF, 0x4E, 0x70,
67+
0x2C, 0xCF, 0x60, 0x92, 0xDA, 0x47, 0x94, 0xDC, 0xF0, 0x7C, 0x8, 0xEA, 0x27, 0x8B, 0x34,
68+
0x22, 0x8A, 0x41,
69+
];
70+
let mechanism = Mechanism::SlhDsa(SignAdditionalContext::new(
71+
HedgeType::DeterministicRequired,
72+
Some(&context),
73+
));
74+
75+
let signature2 = session.sign(&mechanism, private, &data)?;
76+
let signature3 = session.sign(&mechanism, private, &data)?;
77+
// Deterministic signature
78+
assert_eq!(signature2, signature3);
79+
80+
session.verify(&mechanism, public, &data, &signature2)?;
81+
82+
// also using the new API
83+
session.verify_signature_init(&mechanism, public, &signature2)?;
84+
session.verify_signature(&data)?;
85+
86+
// the signature from previous step should fail to verify with different context
87+
let result = session.verify(&mechanism, public, &data, &signature1);
88+
assert!(result.is_err());
89+
assert!(matches!(
90+
result.unwrap_err(),
91+
Error::Pkcs11(_, Function::Verify)
92+
));
93+
94+
// also using the new API
95+
session.verify_signature_init(&mechanism, public, &signature1)?;
96+
let result = session.verify_signature(&data);
97+
assert!(result.is_err());
98+
assert!(matches!(
99+
result.unwrap_err(),
100+
Error::Pkcs11(_, Function::VerifySignature)
101+
));
102+
103+
// Test convrting ParameterSet attributes back to algorithm specific values
104+
let param_attribute = session
105+
.get_attributes(public, &[AttributeType::ParameterSet])?
106+
.remove(0);
107+
let param: SlhDsaParameterSetType = if let Attribute::ParameterSet(num) = param_attribute {
108+
num.into()
109+
} else {
110+
panic!("Expected ParameterSet attribute.");
111+
};
112+
assert_eq!(param, SlhDsaParameterSetType::SHA2_256F);
113+
114+
// delete keys
115+
session.destroy_object(public)?;
116+
session.destroy_object(private)?;
117+
118+
Ok(())
119+
}
120+
121+
#[test]
122+
#[serial]
123+
fn slh_dsa_multipart() -> TestResult {
124+
let (pkcs11, slot) = init_pins();
125+
// PKCS#11 3.2 API is not supported by this token. Skip
126+
if !pkcs11.is_fn_supported(Function::VerifySignature) {
127+
/* return Ignore(); */
128+
print!("SKIP: The PKCS#11 module does not support VerifySignature API");
129+
return Ok(());
130+
}
131+
132+
// open a session
133+
let session = pkcs11.open_rw_session(slot)?;
134+
135+
// log in the session
136+
session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?;
137+
138+
let mechanism = Mechanism::SlhDsaKeyPairGen;
139+
140+
// pub key template
141+
let pub_key_template = vec![
142+
Attribute::Token(true),
143+
Attribute::ParameterSet(SlhDsaParameterSetType::SHA2_192S.into()),
144+
Attribute::Verify(true),
145+
];
146+
147+
// priv key template
148+
let priv_key_template = vec![Attribute::Token(true), Attribute::Sign(true)];
149+
150+
// generate a key pair
151+
let (public, private) =
152+
session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?;
153+
154+
// without optional context
155+
let mechanism = Mechanism::SlhDsa(SignAdditionalContext::new(HedgeType::Required, None));
156+
157+
// data to sign
158+
let data = [
159+
0x1E, 0x5A, 0x78, 0xAD, 0x64, 0xDF, 0x22, 0x9A, 0xA2, 0x2F, 0xD7, 0x94, 0xEC, 0x0E, 0x82,
160+
0xD0, 0xF6, 0x99, 0x53, 0x11, 0x8C, 0x09, 0xD1, 0x34, 0xDF, 0xA2, 0x0F, 0x1C, 0xC6, 0x4A,
161+
0x36, 0x71,
162+
];
163+
164+
session.sign_init(&mechanism, private)?;
165+
for part in data.chunks(10) {
166+
session.sign_update(part)?;
167+
}
168+
let signature = session.sign_final()?;
169+
170+
// verification of multi-part signature
171+
session.verify_init(&mechanism, public)?;
172+
for part in data.chunks(10) {
173+
session.verify_update(part)?;
174+
}
175+
session.verify_final(&signature)?;
176+
177+
// but works with the new API
178+
session.verify_signature_init(&mechanism, public, &signature)?;
179+
for part in data.chunks(10) {
180+
session.verify_signature_update(part)?;
181+
}
182+
session.verify_signature_final()?;
183+
184+
// delete keys
185+
session.destroy_object(public)?;
186+
session.destroy_object(private)?;
187+
188+
Ok(())
189+
}
190+
191+
#[test]
192+
#[serial]
193+
fn slh_dsa_hash() -> TestResult {
194+
let (pkcs11, slot) = init_pins();
195+
// PKCS#11 3.2 API is not supported by this token. Skip
196+
if !pkcs11.is_fn_supported(Function::VerifySignature) {
197+
/* return Ignore(); */
198+
print!("SKIP: The PKCS#11 module does not support VerifySignature API");
199+
return Ok(());
200+
}
201+
202+
// open a session
203+
let session = pkcs11.open_rw_session(slot)?;
204+
205+
// log in the session
206+
session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?;
207+
208+
let mechanism = Mechanism::SlhDsaKeyPairGen;
209+
210+
// pub key template
211+
let pub_key_template = vec![
212+
Attribute::Token(true),
213+
Attribute::ParameterSet(SlhDsaParameterSetType::SHA2_128S.into()),
214+
Attribute::Verify(true),
215+
];
216+
217+
// priv key template
218+
let priv_key_template = vec![Attribute::Token(true), Attribute::Sign(true)];
219+
220+
// generate a key pair
221+
let (public, private) =
222+
session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?;
223+
224+
// without optional context
225+
let mechanism = Mechanism::HashSlhDsa(HashSignAdditionalContext::new(
226+
HedgeType::Preferred,
227+
None,
228+
MechanismType::SHA384,
229+
));
230+
231+
// data to sign is already sha384 hash!
232+
let data = [
233+
0x1E, 0x5A, 0x78, 0xAD, 0x64, 0xDF, 0x22, 0x9A, 0xA2, 0x2F, 0xD7, 0x94, 0xEC, 0x0E, 0x82,
234+
0xD0, 0xF6, 0x99, 0x53, 0x11, 0x8C, 0x09, 0xD1, 0x34, 0xDF, 0xA2, 0x0F, 0x1C, 0xC6, 0x4A,
235+
0xD0, 0xF6, 0x99, 0x53, 0x11, 0x8C, 0x09, 0xD1, 0x34, 0xDF, 0xA2, 0x0F, 0x1C, 0xC6, 0x4A,
236+
0x36, 0x71, 0x31,
237+
];
238+
239+
// the hash SLH-DSA does not support multi-part operation
240+
session.sign_init(&mechanism, private)?;
241+
let result = session.sign_update(&data[..10]);
242+
assert!(result.is_err());
243+
assert!(matches!(
244+
result.unwrap_err(),
245+
Error::Pkcs11(RvError::OperationNotInitialized, Function::SignUpdate)
246+
));
247+
248+
// this should do with one-shot
249+
let signature = session.sign(&mechanism, private, &data)?;
250+
251+
// verification of multi-part signature does not work here either
252+
session.verify_init(&mechanism, public)?;
253+
let result = session.verify_update(&data[..10]);
254+
assert!(result.is_err());
255+
assert!(matches!(
256+
result.unwrap_err(),
257+
Error::Pkcs11(RvError::OperationNotInitialized, Function::VerifyUpdate)
258+
));
259+
260+
// this should do with one-shot
261+
session.verify(&mechanism, public, &data, &signature)?;
262+
263+
// multipart verification does not work with the new API either
264+
session.verify_signature_init(&mechanism, public, &signature)?;
265+
let result = session.verify_signature_update(&data[..10]);
266+
assert!(result.is_err());
267+
assert!(matches!(
268+
result.unwrap_err(),
269+
Error::Pkcs11(
270+
RvError::OperationNotInitialized,
271+
Function::VerifySignatureUpdate
272+
)
273+
));
274+
275+
// should work with one-shot new API
276+
session.verify_signature_init(&mechanism, public, &signature)?;
277+
session.verify_signature(&data)?;
278+
279+
// delete keys
280+
session.destroy_object(public)?;
281+
session.destroy_object(private)?;
282+
283+
Ok(())
284+
}
285+
286+
#[test]
287+
#[serial]
288+
fn slh_dsa_hashes() -> TestResult {
289+
let (pkcs11, slot) = init_pins();
290+
// PKCS#11 3.2 API is not supported by this token. Skip
291+
if !pkcs11.is_fn_supported(Function::VerifySignature) {
292+
/* return Ignore(); */
293+
print!("SKIP: The PKCS#11 module does not support VerifySignature API");
294+
return Ok(());
295+
}
296+
297+
// open a session
298+
let session = pkcs11.open_rw_session(slot)?;
299+
300+
// log in the session
301+
session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?;
302+
303+
let mechanism = Mechanism::SlhDsaKeyPairGen;
304+
305+
// pub key template
306+
let pub_key_template = vec![
307+
Attribute::Token(true),
308+
Attribute::ParameterSet(SlhDsaParameterSetType::SHA2_128F.into()),
309+
Attribute::Verify(true),
310+
];
311+
312+
// priv key template
313+
let priv_key_template = vec![Attribute::Token(true), Attribute::Sign(true)];
314+
315+
// generate a key pair
316+
let (public, private) =
317+
session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?;
318+
319+
// without optional context
320+
let mechanism =
321+
Mechanism::HashSlhDsaSha3_224(SignAdditionalContext::new(HedgeType::Required, None));
322+
323+
let data = [
324+
0xD0, 0xF6, 0x99, 0x53, 0x11, 0x8C, 0x09, 0xD1, 0x34, 0xDF, 0xA2, 0x0F, 0x1C, 0xC6, 0x4A,
325+
0x1E, 0x5A, 0x78, 0xAD, 0x64, 0xDF, 0x22, 0x9A, 0xA2, 0x2F, 0xD7, 0x94, 0xEC, 0x0E, 0x82,
326+
];
327+
328+
// first try multipart
329+
session.sign_init(&mechanism, private)?;
330+
for part in data.chunks(10) {
331+
session.sign_update(part)?;
332+
}
333+
let signature = session.sign_final()?;
334+
335+
// this should do with one-shot
336+
let signature2 = session.sign(&mechanism, private, &data)?;
337+
338+
// first try multipart
339+
session.verify_init(&mechanism, public)?;
340+
for part in data.chunks(10) {
341+
session.verify_update(part)?;
342+
}
343+
session.verify_final(&signature)?;
344+
345+
// this should do with one-shot
346+
session.verify(&mechanism, public, &data, &signature)?;
347+
348+
// first try multipart
349+
session.verify_signature_init(&mechanism, public, &signature2)?;
350+
for part in data.chunks(10) {
351+
session.verify_signature_update(part)?;
352+
}
353+
session.verify_signature_final()?;
354+
355+
// should work with one-shot new API
356+
session.verify_signature_init(&mechanism, public, &signature2)?;
357+
session.verify_signature(&data)?;
358+
359+
// delete keys
360+
session.destroy_object(public)?;
361+
session.destroy_object(private)?;
362+
363+
Ok(())
364+
}

0 commit comments

Comments
 (0)