diff options
Diffstat (limited to 'third_party/rust/pkcs11/src/tests.rs')
-rw-r--r-- | third_party/rust/pkcs11/src/tests.rs | 1552 |
1 files changed, 1552 insertions, 0 deletions
diff --git a/third_party/rust/pkcs11/src/tests.rs b/third_party/rust/pkcs11/src/tests.rs new file mode 100644 index 0000000000..bc0da16f8c --- /dev/null +++ b/third_party/rust/pkcs11/src/tests.rs @@ -0,0 +1,1552 @@ +// Copyright 2017 Marcus Heese +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +use std::env; +use std::path::PathBuf; + +/// Tests need to be run with `RUST_TEST_THREADS=1` currently to pass. +extern crate num_traits; +extern crate hex; + +use self::num_traits::Num; +use self::hex::FromHex; + +use super::*; +use super::types::*; +use super::errors::Error; +use num_bigint::BigUint; + +fn pkcs11_module_name() -> PathBuf { + let default_path = option_env!("PKCS11_SOFTHSM2_MODULE") + .unwrap_or("/usr/local/lib/softhsm/libsofthsm2.so"); + let path = env::var_os("PKCS11_SOFTHSM2_MODULE") + .unwrap_or(default_path.into()); + let path_buf = PathBuf::from(path); + + if !path_buf.exists() { + panic!( + "Could not find SoftHSM2 at `{}`. Set the `PKCS11_SOFTHSM2_MODULE` environment variable to \ + its location.", + path_buf.display()); + } + + path_buf +} + +#[test] +#[serial] +fn test_label_from_str() { + let s30 = "Löwe 老虎 Léopar虎d虎aaa"; + let s32 = "Löwe 老虎 Léopar虎d虎aaaö"; + let s33 = "Löwe 老虎 Léopar虎d虎aaa虎"; + let s34 = "Löwe 老虎 Léopar虎d虎aaab虎"; + let l30 = label_from_str(s30); + let l32 = label_from_str(s32); + let l33 = label_from_str(s33); + let l34 = label_from_str(s34); + println!("Label l30: {:?}", l30); + println!("Label l32: {:?}", l32); + println!("Label l33: {:?}", l33); + println!("Label l34: {:?}", l34); + // now the assertions: + // - l30 must have the last 2 as byte 32 + // - l32 must not have any byte 32 at the end + // - l33 must have the last 2 as byte 32 because the trailing '虎' is three bytes + // - l34 must have hte last 1 as byte 32 + assert_ne!(l30[29], 32); + assert_eq!(l30[30], 32); + assert_eq!(l30[31], 32); + assert_ne!(l32[31], 32); + assert_ne!(l33[29], 32); + assert_eq!(l33[30], 32); + assert_eq!(l33[31], 32); + assert_ne!(l34[30], 32); + assert_eq!(l34[31], 32); +} +#[test] +#[serial] +fn ctx_new() { + let res = Ctx::new(pkcs11_module_name()); + assert!( + res.is_ok(), + "failed to create new context: {}", + res.unwrap_err() + ); +} + +#[test] +#[serial] +fn ctx_initialize() { + let mut ctx = Ctx::new(pkcs11_module_name()).unwrap(); + let res = ctx.initialize(None); + assert!( + res.is_ok(), + "failed to initialize context: {}", + res.unwrap_err() + ); + assert!(ctx.is_initialized(), "internal state is not initialized"); +} + +#[test] +#[serial] +fn ctx_new_and_initialize() { + let res = Ctx::new_and_initialize(pkcs11_module_name()); + assert!( + res.is_ok(), + "failed to create or initialize new context: {}", + res.unwrap_err() + ); +} + +#[test] +#[serial] +fn ctx_finalize() { + let mut ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let res = ctx.finalize(); + assert!( + res.is_ok(), + "failed to finalize context: {}", + res.unwrap_err() + ); +} + +#[test] +#[serial] +fn ctx_get_info() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let res = ctx.get_info(); + assert!( + res.is_ok(), + "failed to call C_GetInfo: {}", + res.unwrap_err() + ); + let info = res.unwrap(); + println!("{:?}", info); +} + +#[test] +#[serial] +fn ctx_get_function_list() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let res = ctx.get_function_list(); + assert!( + res.is_ok(), + "failed to call C_GetFunctionList: {}", + res.unwrap_err() + ); + let list = res.unwrap(); + println!("{:?}", list); +} + +#[test] +#[serial] +fn ctx_get_slot_list() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let res = ctx.get_slot_list(false); + assert!( + res.is_ok(), + "failed to call C_GetSlotList: {}", + res.unwrap_err() + ); + let slots = res.unwrap(); + println!("Slots: {:?}", slots); +} + +#[test] +#[serial] +fn ctx_get_slot_infos() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + for slot in slots[..1].into_iter() { + let slot = *slot; + let res = ctx.get_slot_info(slot); + assert!( + res.is_ok(), + "failed to call C_GetSlotInfo({}): {}", + slot, + res.unwrap_err() + ); + let info = res.unwrap(); + println!("Slot {} {:?}", slot, info); + } +} + +#[test] +#[serial] +fn ctx_get_token_infos() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + for slot in slots[..1].into_iter() { + let slot = *slot; + let res = ctx.get_token_info(slot); + assert!( + res.is_ok(), + "failed to call C_GetTokenInfo({}): {}", + slot, + res.unwrap_err() + ); + let info = res.unwrap(); + println!("Slot {} {:?}", slot, info); + } +} + +#[test] +#[serial] +fn ctx_get_mechanism_lists() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + for slot in slots[..1].into_iter() { + let slot = *slot; + let res = ctx.get_mechanism_list(slot); + assert!( + res.is_ok(), + "failed to call C_GetMechanismList({}): {}", + slot, + res.unwrap_err() + ); + let mechs = res.unwrap(); + println!("Slot {} Mechanisms: {:?}", slot, mechs); + } +} + +#[test] +#[serial] +fn ctx_get_mechanism_infos() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + for slot in slots[..1].into_iter() { + let slot = *slot; + let mechanisms = ctx.get_mechanism_list(slot).unwrap(); + for mechanism in mechanisms { + let res = ctx.get_mechanism_info(slot, mechanism); + assert!( + res.is_ok(), + "failed to call C_GetMechanismInfo({}, {}): {}", + slot, + mechanism, + res.unwrap_err() + ); + let info = res.unwrap(); + println!("Slot {} Mechanism {}: {:?}", slot, mechanism, info); + } + } +} + +#[test] +#[serial] +fn ctx_init_token() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + let pin = Some("1234"); + const LABEL: &str = "rust-unit-test"; + for slot in slots[..1].into_iter() { + let slot = *slot; + let res = ctx.init_token(slot, pin, LABEL); + assert!( + res.is_ok(), + "failed to call C_InitToken({}, {}, {}): {}", + slot, + pin.unwrap(), + LABEL, + res.unwrap_err() + ); + println!( + "Slot {} C_InitToken successful, PIN: {}", + slot, + pin.unwrap() + ); + } +} + +#[test] +#[serial] +fn ctx_init_pin() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + let pin = Some("1234"); + const LABEL: &str = "rust-unit-test"; + for slot in slots[..1].into_iter() { + let slot = *slot; + ctx.init_token(slot, pin, LABEL).unwrap(); + let sh = ctx + .open_session(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, None, None) + .unwrap(); + ctx.login(sh, CKU_SO, pin).unwrap(); + let res = ctx.init_pin(sh, pin); + assert!( + res.is_ok(), + "failed to call C_InitPIN({}, {}): {}", + sh, + pin.unwrap(), + res.unwrap_err() + ); + println!("InitPIN successful"); + } +} + +#[test] +#[serial] +fn ctx_set_pin() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + let pin = Some("1234"); + let new_pin = Some("1234"); + const LABEL: &str = "rust-unit-test"; + for slot in slots[..1].into_iter() { + let slot = *slot; + ctx.init_token(slot, pin, LABEL).unwrap(); + let sh = ctx + .open_session(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, None, None) + .unwrap(); + ctx.login(sh, CKU_SO, pin).unwrap(); + let res = ctx.set_pin(sh, pin, new_pin); + assert!( + res.is_ok(), + "failed to call C_SetPIN({}, {}, {}): {}", + sh, + pin.unwrap(), + new_pin.unwrap(), + res.unwrap_err() + ); + println!("SetPIN successful"); + } +} + +#[test] +#[serial] +fn ctx_open_session() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + let pin = Some("1234"); + const LABEL: &str = "rust-unit-test"; + for slot in slots[..1].into_iter() { + let slot = *slot; + ctx.init_token(slot, pin, LABEL).unwrap(); + let res = ctx.open_session(slot, CKF_SERIAL_SESSION, None, None); + assert!( + res.is_ok(), + "failed to call C_OpenSession({}, CKF_SERIAL_SESSION, None, None): {}", + slot, + res.unwrap_err() + ); + let sh = res.unwrap(); + println!("Opened Session on Slot {}: CK_SESSION_HANDLE {}", slot, sh); + } +} + +#[test] +#[serial] +fn ctx_close_session() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + let pin = Some("1234"); + const LABEL: &str = "rust-unit-test"; + for slot in slots[..1].into_iter() { + let slot = *slot; + ctx.init_token(slot, pin, LABEL).unwrap(); + let sh = ctx + .open_session(slot, CKF_SERIAL_SESSION, None, None) + .unwrap(); + let res = ctx.close_session(sh); + assert!( + res.is_ok(), + "failed to call C_CloseSession({}): {}", + sh, + res.unwrap_err() + ); + println!("Closed Session with CK_SESSION_HANDLE {}", sh); + } +} + +#[test] +#[serial] +fn ctx_close_all_sessions() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + let pin = Some("1234"); + const LABEL: &str = "rust-unit-test"; + for slot in slots[..1].into_iter() { + let slot = *slot; + ctx.init_token(slot, pin, LABEL).unwrap(); + ctx + .open_session(slot, CKF_SERIAL_SESSION, None, None) + .unwrap(); + let res = ctx.close_all_sessions(slot); + assert!( + res.is_ok(), + "failed to call C_CloseAllSessions({}): {}", + slot, + res.unwrap_err() + ); + println!("Closed All Sessions on Slot {}", slot); + } +} + +#[test] +#[serial] +fn ctx_get_session_info() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + let pin = Some("1234"); + const LABEL: &str = "rust-unit-test"; + for slot in slots[..1].into_iter() { + let slot = *slot; + ctx.init_token(slot, pin, LABEL).unwrap(); + let sh = ctx + .open_session(slot, CKF_SERIAL_SESSION, None, None) + .unwrap(); + let res = ctx.get_session_info(sh); + assert!( + res.is_ok(), + "failed to call C_GetSessionInfo({}): {}", + sh, + res.unwrap_err() + ); + let info = res.unwrap(); + println!("{:?}", info); + } +} + +#[test] +#[serial] +fn ctx_login() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + let pin = Some("1234"); + const LABEL: &str = "rust-unit-test"; + for slot in slots[..1].into_iter() { + let slot = *slot; + ctx.init_token(slot, pin, LABEL).unwrap(); + let sh = ctx + .open_session(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, None, None) + .unwrap(); + let res = ctx.login(sh, CKU_SO, pin); + assert!( + res.is_ok(), + "failed to call C_Login({}, CKU_SO, {}): {}", + sh, + pin.unwrap(), + res.unwrap_err() + ); + println!("Login successful"); + } +} + +#[test] +#[serial] +fn ctx_logout() { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + let pin = Some("1234"); + const LABEL: &str = "rust-unit-test"; + for slot in slots[..1].into_iter() { + let slot = *slot; + ctx.init_token(slot, pin, LABEL).unwrap(); + let sh = ctx + .open_session(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, None, None) + .unwrap(); + ctx.login(sh, CKU_SO, pin).unwrap(); + let res = ctx.logout(sh); + assert!( + res.is_ok(), + "failed to call C_Logout({}): {}", + sh, + res.unwrap_err() + ); + println!("Logout successful"); + } +} + +#[test] +fn attr_bool() { + let b: CK_BBOOL = CK_FALSE; + let attr = CK_ATTRIBUTE::new(CKA_OTP_USER_IDENTIFIER).with_bool(&b); + println!("{:?}", attr); + let ret: bool = attr.get_bool(); + println!("{}", ret); + assert_eq!(false, ret, "attr.get_bool() should have been false"); + + let b: CK_BBOOL = CK_TRUE; + let attr = CK_ATTRIBUTE::new(CKA_OTP_USER_IDENTIFIER).with_bool(&b); + println!("{:?}", attr); + let ret: bool = attr.get_bool(); + println!("{}", ret); + assert_eq!(true, ret, "attr.get_bool() should have been true"); +} + +#[test] +fn attr_ck_ulong() { + let val: CK_ULONG = 42; + let attr = CK_ATTRIBUTE::new(CKA_RESOLUTION).with_ck_ulong(&val); + println!("{:?}", attr); + let ret: CK_ULONG = attr.get_ck_ulong(); + println!("{}", ret); + assert_eq!(val, ret, "attr.get_ck_ulong() shouls have been {}", val); +} + +#[test] +fn attr_ck_long() { + let val: CK_LONG = -42; + let attr = CK_ATTRIBUTE::new(CKA_RESOLUTION).with_ck_long(&val); + println!("{:?}", attr); + let ret: CK_LONG = attr.get_ck_long(); + println!("{}", ret); + assert_eq!(val, ret, "attr.get_ck_long() shouls have been {}", val); +} + +#[test] +fn attr_bytes() { + let val = vec![0, 1, 2, 3, 3, 4, 5]; + let attr = CK_ATTRIBUTE::new(CKA_VALUE).with_bytes(val.as_slice()); + println!("{:?}", attr); + let ret: Vec<CK_BYTE> = attr.get_bytes(); + println!("{:?}", ret); + assert_eq!( + val, + ret.as_slice(), + "attr.get_bytes() shouls have been {:?}", + val + ); +} + +#[test] +fn attr_string() { + let val = String::from("Löwe 老虎"); + let attr = CK_ATTRIBUTE::new(CKA_LABEL).with_string(&val); + println!("{:?}", attr); + let ret = attr.get_string(); + println!("{:?}", ret); + assert_eq!(val, ret, "attr.get_string() shouls have been {}", val); +} + +#[test] +fn attr_date() { + let val: CK_DATE = Default::default(); + let attr = CK_ATTRIBUTE::new(CKA_LABEL).with_date(&val); + println!("{:?}", attr); + let ret = attr.get_date(); + println!("{:?}", ret); + assert_eq!( + val.day, + ret.day, + "attr.get_date() should have been {:?}", + val + ); + assert_eq!( + val.month, + ret.month, + "attr.get_date() should have been {:?}", + val + ); + assert_eq!( + val.year, + ret.year, + "attr.get_date() should have been {:?}", + val + ); +} + +#[test] +fn attr_biginteger() { + let num_str = "123456789012345678901234567890123456789012345678901234567890123456789012345678"; + let val = BigUint::from_str_radix(num_str, 10).unwrap(); + let slice = val.to_bytes_le(); + let attr = CK_ATTRIBUTE::new(CKA_LABEL).with_biginteger(&slice); + println!("{:?}", attr); + let ret = attr.get_biginteger(); + println!("{:?}", ret); + assert_eq!(ret, val, "attr.get_biginteger() should have been {:?}", val); + assert_eq!( + ret.to_str_radix(10), + num_str, + "attr.get_biginteger() should have been {:?}", + num_str + ); +} + +/// This will create and initialize a context, set a SO and USER PIN, and login as the USER. +/// This is the starting point for all tests that are acting on the token. +/// If you look at the tests here in a "serial" manner, if all the tests are working up until +/// here, this will always succeed. +fn fixture_token() -> Result<(Ctx, CK_SESSION_HANDLE), Error> { + let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap(); + let slots = ctx.get_slot_list(false).unwrap(); + let pin = Some("1234"); + const LABEL: &str = "rust-unit-test"; + let slot = *slots.first().ok_or(Error::Module("no slot available"))?; + ctx.init_token(slot, pin, LABEL)?; + let sh = ctx.open_session(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, None, None)?; + ctx.login(sh, CKU_SO, pin)?; + ctx.init_pin(sh, pin)?; + ctx.logout(sh)?; + ctx.login(sh, CKU_USER, pin)?; + Ok((ctx, sh)) +} + +#[test] +#[serial] +fn ctx_create_object() { + /* + CKA_CLASS ck_type object_class:CKO_DATA + CKA_TOKEN bool true + CKA_PRIVATE bool true + CKA_MODIFIABLE bool true + CKA_COPYABLE bool true + CKA_LABEL string e4-example + CKA_VALUE bytes SGVsbG8gV29ybGQh + */ + let (ctx, sh) = fixture_token().unwrap(); + + let class = CKO_DATA; + let token: CK_BBOOL = CK_TRUE; + let private: CK_BBOOL = CK_TRUE; + let modifiable: CK_BBOOL = CK_TRUE; + let copyable: CK_BBOOL = CK_TRUE; + let label = String::from("rust-unit-test"); + let value = b"Hello World!"; + + let template = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&class), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&token), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&private), + CK_ATTRIBUTE::new(CKA_MODIFIABLE).with_bool(&modifiable), + CK_ATTRIBUTE::new(CKA_COPYABLE).with_bool(©able), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&label), + CK_ATTRIBUTE::new(CKA_VALUE).with_bytes(&value[..]), + ]; + println!("Template: {:?}", template); + let res = ctx.create_object(sh, &template); + assert!( + res.is_ok(), + "failed to call C_CreateObject({}, {:?}): {}", + sh, + &template, + res.is_err() + ); + let oh = res.unwrap(); + println!("Object Handle: {}", oh); +} + +fn fixture_token_and_object() -> Result<(Ctx, CK_SESSION_HANDLE, CK_OBJECT_HANDLE), Error> { + let (ctx, sh) = fixture_token()?; + + let class = CKO_DATA; + let token: CK_BBOOL = CK_TRUE; + let private: CK_BBOOL = CK_TRUE; + let modifiable: CK_BBOOL = CK_TRUE; + let copyable: CK_BBOOL = CK_TRUE; + let label = String::from("rust-unit-test"); + let value = b"Hello World!"; + + let template = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&class), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&token), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&private), + CK_ATTRIBUTE::new(CKA_MODIFIABLE).with_bool(&modifiable), + CK_ATTRIBUTE::new(CKA_COPYABLE).with_bool(©able), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&label), + CK_ATTRIBUTE::new(CKA_VALUE).with_bytes(&value[..]), + ]; + let oh = ctx.create_object(sh, &template)?; + Ok((ctx, sh, oh)) +} + +#[test] +#[serial] +fn ctx_copy_object() { + let (ctx, sh, oh) = fixture_token_and_object().unwrap(); + + let label2 = String::from("rust-unit-test2"); + let template2 = vec![CK_ATTRIBUTE::new(CKA_LABEL).with_string(&label2)]; + println!("Template2: {:?}", template2); + + let res = ctx.copy_object(sh, oh, &template2); + assert!( + res.is_ok(), + "failed to call C_CopyObject({}, {}, {:?}): {}", + sh, + oh, + &template2, + res.unwrap_err(), + ); + let oh2 = res.unwrap(); + println!("Object Handle2: {}", oh2); +} + +#[test] +#[serial] +fn ctx_destroy_object() { + let (ctx, sh, oh) = fixture_token_and_object().unwrap(); + + let res = ctx.destroy_object(sh, oh); + assert!( + res.is_ok(), + "failed to call C_DestroyObject({}, {}): {})", + sh, + oh, + res.unwrap_err() + ); +} + +#[test] +#[serial] +fn ctx_get_object_size() { + let (ctx, sh, oh) = fixture_token_and_object().unwrap(); + + let res = ctx.get_object_size(sh, oh); + assert!( + res.is_ok(), + "failed to call C_GetObjectSize({}, {}): {}", + sh, + oh, + res.unwrap_err() + ); + let size = res.unwrap(); + println!("Object Size: {}", size); +} + +#[test] +#[serial] +fn ctx_get_attribute_value() { + { + let (ctx, sh, oh) = fixture_token_and_object().unwrap(); + + let mut template = vec![ + CK_ATTRIBUTE::new(CKA_CLASS), + CK_ATTRIBUTE::new(CKA_PRIVATE), + CK_ATTRIBUTE::new(CKA_LABEL), + CK_ATTRIBUTE::new(CKA_VALUE), + ]; + println!("Template: {:?}", template); + { + let res = ctx.get_attribute_value(sh, oh, &template); + assert!( + res.is_ok(), + "failed to call C_GetAttributeValue({}, {}, {:?}): {}", + sh, + oh, + &template, + res.unwrap_err() + ); + let (rv, _) = res.unwrap(); + println!("CK_RV: 0x{:x}, Template: {:?}", rv, &template); + } + + let class: CK_ULONG = 0; + let private: CK_BBOOL = 1; + let label: String = String::with_capacity(template[2].ulValueLen); + let value: Vec<CK_BYTE> = Vec::with_capacity(template[3].ulValueLen); + template[0].set_ck_ulong(&class); + template[1].set_bool(&private); + template[2].set_string(&label); + template[3].set_bytes(&value.as_slice()); + + let res = ctx.get_attribute_value(sh, oh, &template); + assert!( + res.is_ok(), + "failed to call C_GetAttributeValue({}, {}, {:?}): {}", + sh, + oh, + &template, + res.unwrap_err() + ); + let (rv, _) = res.unwrap(); + println!("CK_RV: 0x{:x}, Retrieved Attributes: {:?}", rv, &template); + + assert_eq!(CKO_DATA, template[0].get_ck_ulong()); + assert_eq!(true, template[1].get_bool()); + assert_eq!(String::from("rust-unit-test"), template[2].get_string()); + assert_eq!(Vec::from("Hello World!"), template[3].get_bytes()); + } + println!("The end"); +} + +#[test] +#[serial] +fn ctx_set_attribute_value() { + let (ctx, sh, oh) = fixture_token_and_object().unwrap(); + + let value = b"Hello New World!"; + let template = vec![CK_ATTRIBUTE::new(CKA_LABEL).with_bytes(&value[..])]; + + let res = ctx.set_attribute_value(sh, oh, &template); + assert!( + res.is_ok(), + "failed to call C_SetAttributeValue({}, {}, {:?}): {}", + sh, + oh, + &template, + res.unwrap_err() + ); + + let str: Vec<CK_BYTE> = Vec::from("aaaaaaaaaaaaaaaa"); + let template2 = vec![CK_ATTRIBUTE::new(CKA_LABEL).with_bytes(&str.as_slice())]; + ctx.get_attribute_value(sh, oh, &template2).unwrap(); + assert_eq!(Vec::from("Hello New World!"), template2[0].get_bytes()); +} + +#[test] +#[serial] +fn ctx_find_objects_init() { + let (ctx, sh, _) = fixture_token_and_object().unwrap(); + + let label = String::from("rust-unit-test"); + let template = vec![CK_ATTRIBUTE::new(CKA_LABEL).with_string(&label)]; + + let res = ctx.find_objects_init(sh, &template); + assert!( + res.is_ok(), + "failed to call C_FindObjectsInit({}, {:?}): {}", + sh, + &template, + res.unwrap_err() + ); +} + +#[test] +#[serial] +fn ctx_find_objects() { + let (ctx, sh, _) = fixture_token_and_object().unwrap(); + + let label = String::from("rust-unit-test"); + let template = vec![CK_ATTRIBUTE::new(CKA_LABEL).with_string(&label)]; + + ctx.find_objects_init(sh, &template).unwrap(); + + let res = ctx.find_objects(sh, 10); + assert!( + res.is_ok(), + "failed to call C_FindObjects({}, {}): {}", + sh, + 10, + res.unwrap_err() + ); + let objs = res.unwrap(); + assert_eq!(objs.len(), 1); +} + +#[test] +#[serial] +fn ctx_find_objects_final() { + let (ctx, sh, _) = fixture_token_and_object().unwrap(); + + let label = String::from("rust-unit-test"); + let template = vec![CK_ATTRIBUTE::new(CKA_LABEL).with_string(&label)]; + + ctx.find_objects_init(sh, &template).unwrap(); + ctx.find_objects(sh, 10).unwrap(); + + let res = ctx.find_objects_final(sh); + assert!( + res.is_ok(), + "failed to call C_FindObjectsFinal({}): {}", + sh, + res.unwrap_err() + ); +} + +#[test] +#[serial] +fn ctx_generate_key() { + let (ctx, sh) = fixture_token().unwrap(); + + let mechanism = CK_MECHANISM { + mechanism: CKM_AES_KEY_GEN, + pParameter: ptr::null(), + ulParameterLen: 0, + }; + + // Wrapping Key Template: + // CKA_CLASS ck_type object_class:CKO_SECRET_KEY + // CKA_KEY_TYPE ck_type key_type:CKK_AES + // CKA_TOKEN bool true + // CKA_LABEL string wrap1-wrap-key + // CKA_ENCRYPT bool false + // CKA_DECRYPT bool false + // CKA_VALUE_LEN uint 32 + // CKA_PRIVATE bool true + // CKA_SENSITIVE bool false + // CKA_EXTRACTABLE bool true + // CKA_WRAP bool true + // CKA_UNWRAP bool true + + let class = CKO_SECRET_KEY; + let keyType = CKK_AES; + let valueLen = 32; + let label = String::from("wrap1-wrap-key"); + let token: CK_BBOOL = CK_TRUE; + let private: CK_BBOOL = CK_TRUE; + let encrypt: CK_BBOOL = CK_FALSE; + let decrypt: CK_BBOOL = CK_FALSE; + let sensitive: CK_BBOOL = CK_FALSE; + let extractable: CK_BBOOL = CK_TRUE; + let wrap: CK_BBOOL = CK_TRUE; + let unwrap: CK_BBOOL = CK_TRUE; + + let template = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&class), + CK_ATTRIBUTE::new(CKA_KEY_TYPE).with_ck_ulong(&keyType), + CK_ATTRIBUTE::new(CKA_VALUE_LEN).with_ck_ulong(&valueLen), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&label), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&token), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&private), + CK_ATTRIBUTE::new(CKA_ENCRYPT).with_bool(&encrypt), + CK_ATTRIBUTE::new(CKA_DECRYPT).with_bool(&decrypt), + CK_ATTRIBUTE::new(CKA_SENSITIVE).with_bool(&sensitive), + CK_ATTRIBUTE::new(CKA_EXTRACTABLE).with_bool(&extractable), + CK_ATTRIBUTE::new(CKA_WRAP).with_bool(&wrap), + CK_ATTRIBUTE::new(CKA_UNWRAP).with_bool(&unwrap), + ]; + + let res = ctx.generate_key(sh, &mechanism, &template); + assert!( + res.is_ok(), + "failed to call C_Generatekey({}, {:?}, {:?}): {}", + sh, + mechanism, + template, + res.unwrap_err() + ); + let oh = res.unwrap(); + assert_ne!(oh, CK_INVALID_HANDLE); + println!("Generated Key Object Handle: {}", oh); +} + +#[test] +#[serial] +fn ctx_generate_key_pair() { + let (ctx, sh) = fixture_token().unwrap(); + + let mechanism = CK_MECHANISM { + mechanism: CKM_RSA_PKCS_KEY_PAIR_GEN, + pParameter: ptr::null(), + ulParameterLen: 0, + }; + + // Private Key Template + // CKA_CLASS ck_type object_class:CKO_PRIVATE_KEY + // CKA_KEY_TYPE ck_type key_type:CKK_RSA + // CKA_TOKEN bool true + // CKA_SENSITIVE bool true + // CKA_UNWRAP bool false + // CKA_EXTRACTABLE bool false + // CKA_LABEL string ca-hsm-priv + // CKA_SIGN bool true + // CKA_PRIVATE bool true + + let privClass = CKO_PRIVATE_KEY; + let privKeyType = CKK_RSA; + let privLabel = String::from("ca-hsm-priv"); + let privToken = CK_TRUE; + let privPrivate = CK_TRUE; + let privSensitive = CK_TRUE; + let privUnwrap = CK_FALSE; + let privExtractable = CK_FALSE; + let privSign = CK_TRUE; + + let privTemplate = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&privClass), + CK_ATTRIBUTE::new(CKA_KEY_TYPE).with_ck_ulong(&privKeyType), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&privLabel), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&privToken), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&privPrivate), + CK_ATTRIBUTE::new(CKA_SENSITIVE).with_bool(&privSensitive), + CK_ATTRIBUTE::new(CKA_UNWRAP).with_bool(&privUnwrap), + CK_ATTRIBUTE::new(CKA_EXTRACTABLE).with_bool(&privExtractable), + CK_ATTRIBUTE::new(CKA_SIGN).with_bool(&privSign), + ]; + + // Public Key Template + // CKA_CLASS ck_type object_class:CKO_PUBLIC_KEY + // CKA_KEY_TYPE ck_type key_type:CKK_RSA + // CKA_TOKEN bool true + // CKA_MODULUS_BITS uint 4096 + // CKA_PUBLIC_EXPONENT big_integer 65537 + // CKA_LABEL string ca-hsm-pub + // CKA_WRAP bool false + // CKA_VERIFY bool true + // CKA_PRIVATE bool true + + let pubClass = CKO_PUBLIC_KEY; + let pubKeyType = CKK_RSA; + let pubLabel = String::from("ca-hsm-pub"); + let pubToken = CK_TRUE; + let pubPrivate = CK_TRUE; + let pubWrap = CK_FALSE; + let pubVerify = CK_TRUE; + let pubModulusBits: CK_ULONG = 4096; + let pubPublicExponent = BigUint::from(65537u32); + let pubPublicExponentSlice = pubPublicExponent.to_bytes_le(); + + let pubTemplate = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&pubClass), + CK_ATTRIBUTE::new(CKA_KEY_TYPE).with_ck_ulong(&pubKeyType), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&pubLabel), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&pubToken), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&pubPrivate), + CK_ATTRIBUTE::new(CKA_WRAP).with_bool(&pubWrap), + CK_ATTRIBUTE::new(CKA_VERIFY).with_bool(&pubVerify), + CK_ATTRIBUTE::new(CKA_MODULUS_BITS).with_ck_ulong(&pubModulusBits), + CK_ATTRIBUTE::new(CKA_PUBLIC_EXPONENT).with_biginteger(&pubPublicExponentSlice), + ]; + + let res = ctx.generate_key_pair(sh, &mechanism, &pubTemplate, &privTemplate); + assert!( + res.is_ok(), + "failed to call C_GenerateKeyPair({}, {:?}, {:?}, {:?}): {}", + sh, + &mechanism, + &pubTemplate, + &privTemplate, + res.unwrap_err() + ); + let (pubOh, privOh) = res.unwrap(); + println!("Private Key Object Handle: {}", privOh); + println!("Public Key Object Handle: {}", pubOh); +} + +fn fixture_token_and_secret_keys( +) -> Result<(Ctx, CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE), Error> { + let (ctx, sh) = fixture_token()?; + + let wrapOh: CK_OBJECT_HANDLE; + let secOh: CK_OBJECT_HANDLE; + { + let mechanism = CK_MECHANISM { + mechanism: CKM_AES_KEY_GEN, + pParameter: ptr::null(), + ulParameterLen: 0, + }; + + let class = CKO_SECRET_KEY; + let keyType = CKK_AES; + let valueLen = 32; + let label = String::from("wrap1-wrap-key"); + let token: CK_BBOOL = CK_TRUE; + let private: CK_BBOOL = CK_TRUE; + let encrypt: CK_BBOOL = CK_FALSE; + let decrypt: CK_BBOOL = CK_FALSE; + let sensitive: CK_BBOOL = CK_FALSE; + let extractable: CK_BBOOL = CK_TRUE; + let wrap: CK_BBOOL = CK_TRUE; + let unwrap: CK_BBOOL = CK_TRUE; + + let template = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&class), + CK_ATTRIBUTE::new(CKA_KEY_TYPE).with_ck_ulong(&keyType), + CK_ATTRIBUTE::new(CKA_VALUE_LEN).with_ck_ulong(&valueLen), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&label), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&token), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&private), + CK_ATTRIBUTE::new(CKA_ENCRYPT).with_bool(&encrypt), + CK_ATTRIBUTE::new(CKA_DECRYPT).with_bool(&decrypt), + CK_ATTRIBUTE::new(CKA_SENSITIVE).with_bool(&sensitive), + CK_ATTRIBUTE::new(CKA_EXTRACTABLE).with_bool(&extractable), + CK_ATTRIBUTE::new(CKA_WRAP).with_bool(&wrap), + CK_ATTRIBUTE::new(CKA_UNWRAP).with_bool(&unwrap), + ]; + + wrapOh = ctx.generate_key(sh, &mechanism, &template)?; + } + + { + let mechanism = CK_MECHANISM { + mechanism: CKM_AES_KEY_GEN, + pParameter: ptr::null(), + ulParameterLen: 0, + }; + + // CKA_CLASS ck_type object_class:CKO_SECRET_KEY + // CKA_KEY_TYPE ck_type key_type:CKK_AES + // CKA_TOKEN bool true + // CKA_LABEL string secured-key + // CKA_ENCRYPT bool true + // CKA_DECRYPT bool true + // CKA_VALUE_LEN uint 32 + // CKA_PRIVATE bool true + // CKA_SENSITIVE bool true + // CKA_EXTRACTABLE bool true + // CKA_WRAP bool false + // CKA_UNWRAP bool false + + let class = CKO_SECRET_KEY; + let keyType = CKK_AES; + let valueLen = 32; + let label = String::from("secured-key"); + let token: CK_BBOOL = CK_TRUE; + let private: CK_BBOOL = CK_TRUE; + let encrypt: CK_BBOOL = CK_TRUE; + let decrypt: CK_BBOOL = CK_TRUE; + let sensitive: CK_BBOOL = CK_TRUE; + let extractable: CK_BBOOL = CK_TRUE; + let wrap: CK_BBOOL = CK_FALSE; + let unwrap: CK_BBOOL = CK_FALSE; + + let template = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&class), + CK_ATTRIBUTE::new(CKA_KEY_TYPE).with_ck_ulong(&keyType), + CK_ATTRIBUTE::new(CKA_VALUE_LEN).with_ck_ulong(&valueLen), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&label), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&token), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&private), + CK_ATTRIBUTE::new(CKA_ENCRYPT).with_bool(&encrypt), + CK_ATTRIBUTE::new(CKA_DECRYPT).with_bool(&decrypt), + CK_ATTRIBUTE::new(CKA_SENSITIVE).with_bool(&sensitive), + CK_ATTRIBUTE::new(CKA_EXTRACTABLE).with_bool(&extractable), + CK_ATTRIBUTE::new(CKA_WRAP).with_bool(&wrap), + CK_ATTRIBUTE::new(CKA_UNWRAP).with_bool(&unwrap), + ]; + + secOh = ctx.generate_key(sh, &mechanism, &template)?; + } + + Ok((ctx, sh, wrapOh, secOh)) +} + +#[allow(dead_code)] +fn fixture_key_pair( + ctx: &Ctx, + sh: CK_SESSION_HANDLE, + pubLabel: String, + privLabel: String, +) -> Result<(CK_OBJECT_HANDLE, CK_OBJECT_HANDLE), Error> { + let mechanism = CK_MECHANISM { + mechanism: CKM_RSA_PKCS_KEY_PAIR_GEN, + pParameter: ptr::null(), + ulParameterLen: 0, + }; + + let privClass = CKO_PRIVATE_KEY; + let privKeyType = CKK_RSA; + let privLabel = privLabel; + let privToken = CK_TRUE; + let privPrivate = CK_TRUE; + let privSensitive = CK_TRUE; + let privUnwrap = CK_FALSE; + let privExtractable = CK_FALSE; + let privSign = CK_TRUE; + + let privTemplate = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&privClass), + CK_ATTRIBUTE::new(CKA_KEY_TYPE).with_ck_ulong(&privKeyType), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&privLabel), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&privToken), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&privPrivate), + CK_ATTRIBUTE::new(CKA_SENSITIVE).with_bool(&privSensitive), + CK_ATTRIBUTE::new(CKA_UNWRAP).with_bool(&privUnwrap), + CK_ATTRIBUTE::new(CKA_EXTRACTABLE).with_bool(&privExtractable), + CK_ATTRIBUTE::new(CKA_SIGN).with_bool(&privSign), + ]; + + let pubClass = CKO_PUBLIC_KEY; + let pubKeyType = CKK_RSA; + let pubLabel = pubLabel; + let pubToken = CK_TRUE; + let pubPrivate = CK_TRUE; + let pubWrap = CK_FALSE; + let pubVerify = CK_TRUE; + let pubModulusBits: CK_ULONG = 4096; + let pubPublicExponent = BigUint::from(65537u32); + let pubPublicExponentSlice = pubPublicExponent.to_bytes_le(); + + let pubTemplate = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&pubClass), + CK_ATTRIBUTE::new(CKA_KEY_TYPE).with_ck_ulong(&pubKeyType), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&pubLabel), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&pubToken), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&pubPrivate), + CK_ATTRIBUTE::new(CKA_WRAP).with_bool(&pubWrap), + CK_ATTRIBUTE::new(CKA_VERIFY).with_bool(&pubVerify), + CK_ATTRIBUTE::new(CKA_MODULUS_BITS).with_ck_ulong(&pubModulusBits), + CK_ATTRIBUTE::new(CKA_PUBLIC_EXPONENT).with_biginteger(&pubPublicExponentSlice), + ]; + + let (pubOh, privOh) = ctx.generate_key_pair(sh, &mechanism, &pubTemplate, &privTemplate)?; + Ok((pubOh, privOh)) +} + +fn fixture_dh_key_pair( + ctx: &Ctx, + sh: CK_SESSION_HANDLE, + pubLabel: String, + privLabel: String, +) -> Result<(CK_OBJECT_HANDLE, CK_OBJECT_HANDLE), Error> { + let mechanism = CK_MECHANISM { + mechanism: CKM_DH_PKCS_KEY_PAIR_GEN, + pParameter: ptr::null(), + ulParameterLen: 0, + }; + //[]*pkcs11.Attribute{ + // pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), + // pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_DH), + // pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, true), + // pkcs11.NewAttribute(pkcs11.CKA_TOKEN, false), + // pkcs11.NewAttribute(pkcs11.CKA_DERIVE, true), + //}, + let privClass = CKO_PRIVATE_KEY; + let privKeyType = CKK_DH; + let privLabel = privLabel; + let privToken = CK_TRUE; + let privPrivate = CK_TRUE; + let privSensitive = CK_TRUE; + let privExtractable = CK_FALSE; + let privDerive = CK_TRUE; + + let privTemplate = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&privClass), + CK_ATTRIBUTE::new(CKA_KEY_TYPE).with_ck_ulong(&privKeyType), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&privLabel), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&privToken), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&privPrivate), + CK_ATTRIBUTE::new(CKA_SENSITIVE).with_bool(&privSensitive), + CK_ATTRIBUTE::new(CKA_EXTRACTABLE).with_bool(&privExtractable), + CK_ATTRIBUTE::new(CKA_DERIVE).with_bool(&privDerive), + ]; + + /* + []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY), + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_DH), + pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, true), + pkcs11.NewAttribute(pkcs11.CKA_TOKEN, false), + pkcs11.NewAttribute(pkcs11.CKA_DERIVE, true), + pkcs11.NewAttribute(pkcs11.CKA_BASE, domainParamBase.Bytes()), + pkcs11.NewAttribute(pkcs11.CKA_PRIME, domainParamPrime.Bytes()), + }, + */ + + let pubClass = CKO_PUBLIC_KEY; + let pubKeyType = CKK_DH; + let pubLabel = pubLabel; + let pubToken = CK_TRUE; + let pubPrivate = CK_TRUE; + let pubDerive = CK_TRUE; + // 2048-bit MODP Group + let prime: Vec<u8> = Vec::from_hex( + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", + ).unwrap(); + // 1536-bit MODP Group + //let base: Vec<u8> = Vec::from_hex( + // "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF" + //).unwrap(); + let base: Vec<u8> = Vec::from_hex("02").unwrap(); + + let pubTemplate = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&pubClass), + CK_ATTRIBUTE::new(CKA_KEY_TYPE).with_ck_ulong(&pubKeyType), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&pubLabel), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&pubToken), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&pubPrivate), + CK_ATTRIBUTE::new(CKA_DERIVE).with_bool(&pubDerive), + CK_ATTRIBUTE::new(CKA_BASE).with_bytes(&base.as_slice()), + CK_ATTRIBUTE::new(CKA_PRIME).with_bytes(&prime.as_slice()), + ]; + + let (pubOh, privOh) = ctx.generate_key_pair(sh, &mechanism, &pubTemplate, &privTemplate)?; + Ok((pubOh, privOh)) +} + +#[test] +#[serial] +fn ctx_wrap_key() { + let (ctx, sh, wrapOh, secOh) = fixture_token_and_secret_keys().unwrap(); + + // using the default IV + let mechanism = CK_MECHANISM { + mechanism: CKM_AES_KEY_WRAP_PAD, + pParameter: ptr::null(), + ulParameterLen: 0, + }; + + let res = ctx.wrap_key(sh, &mechanism, wrapOh, secOh); + assert!( + res.is_ok(), + "failed to call C_WrapKey({}, {:?}, {}, {}) without parameter: {}", + sh, + &mechanism, + wrapOh, + secOh, + res.unwrap_err() + ); + let wrappedKey = res.unwrap(); + println!( + "Wrapped Key Bytes (Total of {} bytes): {:?}", + wrappedKey.len(), + wrappedKey + ); +} + +#[test] +#[serial] +fn ctx_unwrap_key() { + let (ctx, sh, wrapOh, secOh) = fixture_token_and_secret_keys().unwrap(); + + // using the default IV + let mechanism = CK_MECHANISM { + mechanism: CKM_AES_KEY_WRAP_PAD, + pParameter: ptr::null(), + ulParameterLen: 0, + }; + + let wrappedKey = ctx.wrap_key(sh, &mechanism, wrapOh, secOh).unwrap(); + + let class = CKO_SECRET_KEY; + let keyType = CKK_AES; + let label = String::from("secured-key-unwrapped"); + let token: CK_BBOOL = CK_TRUE; + let private: CK_BBOOL = CK_TRUE; + let encrypt: CK_BBOOL = CK_TRUE; + let decrypt: CK_BBOOL = CK_TRUE; + let sensitive: CK_BBOOL = CK_TRUE; + let extractable: CK_BBOOL = CK_TRUE; + let wrap: CK_BBOOL = CK_FALSE; + let unwrap: CK_BBOOL = CK_FALSE; + + let template = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&class), + CK_ATTRIBUTE::new(CKA_KEY_TYPE).with_ck_ulong(&keyType), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&label), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&token), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&private), + CK_ATTRIBUTE::new(CKA_ENCRYPT).with_bool(&encrypt), + CK_ATTRIBUTE::new(CKA_DECRYPT).with_bool(&decrypt), + CK_ATTRIBUTE::new(CKA_SENSITIVE).with_bool(&sensitive), + CK_ATTRIBUTE::new(CKA_EXTRACTABLE).with_bool(&extractable), + CK_ATTRIBUTE::new(CKA_WRAP).with_bool(&wrap), + CK_ATTRIBUTE::new(CKA_UNWRAP).with_bool(&unwrap), + ]; + + let res = ctx.unwrap_key(sh, &mechanism, wrapOh, &wrappedKey, &template); + assert!( + res.is_ok(), + "failed to call C_UnwrapKey({}, {:?}, {}, {:?}, {:?}): {}", + sh, + &mechanism, + wrapOh, + &wrappedKey, + &template, + res.unwrap_err() + ); + let oh = res.unwrap(); + println!("New unwrapped key Object Handle: {}", oh); +} + +#[test] +#[serial] +fn ctx_derive_key() { + let (ctx, sh) = fixture_token().unwrap(); + + // 1. generate 2 DH KeyPairs + let (pubOh1, privOh1) = fixture_dh_key_pair( + &ctx, + sh, + String::from("label1-pub"), + String::from("label1-priv"), + ).unwrap(); + let (pubOh2, privOh2) = fixture_dh_key_pair( + &ctx, + sh, + String::from("label2-pub"), + String::from("label2-priv"), + ).unwrap(); + + // 2. retrieve the public key bytes from both + let mut template = vec![CK_ATTRIBUTE::new(CKA_VALUE)]; + ctx.get_attribute_value(sh, pubOh1, &template).unwrap(); + let value: Vec<CK_BYTE> = Vec::with_capacity(template[0].ulValueLen); + template[0].set_bytes(&value.as_slice()); + ctx.get_attribute_value(sh, pubOh1, &template).unwrap(); + + let pub1Bytes = template[0].get_bytes(); + + let mut template = vec![CK_ATTRIBUTE::new(CKA_VALUE)]; + ctx.get_attribute_value(sh, pubOh2, &template).unwrap(); + let value: Vec<CK_BYTE> = Vec::with_capacity(template[0].ulValueLen); + template[0].set_bytes(&value.as_slice()); + ctx.get_attribute_value(sh, pubOh2, &template).unwrap(); + + let pub2Bytes = template[0].get_bytes(); + + // 3. derive the first secret key + let mechanism = CK_MECHANISM { + mechanism: CKM_DH_PKCS_DERIVE, + pParameter: pub2Bytes.as_slice().as_ptr() as CK_VOID_PTR, + ulParameterLen: pub2Bytes.len(), + }; + + let class = CKO_SECRET_KEY; + let keyType = CKK_AES; + let valueLen = 32; + let label = String::from("derived-key-1"); + let token: CK_BBOOL = CK_TRUE; + let private: CK_BBOOL = CK_TRUE; + let sensitive: CK_BBOOL = CK_FALSE; + let extractable: CK_BBOOL = CK_TRUE; + + let template = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&class), + CK_ATTRIBUTE::new(CKA_KEY_TYPE).with_ck_ulong(&keyType), + CK_ATTRIBUTE::new(CKA_VALUE_LEN).with_ck_ulong(&valueLen), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&label), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&token), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&private), + CK_ATTRIBUTE::new(CKA_SENSITIVE).with_bool(&sensitive), + CK_ATTRIBUTE::new(CKA_EXTRACTABLE).with_bool(&extractable), + ]; + + let res = ctx.derive_key(sh, &mechanism, privOh1, &template); + assert!(res.is_ok(), "failed to call C_DeriveKey({}, {:?}, {}, {:?}): {}", sh, &mechanism, privOh1, &template, res.unwrap_err()); + let secOh1 = res.unwrap(); + println!("1st Derived Secret Key Object Handle: {}", secOh1); + + // 4. derive the second secret key + let mechanism = CK_MECHANISM { + mechanism: CKM_DH_PKCS_DERIVE, + pParameter: pub1Bytes.as_slice().as_ptr() as CK_VOID_PTR, + ulParameterLen: pub1Bytes.len(), + }; + + let class = CKO_SECRET_KEY; + let keyType = CKK_AES; + let valueLen = 32; + let label = String::from("derived-key-2"); + let token: CK_BBOOL = CK_TRUE; + let private: CK_BBOOL = CK_TRUE; + let sensitive: CK_BBOOL = CK_FALSE; + let extractable: CK_BBOOL = CK_TRUE; + + let template = vec![ + CK_ATTRIBUTE::new(CKA_CLASS).with_ck_ulong(&class), + CK_ATTRIBUTE::new(CKA_KEY_TYPE).with_ck_ulong(&keyType), + CK_ATTRIBUTE::new(CKA_VALUE_LEN).with_ck_ulong(&valueLen), + CK_ATTRIBUTE::new(CKA_LABEL).with_string(&label), + CK_ATTRIBUTE::new(CKA_TOKEN).with_bool(&token), + CK_ATTRIBUTE::new(CKA_PRIVATE).with_bool(&private), + CK_ATTRIBUTE::new(CKA_SENSITIVE).with_bool(&sensitive), + CK_ATTRIBUTE::new(CKA_EXTRACTABLE).with_bool(&extractable), + ]; + + let res = ctx.derive_key(sh, &mechanism, privOh2, &template); + assert!(res.is_ok(), "failed to call C_DeriveKey({}, {:?}, {}, {:?}): {}", sh, &mechanism, privOh2, &template, res.unwrap_err()); + let secOh2 = res.unwrap(); + println!("2nd Derived Secret Key Object Handle: {}", secOh2); + + // 5. retrieve the derived private keys from both + let mut template = vec![CK_ATTRIBUTE::new(CKA_VALUE)]; + ctx.get_attribute_value(sh, secOh1, &template).unwrap(); + let value: Vec<CK_BYTE> = Vec::with_capacity(template[0].ulValueLen); + template[0].set_bytes(&value.as_slice()); + ctx.get_attribute_value(sh, secOh1, &template).unwrap(); + + let sec1Bytes = template[0].get_bytes(); + + let mut template = vec![CK_ATTRIBUTE::new(CKA_VALUE)]; + ctx.get_attribute_value(sh, secOh2, &template).unwrap(); + let value: Vec<CK_BYTE> = Vec::with_capacity(template[0].ulValueLen); + template[0].set_bytes(&value.as_slice()); + ctx.get_attribute_value(sh, secOh2, &template).unwrap(); + + let sec2Bytes = template[0].get_bytes(); + + println!("1st Derived Key Bytes: {:?}", sec1Bytes); + println!("2nd Derived Key Bytes: {:?}", sec2Bytes); + assert_eq!(sec1Bytes, sec2Bytes, "Derived Secret Keys don't match"); +} + +#[test] +#[serial] +fn ctx_seed_random() { + let (ctx, sh) = fixture_token().unwrap(); + + let seed: Vec<CK_BYTE> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + let res = ctx.seed_random(sh, &seed); + assert!( + res.is_ok(), + "failed to call C_SeedRandom({}, {:?}): {}", + sh, + &seed, + res.unwrap_err() + ); +} + +#[test] +#[serial] +fn ctx_generate_random() { + let (ctx, sh) = fixture_token().unwrap(); + let res = ctx.generate_random(sh, 32); + assert!( + res.is_ok(), + "failed to call C_GenerateRandom({}, {}): {}", + sh, + 32, + res.unwrap_err() + ); + let randomData = res.unwrap(); + println!("Randomly Generated Data: {:?}", randomData); +} + +#[test] +#[serial] +fn ctx_get_function_status() { + let (ctx, sh) = fixture_token().unwrap(); + let res = ctx.get_function_status(sh); + assert!( + res.is_ok(), + "failed to call C_GetFunctionStatus({}): {}", + sh, + res.unwrap_err() + ); + let val = res.unwrap(); + assert_eq!(val, CKR_FUNCTION_NOT_PARALLEL); +} + +#[test] +#[serial] +fn ctx_cancel_function() { + let (ctx, sh) = fixture_token().unwrap(); + let res = ctx.cancel_function(sh); + assert!( + res.is_ok(), + "failed to call C_CancelFunction({}): {}", + sh, + res.unwrap_err() + ); + let val = res.unwrap(); + assert_eq!(val, CKR_FUNCTION_NOT_PARALLEL); +} + +#[test] +#[serial] +fn ctx_wait_for_slot_event() { + let (ctx, _) = fixture_token().unwrap(); + let res = ctx.wait_for_slot_event(CKF_DONT_BLOCK); + if res.is_err() { + // SoftHSM does not support this function, so this is what we should compare against + //assert_eq!(Error::Pkcs11(CKR_FUNCTION_NOT_SUPPORTED), res.unwrap_err()); + match res.unwrap_err() { + Error::Pkcs11(CKR_FUNCTION_NOT_SUPPORTED) => { + println!("as expected SoftHSM does not support this function"); + } + _ => panic!("ahhh"), + } + } else { + assert!( + res.is_ok(), + "failed to call C_WaitForSlotEvent({}): {}", + CKF_DONT_BLOCK, + res.unwrap_err() + ); + } +} |