|
2 | 2 | // See LICENSE.txt file for terms |
3 | 3 |
|
4 | 4 | use crate::tests::*; |
| 5 | +use serde_json::{from_reader, Value}; |
5 | 6 |
|
6 | 7 | use serial_test::parallel; |
7 | 8 |
|
@@ -3997,3 +3998,352 @@ fn test_slhdsa_operations() { |
3997 | 3998 | )); |
3998 | 3999 | assert_eq!(out, signature); |
3999 | 4000 | } |
| 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!(¶ms), |
| 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!(¶ms), |
| 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!(¶ms), |
| 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