Skip to content

Commit bf2bd20

Browse files
committed
tests: SLH-DSA test vectors
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
1 parent 6941799 commit bf2bd20

File tree

2 files changed

+7463
-0
lines changed

2 files changed

+7463
-0
lines changed

src/tests/slhdsa.rs

Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// See LICENSE.txt file for terms
33

44
use crate::tests::*;
5+
use serde_json::{from_reader, Value};
56

67
use serial_test::parallel;
78

@@ -3997,3 +3998,352 @@ fn test_slhdsa_operations() {
39973998
));
39983999
assert_eq!(out, signature);
39994000
}
4001+
4002+
fn run_test(
4003+
session: CK_SESSION_HANDLE,
4004+
test: &Value,
4005+
ckp: CK_SLH_DSA_PARAMETER_SET_TYPE,
4006+
pre_hash: bool,
4007+
) {
4008+
let tnum = match test["tcId"].as_u64() {
4009+
Some(n) => n,
4010+
None => panic!("No tcId value"),
4011+
};
4012+
4013+
let pk = if let Some(pk_str) = test["pk"].as_str() {
4014+
hex::decode(pk_str).expect("failed to decode SLH-DSA public key")
4015+
} else {
4016+
panic!("no pk value");
4017+
};
4018+
let sk = if let Some(sk_str) = test["sk"].as_str() {
4019+
hex::decode(sk_str).expect("failed to decode SLH-DSA private key")
4020+
} else {
4021+
panic!("no sk value");
4022+
};
4023+
let message = if let Some(message_str) = test["message"].as_str() {
4024+
hex::decode(message_str).expect("failed to decode message")
4025+
} else {
4026+
panic!("no message value");
4027+
};
4028+
let signature = if let Some(signature_str) = test["signature"].as_str() {
4029+
hex::decode(signature_str).expect("failed to decode signature value")
4030+
} else {
4031+
panic!("no signature value");
4032+
};
4033+
let context = if let Some(context_str) = test["context"].as_str() {
4034+
hex::decode(context_str).expect("failed to decode signature value")
4035+
} else {
4036+
panic!("no context value");
4037+
};
4038+
4039+
let hash_alg = match test["hashAlg"].as_str() {
4040+
Some(p) => p,
4041+
None => panic!("No hashAlg value"),
4042+
};
4043+
let (hash_mech, sign_mech) = match hash_alg {
4044+
"SHA2-224" => (CKM_SHA224, CKM_HASH_SLH_DSA_SHA224),
4045+
"SHA2-256" => (CKM_SHA256, CKM_HASH_SLH_DSA_SHA256),
4046+
"SHA2-384" => (CKM_SHA384, CKM_HASH_SLH_DSA_SHA384),
4047+
"SHA2-512" => (CKM_SHA512, CKM_HASH_SLH_DSA_SHA512),
4048+
"SHA3-224" => (CKM_SHA3_224, CKM_HASH_SLH_DSA_SHA3_224),
4049+
"SHA3-256" => (CKM_SHA3_256, CKM_HASH_SLH_DSA_SHA3_256),
4050+
"SHA3-384" => (CKM_SHA3_384, CKM_HASH_SLH_DSA_SHA3_384),
4051+
"SHA3-512" => (CKM_SHA3_512, CKM_HASH_SLH_DSA_SHA3_512),
4052+
"none" => {
4053+
if pre_hash {
4054+
println!("Prehash requested bu no hash algorithm provided, skipping!");
4055+
return;
4056+
}
4057+
(0, 0)
4058+
}
4059+
_ => {
4060+
println!("Unsupported hash algorithm {hash_alg}, skipping!");
4061+
return;
4062+
}
4063+
};
4064+
4065+
println!(
4066+
"Executing Test: {} (pre_hash={}) (hash_alg={})",
4067+
tnum, pre_hash, hash_alg
4068+
);
4069+
4070+
let priv_handle = ret_or_panic!(import_object(
4071+
session,
4072+
CKO_PRIVATE_KEY,
4073+
&[(CKA_KEY_TYPE, CKK_SLH_DSA), (CKA_PARAMETER_SET, ckp),],
4074+
&[(CKA_VALUE, &sk),],
4075+
&[(CKA_SIGN, true)],
4076+
));
4077+
4078+
let pub_handle = ret_or_panic!(import_object(
4079+
session,
4080+
CKO_PUBLIC_KEY,
4081+
&[(CKA_KEY_TYPE, CKK_SLH_DSA), (CKA_PARAMETER_SET, ckp),],
4082+
&[(CKA_VALUE, &pk)],
4083+
&[(CKA_VERIFY, true)],
4084+
));
4085+
4086+
if pre_hash {
4087+
/* Compute Hash to feed to signature/verify functions */
4088+
let mut mechanism: CK_MECHANISM = CK_MECHANISM {
4089+
mechanism: hash_mech,
4090+
pParameter: std::ptr::null_mut(),
4091+
ulParameterLen: 0,
4092+
};
4093+
let mut ret = fn_digest_init(session, &mut mechanism);
4094+
assert_eq!(ret, CKR_OK);
4095+
4096+
let mut digest_len: CK_ULONG = 0;
4097+
ret = fn_digest(
4098+
session,
4099+
byte_ptr!(message.as_ptr()),
4100+
message.len() as CK_ULONG,
4101+
std::ptr::null_mut(),
4102+
&mut digest_len,
4103+
);
4104+
assert_eq!(ret, CKR_OK);
4105+
let mut digest: Vec<u8> = vec![0; digest_len as usize];
4106+
ret = fn_digest(
4107+
session,
4108+
byte_ptr!(message.as_ptr()),
4109+
message.len() as CK_ULONG,
4110+
digest.as_mut_ptr(),
4111+
&mut digest_len,
4112+
);
4113+
assert_eq!(ret, CKR_OK);
4114+
4115+
let params = CK_HASH_SIGN_ADDITIONAL_CONTEXT {
4116+
hedgeVariant: CKH_DETERMINISTIC_REQUIRED,
4117+
pContext: byte_ptr!(context.as_ptr()),
4118+
ulContextLen: context.len() as CK_ULONG,
4119+
hash: hash_mech,
4120+
};
4121+
4122+
let mechanism: CK_MECHANISM = CK_MECHANISM {
4123+
mechanism: CKM_HASH_SLH_DSA,
4124+
pParameter: void_ptr!(&params),
4125+
ulParameterLen: sizeof!(CK_HASH_SIGN_ADDITIONAL_CONTEXT),
4126+
};
4127+
4128+
let ret = sig_verify(
4129+
session,
4130+
pub_handle,
4131+
&digest,
4132+
signature.as_slice(),
4133+
&mechanism,
4134+
);
4135+
assert_eq!(ret, CKR_OK);
4136+
4137+
let out =
4138+
ret_or_panic!(sig_gen(session, priv_handle, &digest, &mechanism));
4139+
assert_eq!(out, signature);
4140+
4141+
/* re-test but using the C_VerifySignature API */
4142+
let ret = sig_verifysig(
4143+
session,
4144+
pub_handle,
4145+
&digest,
4146+
signature.as_slice(),
4147+
&mechanism,
4148+
);
4149+
assert_eq!(ret, CKR_OK);
4150+
4151+
/* Test message digesting variant of HashSLH-DSA */
4152+
4153+
let params = CK_SIGN_ADDITIONAL_CONTEXT {
4154+
hedgeVariant: CKH_DETERMINISTIC_REQUIRED,
4155+
pContext: byte_ptr!(context.as_ptr()),
4156+
ulContextLen: context.len() as CK_ULONG,
4157+
};
4158+
4159+
let mechanism: CK_MECHANISM = CK_MECHANISM {
4160+
mechanism: sign_mech,
4161+
pParameter: void_ptr!(&params),
4162+
ulParameterLen: sizeof!(CK_SIGN_ADDITIONAL_CONTEXT),
4163+
};
4164+
4165+
let ret = fn_verify_signature_init(
4166+
session,
4167+
&mechanism as *const _ as CK_MECHANISM_PTR,
4168+
pub_handle,
4169+
byte_ptr!(signature.as_ptr()),
4170+
signature.len() as CK_ULONG,
4171+
);
4172+
assert_eq!(ret, CKR_OK);
4173+
4174+
/* ingest msg in chunks to verify update functions work correctly */
4175+
let mut cursor: usize = 0;
4176+
let mut avail: usize = message.len();
4177+
while avail > 0 {
4178+
let size = if avail > 1000 { 1000 } else { avail };
4179+
avail -= size;
4180+
4181+
let ret = fn_verify_signature_update(
4182+
session,
4183+
byte_ptr!(message[cursor..(cursor + size)].as_ptr()),
4184+
size as CK_ULONG,
4185+
);
4186+
assert_eq!(ret, CKR_OK);
4187+
4188+
cursor += size;
4189+
}
4190+
4191+
let ret = fn_verify_signature_final(session);
4192+
assert_eq!(ret, CKR_OK);
4193+
4194+
/* test signature code too */
4195+
let out = ret_or_panic!(sig_gen(
4196+
session,
4197+
priv_handle,
4198+
message.as_slice(),
4199+
&mechanism
4200+
));
4201+
assert_eq!(out, signature);
4202+
4203+
return;
4204+
}
4205+
4206+
/* non-prehash variant */
4207+
4208+
let params = CK_SIGN_ADDITIONAL_CONTEXT {
4209+
hedgeVariant: CKH_DETERMINISTIC_REQUIRED,
4210+
pContext: byte_ptr!(context.as_ptr()),
4211+
ulContextLen: context.len() as CK_ULONG,
4212+
};
4213+
4214+
let mechanism: CK_MECHANISM = CK_MECHANISM {
4215+
mechanism: CKM_SLH_DSA,
4216+
pParameter: void_ptr!(&params),
4217+
ulParameterLen: sizeof!(CK_SIGN_ADDITIONAL_CONTEXT),
4218+
};
4219+
4220+
/* Verify using the old one-shot API */
4221+
let ret = sig_verify(
4222+
session,
4223+
pub_handle,
4224+
message.as_slice(),
4225+
signature.as_slice(),
4226+
&mechanism,
4227+
);
4228+
assert_eq!(ret, CKR_OK);
4229+
4230+
/* Verify we generate the same signature */
4231+
let out = ret_or_panic!(sig_gen(
4232+
session,
4233+
priv_handle,
4234+
message.as_slice(),
4235+
&mechanism
4236+
));
4237+
assert_eq!(out, signature);
4238+
4239+
/* re-test but using the C_VerifySignature API */
4240+
let ret = sig_verifysig(
4241+
session,
4242+
pub_handle,
4243+
message.as_slice(),
4244+
signature.as_slice(),
4245+
&mechanism,
4246+
);
4247+
assert_eq!(ret, CKR_OK);
4248+
}
4249+
4250+
fn test_groups(session: CK_SESSION_HANDLE, data: Value) {
4251+
let mut mechanism: CK_MECHANISM = CK_MECHANISM {
4252+
mechanism: CKM_SLH_DSA,
4253+
pParameter: std::ptr::null_mut(),
4254+
ulParameterLen: 0,
4255+
};
4256+
4257+
let test_groups: &Vec<Value> = match data["testGroups"].as_array() {
4258+
Some(g) => g,
4259+
None => panic!("No testGroups value"),
4260+
};
4261+
for group in test_groups {
4262+
let gnum = match group["tgId"].as_u64() {
4263+
Some(n) => n,
4264+
None => panic!("No tgId value"),
4265+
};
4266+
match group["testType"].as_str() {
4267+
Some(s) => {
4268+
if s != "AFT" {
4269+
continue;
4270+
}
4271+
}
4272+
None => panic!("No testType value"),
4273+
}
4274+
let parameter_set = match group["parameterSet"].as_str() {
4275+
Some(p) => p,
4276+
None => panic!("No parameterSet value"),
4277+
};
4278+
println!("Executing Test group: {}, paramset:{}", gnum, parameter_set);
4279+
let ckp = match parameter_set {
4280+
"SLH-DSA-SHA2-128s" => CKP_SLH_DSA_SHA2_128S,
4281+
"SLH-DSA-SHAKE-128s" => CKP_SLH_DSA_SHAKE_128S,
4282+
"SLH-DSA-SHA2-128f" => CKP_SLH_DSA_SHA2_128F,
4283+
"SLH-DSA-SHAKE-128f" => CKP_SLH_DSA_SHAKE_128F,
4284+
"SLH-DSA-SHA2-192s" => CKP_SLH_DSA_SHA2_192S,
4285+
"SLH-DSA-SHAKE-192s" => CKP_SLH_DSA_SHAKE_192S,
4286+
"SLH-DSA-SHA2-192f" => CKP_SLH_DSA_SHA2_192F,
4287+
"SLH-DSA-SHAKE-192f" => CKP_SLH_DSA_SHAKE_192F,
4288+
"SLH-DSA-SHA2-256s" => CKP_SLH_DSA_SHA2_256S,
4289+
"SLH-DSA-SHAKE-256s" => CKP_SLH_DSA_SHAKE_256S,
4290+
"SLH-DSA-SHA2-256f" => CKP_SLH_DSA_SHA2_256F,
4291+
"SLH-DSA-SHAKE-256f" => CKP_SLH_DSA_SHAKE_256F,
4292+
_ => {
4293+
println!("Unknown set, skipping!");
4294+
continue;
4295+
}
4296+
};
4297+
4298+
/* only deterministic tests for now */
4299+
match group["deterministic"].as_bool() {
4300+
Some(true) => (),
4301+
Some(false) => {
4302+
println!("Skipping non-deterministic tests");
4303+
continue;
4304+
}
4305+
None => panic!("No deterministic value"),
4306+
}
4307+
4308+
/* skip "none" preHash */
4309+
let pre_hash = match group["preHash"].as_str() {
4310+
Some(p) => p,
4311+
None => panic!("No preHash value"),
4312+
};
4313+
let pre_hash = match pre_hash {
4314+
"pure" => false,
4315+
"preHash" => true,
4316+
p => {
4317+
println!("Skipping preHash tests with value {p}");
4318+
return;
4319+
}
4320+
};
4321+
4322+
let tests = match group["tests"].as_array() {
4323+
Some(t) => t,
4324+
None => panic!("No tests value"),
4325+
};
4326+
for test in tests {
4327+
run_test(session, &test, ckp, pre_hash);
4328+
}
4329+
}
4330+
}
4331+
4332+
#[test]
4333+
#[parallel]
4334+
#[cfg(feature = "slow")]
4335+
fn test_slhdsa_vector() {
4336+
let file =
4337+
std::fs::File::open("testdata/slh_dsa_test_vectors.json").unwrap();
4338+
let data = from_reader(file).unwrap();
4339+
4340+
let mut testtokn = TestToken::initialized("test_slhdsa_test_vector", None);
4341+
let session = testtokn.get_session(false);
4342+
4343+
/* login */
4344+
testtokn.login();
4345+
4346+
test_groups(session, data);
4347+
4348+
testtokn.finalize();
4349+
}

0 commit comments

Comments
 (0)