// 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::convert::TryInto;
use std::env;
use std::path::PathBuf;
extern crate hex;
/// Tests need to be run with `RUST_TEST_THREADS=1` currently to pass.
extern crate num_traits;
use self::hex::FromHex;
use self::num_traits::Num;
use super::errors::Error;
use super::types::*;
use super::*;
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_else(|| 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_str_from_blank_padded() {
let nothing_removed = b"no padding blanks to remove";
let trailing_blanks_removed = b"a few removed ";
let leading_blanks_not_removed = b" untouched";
let trailing_nonblanks_not_removed = b"only spaces removed\t\t\t\t";
let invalid_utf8 = b"\xffinvalid";
assert_eq!(
nothing_removed,
str_from_blank_padded(nothing_removed).as_bytes()
);
assert_eq!(
b"a few removed",
str_from_blank_padded(trailing_blanks_removed).as_bytes()
);
assert_eq!(
leading_blanks_not_removed,
str_from_blank_padded(leading_blanks_not_removed).as_bytes()
);
assert_eq!(
trailing_nonblanks_not_removed,
str_from_blank_padded(trailing_nonblanks_not_removed).as_bytes()
);
assert_eq!("�invalid", str_from_blank_padded(invalid_utf8));
}
#[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);
assert_eq!("SoftHSM", String::from(info.manufacturerID));
assert_eq!(
"Implementation of PKCS11",
String::from(info.libraryDescription)
);
}
#[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].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);
assert_eq!("SoftHSM project", String::from(info.manufacturerID));
assert_eq!(
format!("SoftHSM slot ID {:#x}", slot),
String::from(info.slotDescription)
);
}
}
#[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].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);
assert_eq!("rust-unit-test", String::from(info.label));
assert_eq!("SoftHSM project", String::from(info.manufacturerID));
assert_eq!("SoftHSM v2", String::from(info.model));
}
}
#[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].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].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].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].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].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].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].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].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].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].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].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().unwrap();
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().unwrap();
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().unwrap();
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().unwrap();
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().unwrap();
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().unwrap();
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().unwrap();
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().unwrap();
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, &mut template);
if !res.is_ok() {
// Doing this not as an assert so we can both unwrap_err with the mut template and re-borrow template
let err = res.unwrap_err();
panic!(
"failed to call C_GetAttributeValue({}, {}, {:?}): {}",
sh, oh, &template, 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.try_into().unwrap());
let value: Vec<CK_BYTE> = Vec::with_capacity(template[3].ulValueLen.try_into().unwrap());
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, &mut template);
if !res.is_ok() {
// Doing this not as an assert so we can both unwrap_err with the mut template and re-borrow template
let err = res.unwrap_err();
panic!(
"failed to call C_GetAttributeValue({}, {}, {:?}): {}",
sh, oh, &template, err
);
}
let (rv, _) = res.unwrap();
println!("CK_RV: 0x{:x}, Retrieved Attributes: {:?}", rv, &template);
assert_eq!(CKO_DATA, template[0].get_ck_ulong().unwrap());
assert_eq!(true, template[1].get_bool().unwrap());
assert_eq!(
String::from("rust-unit-test"),
template[2].get_string().unwrap()
);
assert_eq!(Vec::from("Hello World!"), template[3].get_bytes().unwrap());
}
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 mut template2 = vec![CK_ATTRIBUTE::new(CKA_LABEL).with_bytes(&str.as_slice())];
ctx.get_attribute_value(sh, oh, &mut template2).unwrap();
assert_eq!(
Vec::from("Hello New World!"),
template2[0].get_bytes().unwrap()
);
}
#[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_mut(),
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_mut(),
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_mut(),
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_mut(),
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))
}
fn fixture_token_and_key_pair(
) -> Result<(Ctx, CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE), Error> {
let (ctx, sh) = fixture_token()?;
let (pubOh, privOh) = fixture_key_pair(
&ctx,
sh,
"rsa-pub".into(),
"rsa-priv".into(),
true,
true,
true,
)?;
Ok((ctx, sh, pubOh, privOh))
}
fn fixture_key_pair(
ctx: &Ctx,
sh: CK_SESSION_HANDLE,
pubLabel: String,
privLabel: String,
signVerify: bool,
encryptDecrypt: bool,
recover: bool,
) -> Result<(CK_OBJECT_HANDLE, CK_OBJECT_HANDLE), Error> {
let mechanism = CK_MECHANISM {
mechanism: CKM_RSA_PKCS_KEY_PAIR_GEN,
pParameter: ptr::null_mut(),
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 = if signVerify { CK_TRUE } else { CK_FALSE };
let privSignRecover = if recover { CK_TRUE } else { CK_FALSE };
let privDecrypt = if encryptDecrypt { CK_TRUE } else { CK_FALSE };
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),
CK_ATTRIBUTE::new(CKA_SIGN_RECOVER).with_bool(&privSignRecover),
CK_ATTRIBUTE::new(CKA_DECRYPT).with_bool(&privDecrypt),
];
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 = if signVerify { CK_TRUE } else { CK_FALSE };
let pubVerifyRecover = if recover { CK_TRUE } else { CK_FALSE };
let pubEncrypt = if encryptDecrypt { CK_TRUE } else { CK_FALSE };
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_VERIFY_RECOVER).with_bool(&pubVerifyRecover),
CK_ATTRIBUTE::new(CKA_ENCRYPT).with_bool(&pubEncrypt),
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_mut(),
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_sign_init() {
let (ctx, sh, _, privOh) = fixture_token_and_key_pair().unwrap();
let parameter = CK_RSA_PKCS_PSS_PARAMS {
hashAlg: CKM_SHA256,
mgf: CKG_MGF1_SHA256,
sLen: 32,
};
let mechanism = CK_MECHANISM {
mechanism: CKM_SHA256_RSA_PKCS_PSS,
pParameter: ¶meter as *const _ as CK_VOID_PTR,
ulParameterLen: mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>() as CK_ULONG,
};
let res = ctx.sign_init(sh, &mechanism, privOh);
assert!(
res.is_ok(),
"failed to call C_SignInit({}, {:?}, {}) with parameter: {}",
sh,
&mechanism,
privOh,
res.unwrap_err()
);
}
#[test]
#[serial]
fn ctx_sign() {
let (ctx, sh, _, privOh) = fixture_token_and_key_pair().unwrap();
let parameter = CK_RSA_PKCS_PSS_PARAMS {
hashAlg: CKM_SHA256,
mgf: CKG_MGF1_SHA256,
sLen: 32,
};
let mechanism = CK_MECHANISM {
mechanism: CKM_SHA256_RSA_PKCS_PSS,
pParameter: ¶meter as *const _ as CK_VOID_PTR,
ulParameterLen: mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>() as CK_ULONG,
};
let res = ctx.sign_init(sh, &mechanism, privOh);
assert!(
res.is_ok(),
"failed to call C_SignInit({}, {:?}, {}) with parameter: {}",
sh,
&mechanism,
privOh,
res.unwrap_err()
);
let data = String::from("Lorem ipsum tralala").into_bytes();
let signature = ctx.sign(sh, &data);
assert!(
signature.is_ok(),
"failed to call C_Sign({}, {:?}): {}",
sh,
&data,
signature.unwrap_err()
);
let signature = signature.unwrap();
println!("Signature bytes after C_Sign: {:?}", &signature);
}
#[test]
#[serial]
fn ctx_sign_update() {
let (ctx, sh, _, privOh) = fixture_token_and_key_pair().unwrap();
let parameter = CK_RSA_PKCS_PSS_PARAMS {
hashAlg: CKM_SHA256,
mgf: CKG_MGF1_SHA256,
sLen: 32,
};
let mechanism = CK_MECHANISM {
mechanism: CKM_SHA256_RSA_PKCS_PSS,
pParameter: ¶meter as *const _ as CK_VOID_PTR,
ulParameterLen: mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>() as CK_ULONG,
};
let res = ctx.sign_init(sh, &mechanism, privOh);
assert!(
res.is_ok(),
"failed to call C_SignInit({}, {:?}, {}) with parameter: {}",
sh,
&mechanism,
privOh,
res.unwrap_err()
);
let data = String::from("Lorem ipsum tralala").into_bytes();
let ret = ctx.sign_update(sh, &data);
assert!(
ret.is_ok(),
"failed to call C_SignUpdate({}, {:?}): {}",
sh,
&data,
ret.unwrap_err()
);
}
#[test]
#[serial]
fn ctx_sign_final() {
let (ctx, sh, _, privOh) = fixture_token_and_key_pair().unwrap();
let parameter = CK_RSA_PKCS_PSS_PARAMS {
hashAlg: CKM_SHA256,
mgf: CKG_MGF1_SHA256,
sLen: 32,
};
let mechanism = CK_MECHANISM {
mechanism: CKM_SHA256_RSA_PKCS_PSS,
pParameter: ¶meter as *const _ as CK_VOID_PTR,
ulParameterLen: mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>() as CK_ULONG,
};
let res = ctx.sign_init(sh, &mechanism, privOh);
assert!(
res.is_ok(),
"failed to call C_SignInit({}, {:?}, {}) with parameter: {}",
sh,
&mechanism,
privOh,
res.unwrap_err()
);
let data1 = String::from("Lorem ipsum tralala").into_bytes();
let data2 = String::from("Lorem ipsum tralala").into_bytes();
let ret = ctx.sign_update(sh, &data1);
assert!(
ret.is_ok(),
"failed to call C_SignUpdate({}, {:?}): {}",
sh,
&data1,
ret.unwrap_err()
);
let ret = ctx.sign_update(sh, &data2);
assert!(
ret.is_ok(),
"failed to call C_SignUpdate({}, {:?}): {}",
sh,
&data2,
ret.unwrap_err()
);
let signature = ctx.sign_final(sh);
assert!(
signature.is_ok(),
"failed to call C_SignFinal({}): {}",
sh,
signature.unwrap_err()
);
let signature = signature.unwrap();
println!("Signature bytes after multi-part signing: {:?}", &signature);
// final should complete the operation, so we should be able to init another
let res = ctx.sign_init(sh, &mechanism, privOh);
assert!(
res.is_ok(),
"failed to call C_SignInit({}, {:?}, {}) with parameter: {}",
sh,
&mechanism,
privOh,
res.unwrap_err()
);
}
#[test]
#[serial]
fn ctx_verify_init() {
let (ctx, sh, pubOh, _) = fixture_token_and_key_pair().unwrap();
let parameter = CK_RSA_PKCS_PSS_PARAMS {
hashAlg: CKM_SHA256,
mgf: CKG_MGF1_SHA256,
sLen: 32,
};
let mechanism = CK_MECHANISM {
mechanism: CKM_SHA256_RSA_PKCS_PSS,
pParameter: ¶meter as *const _ as CK_VOID_PTR,
ulParameterLen: mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>() as CK_ULONG,
};
let res = ctx.verify_init(sh, &mechanism, pubOh);
assert!(
res.is_ok(),
"failed to call C_VerifyInit({}, {:?}, {}) with parameter: {}",
sh,
&mechanism,
pubOh,
res.unwrap_err()
);
}
#[test]
#[serial]
fn ctx_verify() {
let (ctx, sh, pubOh, privOh) = fixture_token_and_key_pair().unwrap();
let parameter = CK_RSA_PKCS_PSS_PARAMS {
hashAlg: CKM_SHA256,
mgf: CKG_MGF1_SHA256,
sLen: 32,
};
let mechanism = CK_MECHANISM {
mechanism: CKM_SHA256_RSA_PKCS_PSS,
pParameter: ¶meter as *const _ as CK_VOID_PTR,
ulParameterLen: mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>() as CK_ULONG,
};
let res = ctx.sign_init(sh, &mechanism, privOh);
assert!(
res.is_ok(),
"failed to call C_SignInit({}, {:?}, {}) with parameter: {}",
sh,
&mechanism,
privOh,
res.unwrap_err()
);
let data = String::from("Lorem ipsum tralala").into_bytes();
let signature = ctx.sign(sh, &data);
assert!(
signature.is_ok(),
"failed to call C_Sign({}, {:?}): {}",
sh,
&data,
signature.unwrap_err()
);
let signature = signature.unwrap();
let res = ctx.verify_init(sh, &mechanism, pubOh);
assert!(
res.is_ok(),
"failed to call C_VerifyInit({}, {:?}, {}) with parameter: {}",
sh,
&mechanism,
pubOh,
res.unwrap_err()
);
let res = ctx.verify(sh, &data, &signature);
assert!(
res.is_ok(),
"failed to call C_Verify({}, {:?}, {:?}): {}",
sh,
&data,
&signature,
res.unwrap_err()
);
}
#[test]
#[serial]
fn ctx_verify_update() {
let (ctx, sh, pubOh, privOh) = fixture_token_and_key_pair().unwrap();
let parameter = CK_RSA_PKCS_PSS_PARAMS {
hashAlg: CKM_SHA256,
mgf: CKG_MGF1_SHA256,
sLen: 32,
};
let mechanism = CK_MECHANISM {
mechanism: CKM_SHA256_RSA_PKCS_PSS,
pParameter: ¶meter as *const _ as CK_VOID_PTR,
ulParameterLen: mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>() as CK_ULONG,
};
let res = ctx.sign_init(sh, &mechanism, privOh);
assert!(
res.is_ok(),
"failed to call C_SignInit({}, {:?}, {}) with parameter: {}",
sh,
&mechanism,
privOh,
res.unwrap_err()
);
let data = String::from("Lorem ipsum tralala").into_bytes();
let signature = ctx.sign(sh, &data);
assert!(
signature.is_ok(),
"failed to call C_Sign({}, {:?}): {}",
sh,
&data,
signature.unwrap_err()
);
let res = ctx.verify_init(sh, &mechanism, pubOh);
assert!(
res.is_ok(),
"failed to call C_VerifyInit({}, {:?}, {}) with parameter: {}",
sh,
&mechanism,
pubOh,
res.unwrap_err()
);
let res = ctx.verify_update(sh, &data);
assert!(
res.is_ok(),
"failed to call C_VerifyUpdate({}, {:?}): {}",
sh,
&data,
res.unwrap_err()
);
}
#[test]
#[serial]
fn ctx_verify_final() {
let (ctx, sh, pubOh, privOh) = fixture_token_and_key_pair().unwrap();
let parameter = CK_RSA_PKCS_PSS_PARAMS {
hashAlg: CKM_SHA256,
mgf: CKG_MGF1_SHA256,
sLen: 32,
};
let mechanism = CK_MECHANISM {
mechanism: CKM_SHA256_RSA_PKCS_PSS,
pParameter: ¶meter as *const _ as CK_VOID_PTR,
ulParameterLen: mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>() as CK_ULONG,
};
let res = ctx.sign_init(sh, &mechanism, privOh);
assert!(
res.is_ok(),
"failed to call C_SignInit({}, {:?}, {}) with parameter: {}",
sh,
&mechanism,
privOh,
res.unwrap_err()
);
let data = String::from("Lorem ipsum tralala").into_bytes();
let signature = ctx.sign(sh, &data);
assert!(
signature.is_ok(),
"failed to call C_Sign({}, {:?}): {}",
sh,
&data,
signature.unwrap_err()
);
let signature = signature.unwrap();
let res = ctx.verify_init(sh, &mechanism, pubOh);
assert!(
res.is_ok(),
"failed to call C_VerifyInit({}, {:?}, {}) with parameter: {}",
sh,
&mechanism,
pubOh,
res.unwrap_err()
);
let res = ctx.verify_update(sh, &data);
assert!(
res.is_ok(),
"failed to call C_VerifyUpdate({}, {:?}): {}",
sh,
&data,
res.unwrap_err()
);
let res = ctx.verify_final(sh, &signature);
assert!(
res.is_ok(),
"failed to call C_VerifyFinal({}, {:?}): {}",
sh,
&signature,
res.unwrap_err()
);
}
#[test]
#[serial]
fn ctx_sign_recover_init() {
let (ctx, sh, _, privOh) = fixture_token_and_key_pair().unwrap();
let mechanism = CK_MECHANISM {
mechanism: CKM_RSA_PKCS,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.sign_recover_init(sh, &mechanism, privOh);
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!("TODO: SoftHSM supports C_SignRecoverInit now, complete tests"),
}
} else {
assert!(
res.is_ok(),
"failed to call C_SignRecoverInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
privOh,
res.unwrap_err()
);
}
}
#[test]
#[serial]
fn ctx_sign_recover() {
let (ctx, sh) = fixture_token().unwrap();
let data = String::from("Lorem ipsum tralala").into_bytes();
let res = ctx.sign_recover(sh, &data);
assert!(res.is_err());
if let Error::Pkcs11(CKR_FUNCTION_NOT_SUPPORTED) = res.unwrap_err() {
println!("SoftHSM does not support C_SignRecover at the moment");
return;
}
panic!("TODO: SoftHSM supports C_SignRecover now, complete tests")
}
#[test]
#[serial]
fn ctx_verify_recover_init() {
let (ctx, sh, pubOh, _) = fixture_token_and_key_pair().unwrap();
let mechanism = CK_MECHANISM {
mechanism: CKM_RSA_PKCS,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.verify_recover_init(sh, &mechanism, pubOh);
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!("TODO: SoftHSM supports C_VerifyRecoverInit now, complete tests"),
}
} else {
assert!(
res.is_ok(),
"failed to call C_VerifyRecoverInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
pubOh,
res.unwrap_err()
);
}
}
#[test]
#[serial]
fn ctx_verify_recover() {
let (ctx, sh) = fixture_token().unwrap();
let data = String::from("Lorem ipsum tralala").into_bytes();
let res = ctx.verify_recover(sh, &data);
assert!(res.is_err());
if let Error::Pkcs11(CKR_FUNCTION_NOT_SUPPORTED) = res.unwrap_err() {
println!("SoftHSM does not support C_VerifyRecover at the moment");
return;
}
panic!("TODO: SoftHSM supports C_VerifyRecover now, complete tests")
}
#[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_mut(),
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_mut(),
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_encrypt_init() {
let (ctx, sh, _, secOh) = fixture_token_and_secret_keys().unwrap();
// using AES ECB just because it is the simplest to test
let mechanism = CK_MECHANISM {
mechanism: CKM_AES_ECB,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.encrypt_init(sh, &mechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_EncryptInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
secOh,
res.unwrap_err()
);
}
#[test]
#[serial]
fn ctx_encrypt() {
let (ctx, sh, _, secOh) = fixture_token_and_secret_keys().unwrap();
// using AES ECB just because it is the simplest to test
let mechanism = CK_MECHANISM {
mechanism: CKM_AES_ECB,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.encrypt_init(sh, &mechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_EncryptInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
secOh,
res.unwrap_err()
);
// plaintext is padded to one block of data: 16 bytes
let plaintext = String::from("encrypt me ").into_bytes();
let res = ctx.encrypt(sh, &plaintext);
assert!(
res.is_ok(),
"failed to call C_Encrypt({}, {:?}): {}",
sh,
&plaintext,
res.unwrap_err()
);
let res = res.unwrap();
println!("Ciphertext after single call to C_Encrypt: {:?}", res);
}
#[test]
#[serial]
fn ctx_encrypt_update() {
let (ctx, sh, _, secOh) = fixture_token_and_secret_keys().unwrap();
// using AES ECB just because it is the simplest to test
let mechanism = CK_MECHANISM {
mechanism: CKM_AES_ECB,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.encrypt_init(sh, &mechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_EncryptInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
secOh,
res.unwrap_err()
);
// plaintext is padded to one block of data: 16 bytes
let plaintext = String::from("encrypt me ").into_bytes();
let ciphertext = ctx.encrypt_update(sh, &plaintext);
assert!(
ciphertext.is_ok(),
"failed to call C_EncryptUpdate({}, {:?}): {}",
sh,
&plaintext,
ciphertext.unwrap_err()
);
let ciphertext = ciphertext.unwrap();
println!(
"Ciphertext after first call to C_EncryptUpdate: {:?}",
ciphertext
);
}
#[test]
#[serial]
fn ctx_encrypt_final() {
let (ctx, sh, _, secOh) = fixture_token_and_secret_keys().unwrap();
// using AES ECB just because it is the simplest to test
let mechanism = CK_MECHANISM {
mechanism: CKM_AES_ECB,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.encrypt_init(sh, &mechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_EncryptInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
secOh,
res.unwrap_err()
);
// plaintext is padded to one block of data: 16 bytes
let plaintext1 = String::from("encrypt me 1 ").into_bytes();
let plaintext2 = String::from("encrypt me 2 ").into_bytes();
let ciphertext1 = ctx.encrypt_update(sh, &plaintext1);
assert!(
ciphertext1.is_ok(),
"failed to call C_EncryptUpdate({}, {:?}): {}",
sh,
&plaintext1,
ciphertext1.unwrap_err()
);
let ciphertext1 = ciphertext1.unwrap();
println!(
"Ciphertext after first call to C_EncryptUpdate: {:?}",
ciphertext1
);
let ciphertext2 = ctx.encrypt_update(sh, &plaintext2);
assert!(
ciphertext2.is_ok(),
"failed to call C_EncryptUpdate({}, {:?}): {}",
sh,
&plaintext2,
ciphertext2.unwrap_err()
);
let ciphertext2 = ciphertext2.unwrap();
println!(
"Ciphertext after second call to C_EncryptUpdate: {:?}",
ciphertext2
);
let ciphertext3 = ctx.encrypt_final(sh);
assert!(
ciphertext3.is_ok(),
"failed to call C_EncryptFinal({}): {}",
sh,
ciphertext3.unwrap_err()
);
let ciphertext3 = ciphertext3.unwrap();
println!("Ciphertext after call to C_EncryptFinal: {:?}", ciphertext3);
}
#[test]
#[serial]
fn ctx_decrypt_init() {
let (ctx, sh, _, secOh) = fixture_token_and_secret_keys().unwrap();
// using AES ECB just because it is the simplest to test
let mechanism = CK_MECHANISM {
mechanism: CKM_AES_ECB,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.decrypt_init(sh, &mechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_DecryptInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
secOh,
res.unwrap_err()
);
}
#[test]
#[serial]
fn ctx_decrypt() {
let (ctx, sh, _, secOh) = fixture_token_and_secret_keys().unwrap();
// using AES ECB just because it is the simplest to test
let mechanism = CK_MECHANISM {
mechanism: CKM_AES_ECB,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
// 1. encrypt some plaintext
// plaintext is padded to one block of data: 16 bytes
let plaintext = String::from("encrypt me ").into_bytes();
println!("Plaintext: {:?}", &plaintext);
let res = ctx.encrypt_init(sh, &mechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_EncryptInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
secOh,
res.unwrap_err()
);
let ciphertext = ctx.encrypt(sh, &plaintext);
assert!(
ciphertext.is_ok(),
"failed to call C_Encrypt({}, {:?}): {}",
sh,
&plaintext,
ciphertext.unwrap_err()
);
let ciphertext = ciphertext.unwrap();
println!(
"Ciphertext after single call to C_Encrypt: {:?}",
ciphertext
);
// 2. decrypt ciphertext
let res = ctx.decrypt_init(sh, &mechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_DecryptInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
secOh,
res.unwrap_err()
);
let decrypted_ciphertext = ctx.decrypt(sh, &ciphertext);
assert!(
decrypted_ciphertext.is_ok(),
"failed to call C_Decrypt({}, {:?}): {}",
sh,
&ciphertext,
decrypted_ciphertext.unwrap_err()
);
let decrypted_ciphertext = decrypted_ciphertext.unwrap();
println!(
"Decrypted ciphertext after call to C_Decrypt: {:?}",
&decrypted_ciphertext
);
// 3. match decrypted ciphertext against plaintext
assert_eq!(plaintext, decrypted_ciphertext);
}
#[test]
#[serial]
fn ctx_decrypt_update() {
let (ctx, sh, _, secOh) = fixture_token_and_secret_keys().unwrap();
// using AES ECB just because it is the simplest to test
let mechanism = CK_MECHANISM {
mechanism: CKM_AES_ECB,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
// 1. encrypt some plaintext
// plaintext is padded to one block of data: 16 bytes
let plaintext = String::from("encrypt me ").into_bytes();
println!("Plaintext: {:?}", &plaintext);
let res = ctx.encrypt_init(sh, &mechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_EncryptInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
secOh,
res.unwrap_err()
);
let ciphertext = ctx.encrypt(sh, &plaintext);
assert!(
ciphertext.is_ok(),
"failed to call C_Encrypt({}, {:?}): {}",
sh,
&plaintext,
ciphertext.unwrap_err()
);
let ciphertext = ciphertext.unwrap();
println!(
"Ciphertext after single call to C_Encrypt: {:?}",
ciphertext
);
// 2. start to decrypt ciphertext
let res = ctx.decrypt_init(sh, &mechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_DecryptInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
secOh,
res.unwrap_err()
);
let decrypted_ciphertext = ctx.decrypt_update(sh, &ciphertext);
assert!(
decrypted_ciphertext.is_ok(),
"failed to call C_DecryptUpdate({}, {:?}): {}",
sh,
&ciphertext,
decrypted_ciphertext.unwrap_err()
);
let decrypted_ciphertext = decrypted_ciphertext.unwrap();
println!(
"Decrypted ciphertext after call to C_DecryptUpdate: {:?}",
&decrypted_ciphertext
);
}
#[test]
#[serial]
fn ctx_decrypt_final() {
let (ctx, sh, _, secOh) = fixture_token_and_secret_keys().unwrap();
// using AES ECB just because it is the simplest to test
let mechanism = CK_MECHANISM {
mechanism: CKM_AES_ECB,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
// 1. encrypt some plaintext
// plaintext is padded to one block of data: 16 bytes
let plaintext1 = String::from("encrypt me 1 ").into_bytes();
let plaintext2 = String::from("encrypt me 2 ").into_bytes();
println!("Plaintext: {:?}", &plaintext1);
let res = ctx.encrypt_init(sh, &mechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_EncryptInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
secOh,
res.unwrap_err()
);
let ciphertext1 = ctx.encrypt_update(sh, &plaintext1);
assert!(
ciphertext1.is_ok(),
"failed to call C_EncryptUpdate({}, {:?}): {}",
sh,
&plaintext1,
ciphertext1.unwrap_err()
);
let ciphertext1 = ciphertext1.unwrap();
println!(
"Ciphertext after first call to C_EncryptUpdate: {:?}",
ciphertext1
);
let ciphertext2 = ctx.encrypt_update(sh, &plaintext2);
assert!(
ciphertext2.is_ok(),
"failed to call C_EncryptUpdate({}, {:?}): {}",
sh,
&plaintext2,
ciphertext2.unwrap_err()
);
let ciphertext2 = ciphertext2.unwrap();
println!(
"Ciphertext after second call to C_EncryptUpdate: {:?}",
ciphertext2
);
let res = ctx.encrypt_final(sh);
assert!(
res.is_ok(),
"failed to call C_EncryptFinal({}): {}",
sh,
res.unwrap_err()
);
let res = res.unwrap();
assert!(
res.is_empty(),
"call to C_EncryptFinal revealed ciphertext {:?} but selected cipher should not have returned any more ciphertext",
&res
);
println!("Encryption operations finished");
// 2. start to decrypt ciphertext
let res = ctx.decrypt_init(sh, &mechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_DecryptInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
secOh,
res.unwrap_err()
);
let decrypted_ciphertext1 = ctx.decrypt_update(sh, &ciphertext1);
assert!(
decrypted_ciphertext1.is_ok(),
"failed to call C_Decrypt({}, {:?}): {}",
sh,
&ciphertext1,
decrypted_ciphertext1.unwrap_err()
);
let decrypted_ciphertext1 = decrypted_ciphertext1.unwrap();
println!(
"Decrypted ciphertext after first call to C_DecryptUpdate: {:?}",
&decrypted_ciphertext1
);
let decrypted_ciphertext2 = ctx.decrypt_update(sh, &ciphertext2);
assert!(
decrypted_ciphertext2.is_ok(),
"failed to call C_Decrypt({}, {:?}): {}",
sh,
&ciphertext2,
decrypted_ciphertext2.unwrap_err()
);
let decrypted_ciphertext2 = decrypted_ciphertext2.unwrap();
println!(
"Decrypted ciphertext after second call to C_DecryptUpdate: {:?}",
&decrypted_ciphertext2
);
let res = ctx.decrypt_final(sh);
assert!(
res.is_ok(),
"failed to call C_DecryptFinal({}): {}",
sh,
res.unwrap_err()
);
let res = res.unwrap();
assert!(
res.is_empty(),
"call to C_DecryptFinal revealed plaintext {:?} but selected cipher should not have returned any more plaintext",
&res
);
// 3. match decrypted ciphertexts against plaintexts
assert_eq!(plaintext1, decrypted_ciphertext1);
assert_eq!(plaintext2, decrypted_ciphertext2);
// 4. ensure we can start another operation without getting blasted by CKR_OPERATION_ACTIVE
let res = ctx.decrypt_init(sh, &mechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_DecryptInit({}, {:?}, {}) without parameter: {}",
sh,
&mechanism,
secOh,
res.unwrap_err()
);
}
#[test]
#[serial]
fn ctx_digest_init() {
let (ctx, sh) = fixture_token().unwrap();
// using a simple SHA256 for the test
let mechanism = CK_MECHANISM {
mechanism: CKM_SHA256,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.digest_init(sh, &mechanism);
assert!(
res.is_ok(),
"failed to call C_DigestInit({}, {:?}) without parameter: {}",
sh,
&mechanism,
res.unwrap_err()
);
}
#[test]
#[serial]
fn ctx_digest() {
let (ctx, sh) = fixture_token().unwrap();
// using a simple SHA256 for the test
let mechanism = CK_MECHANISM {
mechanism: CKM_SHA256,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.digest_init(sh, &mechanism);
assert!(
res.is_ok(),
"failed to call C_DigestInit({}, {:?}) without parameter: {}",
sh,
&mechanism,
res.unwrap_err()
);
let data = String::from("Lorem ipsum tralala").into_bytes();
let digest = ctx.digest(sh, &data);
assert!(
digest.is_ok(),
"failed to call C_Digest({}, {:?}): {}",
sh,
&data,
digest.unwrap_err()
);
let digest = digest.unwrap();
// tools like shasum are always printing lower-cased hex strings
// so let's create one of these
let hexString = digest
.iter()
.map(|b| format!("{:02x}", b))
.collect::<String>();
println!("Calculated SHA-256 Digest is: {}", hexString);
// now let's compare! created with:
// echo -n "Lorem ipsum tralala" | shasum -a 256 -p | awk '{ print $1 }'
// c4b0c693eb7c30dffc5b8c037342850b95746687a636dc95ecd9d75129277002
assert_eq!(
hexString,
"c4b0c693eb7c30dffc5b8c037342850b95746687a636dc95ecd9d75129277002"
);
}
#[test]
#[serial]
fn ctx_digest_key() {
let (ctx, sh, _, secOh) = fixture_token_and_secret_keys().unwrap();
// using a simple SHA256 for the test
let mechanism = CK_MECHANISM {
mechanism: CKM_SHA256,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.digest_init(sh, &mechanism);
assert!(
res.is_ok(),
"failed to call C_DigestInit({}, {:?}) without parameter: {}",
sh,
&mechanism,
res.unwrap_err()
);
let ret = ctx.digest_key(sh, secOh);
assert!(
ret.is_ok(),
"failed to call C_DigestKey({}, {}): {}",
sh,
secOh,
ret.unwrap_err()
);
let digest = ctx.digest_final(sh);
assert!(
digest.is_ok(),
"failed to call C_DigestFinal({}): {}",
sh,
digest.unwrap_err()
);
let digest = digest.unwrap();
// tools like shasum are always printing lower-cased hex strings
// so let's create one of these
let hexString = digest
.iter()
.map(|b| format!("{:02x}", b))
.collect::<String>();
println!(
"Calculated SHA-256 Digest for generated key is: {}",
hexString
);
}
#[test]
#[serial]
fn ctx_digest_update() {
let (ctx, sh) = fixture_token().unwrap();
// using a simple SHA256 for the test
let mechanism = CK_MECHANISM {
mechanism: CKM_SHA256,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.digest_init(sh, &mechanism);
assert!(
res.is_ok(),
"failed to call C_DigestInit({}, {:?}) without parameter: {}",
sh,
&mechanism,
res.unwrap_err()
);
let data = String::from("Lorem ipsum tralala").into_bytes();
let ret = ctx.digest_update(sh, &data);
assert!(
ret.is_ok(),
"failed to call C_DigestUpdate({}, {:?}): {}",
sh,
&data,
ret.unwrap_err()
);
let digest = ctx.digest_final(sh);
assert!(
digest.is_ok(),
"failed to call C_DigestFinal({}): {}",
sh,
digest.unwrap_err()
);
let digest = digest.unwrap();
// tools like shasum are always printing lower-cased hex strings
// so let's create one of these
let hexString = digest
.iter()
.map(|b| format!("{:02x}", b))
.collect::<String>();
println!("Calculated SHA-256 Digest is: {}", hexString);
// now let's compare! created with:
// echo -n "Lorem ipsum tralala" | shasum -a 256 -p | awk '{ print $1 }'
// c4b0c693eb7c30dffc5b8c037342850b95746687a636dc95ecd9d75129277002
assert_eq!(
hexString,
"c4b0c693eb7c30dffc5b8c037342850b95746687a636dc95ecd9d75129277002"
);
}
#[test]
#[serial]
fn ctx_digest_final() {
let (ctx, sh) = fixture_token().unwrap();
// using a simple SHA256 for the test
let mechanism = CK_MECHANISM {
mechanism: CKM_SHA256,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.digest_init(sh, &mechanism);
assert!(
res.is_ok(),
"failed to call C_DigestInit({}, {:?}) without parameter: {}",
sh,
&mechanism,
res.unwrap_err()
);
let data1 = String::from("Lorem ipsum").into_bytes();
let data2 = String::from(" tralala").into_bytes();
let ret = ctx.digest_update(sh, &data1);
assert!(
ret.is_ok(),
"failed to call C_DigestUpdate({}, {:?}): {}",
sh,
&data1,
ret.unwrap_err()
);
let ret = ctx.digest_update(sh, &data2);
assert!(
ret.is_ok(),
"failed to call C_DigestUpdate({}, {:?}): {}",
sh,
&data2,
ret.unwrap_err()
);
let digest = ctx.digest_final(sh);
assert!(
digest.is_ok(),
"failed to call C_DigestFinal({}): {}",
sh,
digest.unwrap_err()
);
let digest = digest.unwrap();
// tools like shasum are always printing lower-cased hex strings
// so let's create one of these
let hexString = digest
.iter()
.map(|b| format!("{:02x}", b))
.collect::<String>();
println!("Calculated SHA-256 Digest is: {}", hexString);
// now let's compare! created with:
// echo -n "Lorem ipsum tralala" | shasum -a 256 -p | awk '{ print $1 }'
// c4b0c693eb7c30dffc5b8c037342850b95746687a636dc95ecd9d75129277002
assert_eq!(
hexString,
"c4b0c693eb7c30dffc5b8c037342850b95746687a636dc95ecd9d75129277002"
);
// final should have completed the operation
// so we should be able to start another one
let res = ctx.digest_init(sh, &mechanism);
assert!(
res.is_ok(),
"failed to call C_DigestInit({}, {:?}) without parameter: {}",
sh,
&mechanism,
res.unwrap_err()
);
}
#[test]
#[serial]
fn ctx_digest_encrypt_update() {
let (ctx, sh, _, secOh) = fixture_token_and_secret_keys().unwrap();
// plaintext is padded to one block of data: 16 bytes
let plaintext1 = String::from("encrypt me 1 ").into_bytes();
let plaintext2 = String::from("encrypt me 2 ").into_bytes();
// check if this function is supported first
let res = ctx.digest_encrypt_update(sh, &plaintext1);
assert!(res.is_err());
if let Error::Pkcs11(CKR_FUNCTION_NOT_SUPPORTED) = res.unwrap_err() {
println!("SoftHSM does not support C_DigestEncryptUpdate at the moment");
return;
}
let encryptMechanism = CK_MECHANISM {
mechanism: CKM_AES_ECB,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.encrypt_init(sh, &encryptMechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_EncryptInit({}, {:?}, {}) without parameter: {}",
sh,
&encryptMechanism,
secOh,
res.unwrap_err()
);
let digestMechanism = CK_MECHANISM {
mechanism: CKM_SHA256,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.digest_init(sh, &digestMechanism);
assert!(
res.is_ok(),
"failed to call C_DigestInit({}, {:?}) without parameter: {}",
sh,
&digestMechanism,
res.unwrap_err()
);
let ciphertext1 = ctx.digest_encrypt_update(sh, &plaintext1);
assert!(
ciphertext1.is_ok(),
"failed to call C_DigestEncryptUpdate({}, {:?}): {}",
sh,
&plaintext1,
ciphertext1.unwrap_err()
);
let ciphertext1 = ciphertext1.unwrap();
let ciphertext2 = ctx.digest_encrypt_update(sh, &plaintext2);
assert!(
ciphertext2.is_ok(),
"failed to call C_DigestEncryptUpdate({}, {:?}): {}",
sh,
&plaintext2,
ciphertext2.unwrap_err()
);
let ciphertext2 = ciphertext2.unwrap();
let digest = ctx.digest_final(sh);
assert!(
digest.is_ok(),
"failed to call C_DigestFinal({}): {}",
sh,
digest.unwrap_err()
);
let res = ctx.encrypt_final(sh);
assert!(
res.is_ok(),
"failed to call C_EncryptFinal({}): {}",
sh,
res.unwrap_err()
);
let res = res.unwrap();
assert_eq!(res.len(), 0);
println!("Ciphertexts are: {:?}, {:?}", ciphertext1, ciphertext2);
}
#[test]
#[serial]
fn ctx_decrypt_digest_update() {
let (ctx, sh, _, secOh) = fixture_token_and_secret_keys().unwrap();
// plaintext is padded to one block of data: 16 bytes
let plaintext1Str = "encrypt me 1 ";
let plaintext2Str = "encrypt me 2 ";
let plaintext1 = String::from(plaintext1Str).into_bytes();
let plaintext2 = String::from(plaintext2Str).into_bytes();
// check if this function is supported first
let res = ctx.decrypt_digest_update(sh, &plaintext1);
assert!(res.is_err());
if let Error::Pkcs11(CKR_FUNCTION_NOT_SUPPORTED) = res.unwrap_err() {
println!("SoftHSM does not support C_DecryptDigestUpdate at the moment");
return;
}
let encryptMechanism = CK_MECHANISM {
mechanism: CKM_AES_ECB,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.encrypt_init(sh, &encryptMechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_EncryptInit({}, {:?}, {}) without parameter: {}",
sh,
&encryptMechanism,
secOh,
res.unwrap_err()
);
let digestMechanism = CK_MECHANISM {
mechanism: CKM_SHA256,
pParameter: ptr::null_mut(),
ulParameterLen: 0,
};
let res = ctx.digest_init(sh, &digestMechanism);
assert!(
res.is_ok(),
"failed to call C_DigestInit({}, {:?}) without parameter: {}",
sh,
&digestMechanism,
res.unwrap_err()
);
let ciphertext1 = ctx.digest_encrypt_update(sh, &plaintext1);
assert!(
ciphertext1.is_ok(),
"failed to call C_DigestEncryptUpdate({}, {:?}): {}",
sh,
&plaintext1,
ciphertext1.unwrap_err()
);
let ciphertext1 = ciphertext1.unwrap();
let ciphertext2 = ctx.digest_encrypt_update(sh, &plaintext2);
assert!(
ciphertext2.is_ok(),
"failed to call C_DigestEncryptUpdate({}, {:?}): {}",
sh,
&plaintext2,
ciphertext2.unwrap_err()
);
let ciphertext2 = ciphertext2.unwrap();
let digest = ctx.digest_final(sh);
assert!(
digest.is_ok(),
"failed to call C_DigestFinal({}): {}",
sh,
digest.unwrap_err()
);
let res = ctx.encrypt_final(sh);
assert!(
res.is_ok(),
"failed to call C_EncryptFinal({}): {}",
sh,
res.unwrap_err()
);
let res = res.unwrap();
assert_eq!(res.len(), 0);
println!("Ciphertexts are: {:?}, {:?}", ciphertext1, ciphertext2);
// NOW DECRYPT AND DIGEST
let res = ctx.decrypt_init(sh, &encryptMechanism, secOh);
assert!(
res.is_ok(),
"failed to call C_DecryptInit({}, {:?}, {}) without parameter: {}",
sh,
&encryptMechanism,
secOh,
res.unwrap_err()
);
let res = ctx.digest_init(sh, &digestMechanism);
assert!(
res.is_ok(),
"failed to call C_DigestInit({}, {:?}) without parameter: {}",
sh,
&digestMechanism,
res.unwrap_err()
);
let decryptedPlaintext1 = ctx.decrypt_digest_update(sh, &ciphertext1);
assert!(
decryptedPlaintext1.is_ok(),
"failed to call C_DecryptDigestUpdate({}, {:?}): {}",
sh,
&ciphertext1,
decryptedPlaintext1.unwrap_err()
);
let decryptedPlaintext1 = decryptedPlaintext1.unwrap();
let decryptedPlaintext1 = String::from_utf8_lossy(&decryptedPlaintext1);
let decryptedPlaintext2 = ctx.decrypt_digest_update(sh, &ciphertext2);
assert!(
decryptedPlaintext2.is_ok(),
"failed to call C_DecryptDigestUpdate({}, {:?}): {}",
sh,
&ciphertext2,
decryptedPlaintext2.unwrap_err()
);
let decryptedPlaintext2 = decryptedPlaintext2.unwrap();
let decryptedPlaintext2 = String::from_utf8_lossy(&decryptedPlaintext2);
let digest = ctx.digest_final(sh);
assert!(
digest.is_ok(),
"failed to call C_DigestFinal({}): {}",
sh,
digest.unwrap_err()
);
let res = ctx.decrypt_final(sh);
assert!(
res.is_ok(),
"failed to call C_DecryptFinal({}): {}",
sh,
res.unwrap_err()
);
let res = res.unwrap();
assert_eq!(res.len(), 0);
assert_eq!(decryptedPlaintext1.as_ref(), plaintext1Str);
assert_eq!(decryptedPlaintext2.as_ref(), plaintext2Str);
}
#[test]
#[serial]
fn ctx_sign_encrypt_update() {
let (ctx, sh, _, _) = fixture_token_and_key_pair().unwrap();
let data = String::from("Lorem ipsum tralala").into_bytes();
// check if this function is supported first
let res = ctx.sign_encrypt_update(sh, &data);
assert!(res.is_err());
if let Error::Pkcs11(CKR_FUNCTION_NOT_SUPPORTED) = res.unwrap_err() {
println!("SoftHSM does not support C_SignEncryptUpdate at the moment");
return;
}
panic!("TODO: SoftHSM supports C_SignEncryptUpdate now, complete tests")
}
#[test]
#[serial]
fn ctx_decrypt_verify_update() {
let (ctx, sh, _, _) = fixture_token_and_key_pair().unwrap();
let data = String::from("Lorem ipsum tralala").into_bytes();
// check if this function is supported first
let res = ctx.decrypt_verify_update(sh, data);
assert!(res.is_err());
if let Error::Pkcs11(CKR_FUNCTION_NOT_SUPPORTED) = res.unwrap_err() {
println!("SoftHSM does not support C_DecryptVerifyUpdate at the moment");
return;
}
panic!("TODO: SoftHSM supports C_DecryptVerifyUpdate now, complete tests")
}
#[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, &mut template).unwrap();
let value: Vec<CK_BYTE> = Vec::with_capacity(template[0].ulValueLen.try_into().unwrap());
template[0].set_bytes(&value.as_slice());
ctx.get_attribute_value(sh, pubOh1, &mut template).unwrap();
let pub1Bytes = template[0].get_bytes().unwrap();
let mut template = vec![CK_ATTRIBUTE::new(CKA_VALUE)];
ctx.get_attribute_value(sh, pubOh2, &mut template).unwrap();
let value: Vec<CK_BYTE> = Vec::with_capacity(template[0].ulValueLen.try_into().unwrap());
template[0].set_bytes(&value.as_slice());
ctx.get_attribute_value(sh, pubOh2, &mut template).unwrap();
let pub2Bytes = template[0].get_bytes().unwrap();
// 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().try_into().unwrap(),
};
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().try_into().unwrap(),
};
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, &mut template).unwrap();
let value: Vec<CK_BYTE> = Vec::with_capacity(template[0].ulValueLen.try_into().unwrap());
template[0].set_bytes(&value.as_slice());
ctx.get_attribute_value(sh, secOh1, &mut template).unwrap();
let sec1Bytes = template[0].get_bytes().unwrap();
let mut template = vec![CK_ATTRIBUTE::new(CKA_VALUE)];
ctx.get_attribute_value(sh, secOh2, &mut template).unwrap();
let value: Vec<CK_BYTE> = Vec::with_capacity(template[0].ulValueLen.try_into().unwrap());
template[0].set_bytes(&value.as_slice());
ctx.get_attribute_value(sh, secOh2, &mut template).unwrap();
let sec2Bytes = template[0].get_bytes().unwrap();
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();
// this is supported only starting from SoftHSM v2.6.0
let info = ctx.get_info();
assert!(
info.is_ok(),
"failed to call C_GetInfo: {}",
info.unwrap_err()
);
let info = info.unwrap();
if info.libraryVersion.major >= 2 && info.libraryVersion.minor >= 6 {
println!("SoftHSM >= 2.6.0: C_WaitForSlotEvent is supported");
} else {
return;
}
println!("Running C_WaitForSlotEvent...");
let slotID = ctx.wait_for_slot_event(CKF_DONT_BLOCK);
assert!(
slotID.is_ok(),
"failed to call C_WaitForSlotEvent({}): {}",
CKF_DONT_BLOCK,
slotID.unwrap_err()
);
let slotID = slotID.unwrap();
println!("Wait For Slot Event returned: {:?}", slotID);
// at this point we did not expect any event
assert_eq!(slotID, None);
// TODO: think about what the best way is to generate a slot event in SoftHSM
}
#[test]
#[serial]
fn ctx_get_invalid_attribute_value() {
{
let (ctx, sh, oh) = fixture_token_and_object().unwrap();
// Wrong size to trigger an error.
let label: String = String::with_capacity(1);
// Length is not important as it should fail before: the attribute does not exist in the
// object.
let public_exponent: Vec<CK_BYTE> = Vec::with_capacity(3);
let mut template = vec![
CK_ATTRIBUTE::new(CKA_LABEL),
CK_ATTRIBUTE::new(CKA_PUBLIC_EXPONENT),
];
template[0].set_string(&label);
template[1].set_bytes(&public_exponent.as_slice());
println!("Template: {:?}", template);
let res = ctx.get_attribute_value(sh, oh, &mut template);
if !res.is_ok() {
// Doing this not as an assert so we can both unwrap_err with the mut template and re-borrow template
let err = res.unwrap_err();
panic!(
"failed to call C_GetAttributeValue({}, {}, {:?}): {}",
sh, oh, &template, err
);
}
let (rv, _) = res.unwrap();
println!("CK_RV: 0x{:x}, Template: {:?}", rv, &template);
template[0].get_string().unwrap_err();
template[1].get_bytes().unwrap_err();
}
println!("The end");
}