use crate::tests::*;
use serial_test::parallel;
struct TestCase {
value: Vec<u8>,
result: Vec<u8>,
}
fn get_test_case_data(name: &str) -> TestCase {
match name {
"CKM_RSA_PKCS" => {
TestCase {
value: hex::decode(
"6504921a97cd57aa8f3863dc32e1f2d0b57aff63106e59f6afc3f9726b459388\
bae16b3e224f6aa7f4f471f13606eda6e1f1ac2b4df9ef8de921c07c2f4c8598\
d7a3d6ec4b368cb85ce61a74338221118a303e821c0f277b591af6795f50c402\
26127a2efacce4662fd7076c109eb59b18005e7165f6294a6976436ee397774e"
)
.expect("failed to decode value"),
result: hex::decode(
"335ffadc0b1b8bd2b1eb670dd246e76dcccdc955a1687a15f74aa3e1596ebd43\
e607c640525f89dda95809cfd065f1be4e4a249477d24f400d4d4c9438a0af95\
b26b28b416e42aa950e2a52851b52132048f1b1ce944322fc99c1aabb49b7fae\
4c2f0fef674b50adee3bbb5c6c33822b608e4b9577275ca20c710af9fc41b1c0\
1d9c0ff6f0d8324dc08e1a76e232d8feaa06c73bbf64053bea35f1c528b27227\
64822ef1ff06246e75a9a22a10da4ea84fc2441bea24b35506f8447fcf69093c\
5d21ab0305cce2c7ea9ffac357c664b491fc55f2919ec490c38accbab378c252\
ac2df3845acff575ec7524cd2f586cca1497c74f24b299d6d6254c8cdb1d227d"
)
.expect("failed to decode result"),
}
},
"CKM_ECDSA_SHA512" => {
TestCase {
value: hex::decode(
"9ecd500c60e701404922e58ab20cc002651fdee7cbc9336adda33e4c1088fab1\
964ecb7904dc6856865d6c8e15041ccf2d5ac302e99d346ff2f686531d255216\
78d4fd3f76bbf2c893d246cb4d7693792fe18172108146853103a51f824acc62\
1cb7311d2463c3361ea707254f2b052bc22cb8012873dcbb95bf1a5cc53ab89f"
)
.expect("failed to decode value"),
result: hex::decode(
"004de826ea704ad10bc0f7538af8a3843f284f55c8b946af9235af5af74f2b76\
e099e4bc72fd79d28a380f8d4b4c919ac290d248c37983ba05aea42e2dd79fdd\
33e80087488c859a96fea266ea13bf6d114c429b163be97a57559086edb64aed\
4a18594b46fb9efc7fd25d8b2de8f09ca0587f54bd287299f47b2ff124aac566\
e8ee3b43"
)
.expect("failed to decode result"),
}
},
#[cfg(not(feature = "no_sha1"))]
"CKM_SHA_1_HMAC" => {
TestCase {
value: hex::decode("48656c6c6f205348412d3120484d4143")
.expect("failed to decode value"),
result: hex::decode("f7ac5f5288543bd9b92c73c9dce1dd1ed565761d")
.expect("failed to decode result"),
}
},
"CKM_SHA256_HMAC" => {
TestCase {
value: hex::decode("48656c6c6f2053484132353620484d4143")
.expect("failed to decode value"),
result:hex::decode(
"22efc054a9ff430ab7837a06b61027a0b736b62a5c1ffe4b7615520853c9efeb"
)
.expect("failed to decode result"),
}
},
"CKM_SHA384_HMAC" => {
TestCase {
value: hex::decode("48656c6c6f2053484133383420484d4143")
.expect("failed to decode value"),
result:hex::decode(
"458b092405af19a3a38f5fd9213956a38024db45f1d14b317349b6e80b4de72a\
7cbc79a0aaf3d2c0dc23e25f344b683c"
)
.expect("failed to decode result"),
}
},
"CKM_SHA512_HMAC" => {
TestCase {
value: hex::decode("48656c6c6f2053484135313220484d4143")
.expect("failed to decode value"),
result:hex::decode(
"605956482181d6c991e65c3f50b82a007c724292b0c0a4a6aa6fe0605cb3e658\
367609984878d0d1c5b07add13942a262df380a26e57f88bff03702f769f6d86"
)
.expect("failed to decode result"),
}
},
"CKM_SHA3_256_HMAC" => {
TestCase {
value: hex::decode(
"53616d706c65206d65737361676520666f72206b65796c656e3c626c6f636b6c\
656e"
)
.expect("failed to decode value"),
result:hex::decode(
"4fe8e202c4f058e8dddc23d8c34e467343e23555e24fc2f025d598f558f67205"
)
.expect("failed to decode result"),
}
},
_ => panic!("Unknown test case {}", name),
}
}
#[cfg(feature = "rsa")]
#[test]
#[parallel]
fn test_rsa_signatures() {
let mut testtokn = TestToken::initialized(
"test_rsa_signatures",
Some("testdata/test_sign_verify_rsa.json"),
);
let session = testtokn.get_session(false);
testtokn.login();
let mut testcase = get_test_case_data("CKM_RSA_PKCS");
#[allow(unused_variables)]
let pri_key_handle =
match get_test_key_handle(session, "SigGen15_186-2", CKO_PRIVATE_KEY) {
Ok(k) => k,
Err(e) => panic!("{}", e),
};
let pub_key_handle =
match get_test_key_handle(session, "SigGen15_186-2", CKO_PUBLIC_KEY) {
Ok(k) => k,
Err(e) => panic!("{}", e),
};
let mut mechanism: CK_MECHANISM = CK_MECHANISM {
mechanism: CKM_SHA256_RSA_PKCS,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
};
let ret = sig_verify(
session,
pub_key_handle,
&mut testcase.value,
&mut testcase.result,
&mut mechanism,
);
assert_eq!(ret, CKR_OK);
let result = match sig_gen(
session,
pri_key_handle,
&mut testcase.value,
&mut mechanism,
) {
Ok(r) => r,
Err(e) => panic!("f{e}"),
};
assert_eq!(testcase.result, result);
let result = match sig_gen_multipart(
session,
pri_key_handle,
&mut testcase.value,
&mut mechanism,
) {
Ok(r) => r,
Err(e) => panic!("f{e}"),
};
assert_eq!(testcase.result, result);
testtokn.finalize();
}
#[cfg(feature = "ecdsa")]
#[test]
#[parallel]
fn test_ecc_signatures() {
let mut testtokn = TestToken::initialized(
"test_ecc_signatures",
Some("testdata/test_sign_verify_ecdsa.json"),
);
let session = testtokn.get_session(false);
testtokn.login();
let mut testcase = get_test_case_data("CKM_ECDSA_SHA512");
let pri_key_handle = match get_test_key_handle(
session,
"FIPS_186-3/SigGen: [P-521,SHA-512]",
CKO_PRIVATE_KEY,
) {
Ok(k) => k,
Err(e) => panic!("{}", e),
};
let pub_key_handle = match get_test_key_handle(
session,
"FIPS_186-3/SigGen: [P-521,SHA-512]",
CKO_PUBLIC_KEY,
) {
Ok(k) => k,
Err(e) => panic!("{}", e),
};
let mut mechanism: CK_MECHANISM = CK_MECHANISM {
mechanism: CKM_ECDSA_SHA512,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
};
let ret = sig_verify(
session,
pub_key_handle,
&mut testcase.value,
&mut testcase.result,
&mut mechanism,
);
assert_eq!(ret, CKR_OK);
let mut result = match sig_gen(
session,
pri_key_handle,
&mut testcase.value,
&mut mechanism,
) {
Ok(r) => r,
Err(e) => panic!("f{e}"),
};
let ret = sig_verify(
session,
pub_key_handle,
&mut testcase.value,
&mut result,
&mut mechanism,
);
assert_eq!(ret, CKR_OK);
testtokn.finalize();
}
#[cfg(feature = "hmac")]
#[test]
#[parallel]
fn test_hmac_signatures() {
let mut testtokn = TestToken::initialized(
"test_hmac_signatures",
Some("testdata/test_sign_verify.json"),
);
let session = testtokn.get_session(false);
testtokn.login();
let key_handle =
match get_test_key_handle(session, "HMAC Test Key", CKO_SECRET_KEY) {
Ok(k) => k,
Err(e) => panic!("{}", e),
};
#[cfg(not(feature = "no_sha1"))]
{
let mut testcase = get_test_case_data("CKM_SHA_1_HMAC");
let mut mechanism: CK_MECHANISM = CK_MECHANISM {
mechanism: CKM_SHA_1_HMAC,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
};
let ret = sig_verify(
session,
key_handle,
&mut testcase.value,
&mut testcase.result,
&mut mechanism,
);
assert_eq!(ret, CKR_OK);
assert_eq!(check_validation(session, 0), true);
let result = match sig_gen(
session,
key_handle,
&mut testcase.value,
&mut mechanism,
) {
Ok(r) => r,
Err(e) => panic!("f{e}"),
};
assert_eq!(testcase.result, result);
assert_eq!(check_validation(session, 0), true);
}
let mut testcase = get_test_case_data("CKM_SHA256_HMAC");
let mut mechanism: CK_MECHANISM = CK_MECHANISM {
mechanism: CKM_SHA256_HMAC,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
};
let ret = sig_verify(
session,
key_handle,
&mut testcase.value,
&mut testcase.result,
&mut mechanism,
);
assert_eq!(ret, CKR_OK);
assert_eq!(check_validation(session, 0), true);
let result =
match sig_gen(session, key_handle, &mut testcase.value, &mut mechanism)
{
Ok(r) => r,
Err(e) => panic!("f{e}"),
};
assert_eq!(testcase.result, result);
assert_eq!(check_validation(session, 0), true);
let mut testcase = get_test_case_data("CKM_SHA384_HMAC");
let mut mechanism: CK_MECHANISM = CK_MECHANISM {
mechanism: CKM_SHA384_HMAC,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
};
let ret = sig_verify(
session,
key_handle,
&mut testcase.value,
&mut testcase.result,
&mut mechanism,
);
assert_eq!(ret, CKR_OK);
assert_eq!(check_validation(session, 0), true);
let result =
match sig_gen(session, key_handle, &mut testcase.value, &mut mechanism)
{
Ok(r) => r,
Err(e) => panic!("f{e}"),
};
assert_eq!(testcase.result, result);
assert_eq!(check_validation(session, 0), true);
let mut testcase = get_test_case_data("CKM_SHA512_HMAC");
let mut mechanism: CK_MECHANISM = CK_MECHANISM {
mechanism: CKM_SHA512_HMAC,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
};
let ret = sig_verify(
session,
key_handle,
&mut testcase.value,
&mut testcase.result,
&mut mechanism,
);
assert_eq!(ret, CKR_OK);
assert_eq!(check_validation(session, 0), true);
let result =
match sig_gen(session, key_handle, &mut testcase.value, &mut mechanism)
{
Ok(r) => r,
Err(e) => panic!("f{e}"),
};
assert_eq!(testcase.result, result);
assert_eq!(check_validation(session, 0), true);
let key_handle = match get_test_key_handle(
session,
"HMAC SHA-3-256 Test Key",
CKO_SECRET_KEY,
) {
Ok(k) => k,
Err(e) => panic!("{}", e),
};
let mut testcase = get_test_case_data("CKM_SHA3_256_HMAC");
let mut mechanism: CK_MECHANISM = CK_MECHANISM {
mechanism: CKM_SHA3_256_HMAC,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
};
let ret = sig_verify(
session,
key_handle,
&mut testcase.value,
&mut testcase.result,
&mut mechanism,
);
assert_eq!(ret, CKR_OK);
assert_eq!(check_validation(session, 0), true);
let ret = sig_verifysig(
session,
key_handle,
&mut testcase.value,
&mut testcase.result,
&mut mechanism,
);
assert_eq!(ret, CKR_OK);
assert_eq!(check_validation(session, 0), true);
let result =
match sig_gen(session, key_handle, &mut testcase.value, &mut mechanism)
{
Ok(r) => r,
Err(e) => panic!("f{e}"),
};
assert_eq!(testcase.result, result);
assert_eq!(check_validation(session, 0), true);
let fips_hmac_key = ret_or_panic!(generate_key(
session,
CKM_GENERIC_SECRET_KEY_GEN,
std::ptr::null_mut(),
0,
&[(CKA_KEY_TYPE, CKK_GENERIC_SECRET), (CKA_VALUE_LEN, 32)],
&[],
&[(CKA_SIGN, true), (CKA_VERIFY, true)],
));
{
let mut data = b"Truncation test data".to_vec();
let size_16: CK_ULONG = 16;
let mut mech_gen_16 = CK_MECHANISM {
mechanism: CKM_SHA256_HMAC_GENERAL,
pParameter: void_ptr!(&size_16),
ulParameterLen: CK_ULONG_SIZE as CK_ULONG,
};
let sig_16 = match sig_gen(
session,
fips_hmac_key,
&mut data,
&mut mech_gen_16,
) {
Ok(r) => r,
Err(e) => panic!("sig_gen failed: {e}"),
};
assert_eq!(sig_16.len(), 16);
assert_eq!(
sig_verify(
session,
fips_hmac_key,
&mut data,
sig_16.as_slice(),
&mut mech_gen_16
),
CKR_OK
);
assert_eq!(check_validation(session, 1), true);
let size_4: CK_ULONG = 4;
let mut mech_gen_4 = CK_MECHANISM {
mechanism: CKM_SHA256_HMAC_GENERAL,
pParameter: void_ptr!(&size_4),
ulParameterLen: CK_ULONG_SIZE as CK_ULONG,
};
let sig_4 =
match sig_gen(session, fips_hmac_key, &mut data, &mut mech_gen_4) {
Ok(r) => r,
Err(e) => panic!("sig_gen failed: {e}"),
};
assert_eq!(sig_4.len(), 4);
assert_eq!(
sig_verify(
session,
fips_hmac_key,
&mut data,
sig_4.as_slice(),
&mut mech_gen_4
),
CKR_OK
);
assert_eq!(check_validation(session, 0), true);
let mut mech_full = CK_MECHANISM {
mechanism: CKM_SHA256_HMAC,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
};
let sig_full = ret_or_panic!(sig_gen(
session,
fips_hmac_key,
&mut data,
&mut mech_full
));
assert_eq!(sig_full.len(), 32);
assert_eq!(
sig_verify(
session,
fips_hmac_key,
&mut data,
sig_full.as_slice(),
&mut mech_full
),
CKR_OK
);
assert_eq!(check_validation(session, 1), true);
}
mechanism.mechanism = CKM_SHA256_HMAC;
let result =
sig_gen(session, key_handle, &mut testcase.value, &mut mechanism);
assert!(result.is_err());
testtokn.finalize();
}
#[cfg(feature = "hmac")]
#[test]
#[parallel]
fn test_hmac_save_restore() {
let mut testtokn = TestToken::initialized(
"test_hmac_save_restore",
Some("testdata/test_sign_verify.json"),
);
let session = testtokn.get_session(false);
testtokn.login();
let mut data1 = b"some initial data for hmac".to_vec();
let mut data2 = b"and some more data for hmac".to_vec();
let mechs = vec![
("SHA256-HMAC", CKM_SHA256_HMAC, "HMAC Test Key"),
("SHA384-HMAC", CKM_SHA384_HMAC, "HMAC Test Key"),
("SHA512-HMAC", CKM_SHA512_HMAC, "HMAC Test Key"),
(
"SHA3-256-HMAC",
CKM_SHA3_256_HMAC,
"HMAC SHA-3-256 Test Key",
),
];
for (mech_name, mech_type, key_name) in mechs {
let key_handle =
match get_test_key_handle(session, key_name, CKO_SECRET_KEY) {
Ok(k) => k,
Err(e) => panic!("{}", e),
};
let mut mechanism = CK_MECHANISM {
mechanism: mech_type,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
};
let mut ret = fn_sign_init(session, &mut mechanism, key_handle);
assert_eq!(ret, CKR_OK, "C_SignInit failed for {}", mech_name);
ret = fn_sign_update(
session,
data1.as_mut_ptr(),
data1.len() as CK_ULONG,
);
assert_eq!(ret, CKR_OK, "C_SignUpdate(1) failed for {}", mech_name);
let mut state_len: CK_ULONG = 0;
ret = fn_get_operation_state(
session,
std::ptr::null_mut(),
&mut state_len,
);
#[cfg(not(feature = "ossl400"))]
if ret == CKR_STATE_UNSAVEABLE {
println!(
"Mechanism {} does not support save/restore, skipping",
mech_name
);
_ = fn_sign_init(session, std::ptr::null_mut(), CK_INVALID_HANDLE);
continue;
}
assert_eq!(
ret, CKR_OK,
"C_GetOperationState(len) failed for {} with 0x{:08x}",
mech_name, ret
);
let mut state = vec![0u8; state_len as usize];
ret =
fn_get_operation_state(session, state.as_mut_ptr(), &mut state_len);
assert_eq!(
ret, CKR_OK,
"C_GetOperationState(save) failed for {} with 0x{:08x}",
mech_name, ret
);
state.resize(state_len as usize, 0);
ret = fn_sign_update(
session,
data2.as_mut_ptr(),
data2.len() as CK_ULONG,
);
assert_eq!(ret, CKR_OK, "C_SignUpdate(2) failed for {}", mech_name);
let mut sig1_len: CK_ULONG = 0;
ret = fn_sign_final(session, std::ptr::null_mut(), &mut sig1_len);
assert_eq!(ret, CKR_OK, "C_SignFinal(len) failed for {}", mech_name);
let mut signature1 = vec![0u8; sig1_len as usize];
ret = fn_sign_final(session, signature1.as_mut_ptr(), &mut sig1_len);
assert_eq!(ret, CKR_OK, "C_SignFinal(get) failed for {}", mech_name);
signature1.resize(sig1_len as usize, 0);
ret = fn_set_operation_state(
session,
state.as_mut_ptr(),
state.len() as CK_ULONG,
CK_INVALID_HANDLE, key_handle, );
assert_eq!(
ret, CKR_OK,
"C_SetOperationState failed for {} with 0x{:08x}",
mech_name, ret
);
ret = fn_sign_update(
session,
data2.as_mut_ptr(),
data2.len() as CK_ULONG,
);
assert_eq!(ret, CKR_OK, "C_SignUpdate(3) failed for {}", mech_name);
let mut sig2_len: CK_ULONG = 0;
ret = fn_sign_final(session, std::ptr::null_mut(), &mut sig2_len);
assert_eq!(ret, CKR_OK, "C_SignFinal(len2) failed for {}", mech_name);
let mut signature2 = vec![0u8; sig2_len as usize];
ret = fn_sign_final(session, signature2.as_mut_ptr(), &mut sig2_len);
assert_eq!(ret, CKR_OK, "C_SignFinal(get2) failed for {}", mech_name);
signature2.resize(sig2_len as usize, 0);
assert_eq!(
signature1, signature2,
"Signatures do not match for {}",
mech_name
);
}
testtokn.finalize();
}
#[test]
#[parallel]
fn test_sign_buffer_too_small_reports_required_len() {
let mut testtokn = TestToken::initialized(
"test_sign_buffer_too_small_reports_required_len",
None,
);
let session = testtokn.get_session(true);
testtokn.login();
let (_hpub, hpri) = ret_or_panic!(generate_key_pair(
session,
CKM_RSA_PKCS_KEY_PAIR_GEN,
&[(CKA_MODULUS_BITS, 2048)],
&[],
&[(CKA_TOKEN, false), (CKA_VERIFY, true),],
&[(CKA_CLASS, CKO_PRIVATE_KEY), (CKA_KEY_TYPE, CKK_RSA),],
&[],
&[(CKA_TOKEN, false), (CKA_SENSITIVE, true), (CKA_SIGN, true),],
));
let mut mechanism: CK_MECHANISM = CK_MECHANISM {
mechanism: CKM_SHA256_RSA_PKCS,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
};
let ret = fn_sign_init(session, &mut mechanism, hpri);
assert_eq!(ret, CKR_OK);
let data = "data to sign";
let mut sig: [u8; 4] = [0; 4];
let mut sig_len: CK_ULONG = sig.len() as CK_ULONG;
let ret = fn_sign(
session,
data.as_ptr() as *mut u8,
data.len() as CK_ULONG,
sig.as_mut_ptr(),
&mut sig_len,
);
assert_eq!(ret, CKR_BUFFER_TOO_SMALL);
assert_eq!(
sig_len, 256,
"CKR_BUFFER_TOO_SMALL must report the real required length (256 \
for a 2048-bit RSA signature), not leave *pulSignatureLen at \
whatever the caller originally passed in (4)"
);
let mut sig2 = vec![0u8; sig_len as usize];
let mut sig2_len = sig2.len() as CK_ULONG;
let ret = fn_sign(
session,
data.as_ptr() as *mut u8,
data.len() as CK_ULONG,
sig2.as_mut_ptr(),
&mut sig2_len,
);
assert_eq!(ret, CKR_OK);
assert_eq!(sig2_len, 256);
testtokn.finalize();
}
#[test]
#[parallel]
fn test_sign_final_buffer_too_small_reports_required_len() {
let mut testtokn = TestToken::initialized(
"test_sign_final_buffer_too_small_reports_required_len",
None,
);
let session = testtokn.get_session(true);
testtokn.login();
let (_hpub, hpri) = ret_or_panic!(generate_key_pair(
session,
CKM_RSA_PKCS_KEY_PAIR_GEN,
&[(CKA_MODULUS_BITS, 2048)],
&[],
&[(CKA_TOKEN, false), (CKA_VERIFY, true),],
&[(CKA_CLASS, CKO_PRIVATE_KEY), (CKA_KEY_TYPE, CKK_RSA),],
&[],
&[(CKA_TOKEN, false), (CKA_SENSITIVE, true), (CKA_SIGN, true),],
));
let mut mechanism: CK_MECHANISM = CK_MECHANISM {
mechanism: CKM_SHA256_RSA_PKCS,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
};
let ret = fn_sign_init(session, &mut mechanism, hpri);
assert_eq!(ret, CKR_OK);
let data = "data to sign";
let ret = fn_sign_update(
session,
data.as_ptr() as *mut u8,
data.len() as CK_ULONG,
);
assert_eq!(ret, CKR_OK);
let mut sig: [u8; 4] = [0; 4];
let mut sig_len: CK_ULONG = sig.len() as CK_ULONG;
let ret = fn_sign_final(session, sig.as_mut_ptr(), &mut sig_len);
assert_eq!(ret, CKR_BUFFER_TOO_SMALL);
assert_eq!(
sig_len, 256,
"CKR_BUFFER_TOO_SMALL must report the real required length (256 \
for a 2048-bit RSA signature), not leave *pulSignatureLen at \
whatever the caller originally passed in (4)"
);
let mut sig2 = vec![0u8; sig_len as usize];
let mut sig2_len = sig2.len() as CK_ULONG;
let ret = fn_sign_final(session, sig2.as_mut_ptr(), &mut sig2_len);
assert_eq!(ret, CKR_OK);
assert_eq!(sig2_len, 256);
testtokn.finalize();
}