diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a771e832..d3d357c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,7 +38,7 @@ jobs: 'perl(IPC::Cmd)' 'perl(Pod::Html)' 'perl(Digest::SHA)' \ 'perl(Module::Load::Conditional)' 'perl(File::Temp)' \ 'perl(Test::Harness)' 'perl(Test::More)' 'perl(Math::BigInt)' \ - zlib-devel sed + zlib-devel sed sqlite-devel - name: Checkout Repository uses: actions/checkout@v3 diff --git a/.gitignore b/.gitignore index 709732d6..1b6c0090 100644 --- a/.gitignore +++ b/.gitignore @@ -2,12 +2,11 @@ /Cargo.lock /src/pkcs11/bindings.rs /src/ossl/bindings.rs -/src/hacl/bindings.rs /src/fips/bindings.rs -/test.json *.o *.a *.d *.config *.swp -/hacl/gcc-compatible/config.h +/*.json +/*.sql diff --git a/Cargo.toml b/Cargo.toml index f2400eb2..2f25df56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ num-bigint = "0.4.4" num-integer = "0.1.45" num-traits = "0.2.17" once_cell = "1.18.0" +rusqlite = "0.31.0" serde = { version = "1.0.180", features = ["derive"] } serde_json = "1.0.104" uuid = { version = "1.4.1", features = ["v4"] } diff --git a/Makefile b/Makefile index 42a98e5e..b73701ec 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,14 @@ +all: + cargo build + +fips: + cargo build --features fips + +check: + cargo test + +check-fips: + cargo test --features fips check-format: @rustfmt --check --color auto src/*.rs src/*/*.rs diff --git a/README.md b/README.md index e145258f..a15e9858 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ -This is an experimental pkcs11 token written in rust +This is a pkcs11 soft token written in rust # Dependencies * rustc * openssl dependencies + * sqlite # Setup diff --git a/src/lib.rs b/src/lib.rs index 77dd2d1b..f891fbeb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -489,8 +489,8 @@ extern "C" fn fn_set_pin( let vpin: Vec = bytes_to_vec!(new_pin, new_len); let vold: Vec = bytes_to_vec!(old_pin, old_len); - let mut token = - res_or_ret!(rstate.get_token_from_slot_mut(session.get_slot_id())); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); token.set_pin(CK_UNAVAILABLE_INFORMATION, &vpin, Some(&vold)) } extern "C" fn fn_open_session( @@ -631,8 +631,8 @@ extern "C" fn fn_create_object( if !session.is_writable() { fail_if_cka_token_true!(&*tmpl); } - let mut token = - res_or_ret!(rstate.get_token_from_slot_mut(session.get_slot_id())); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); let oh = match token.create_object(s_handle, tmpl) { Ok(h) => h, @@ -659,12 +659,10 @@ extern "C" fn fn_copy_object( if !session.is_writable() { fail_if_cka_token_true!(&*tmpl); } - let mut token = - res_or_ret!(rstate.get_token_from_slot_mut(session.get_slot_id())); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); - /* Pull object to check that operation is not prohibited */ /* TODO: return CKR_ACTION_PROHIBITED instead of CKR_USER_NOT_LOGGED_IN ? */ - let _ = res_or_ret!(token.get_object_by_handle(o_handle, true)); let oh = res_or_ret!(token.copy_object(s_handle, o_handle, tmpl)); unsafe { @@ -675,28 +673,28 @@ extern "C" fn fn_copy_object( } extern "C" fn fn_destroy_object( s_handle: CK_SESSION_HANDLE, - object: CK_OBJECT_HANDLE, + o_handle: CK_OBJECT_HANDLE, ) -> CK_RV { let rstate = global_rlock!(STATE); let session = res_or_ret!(rstate.get_session(s_handle)); - let mut token = - res_or_ret!(rstate.get_token_from_slot_mut(session.get_slot_id())); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); /* TODO: return CKR_ACTION_PROHIBITED instead of CKR_USER_NOT_LOGGED_IN ? */ - let obj = res_or_ret!(token.get_object_by_handle(object, true)); + let obj = res_or_ret!(token.get_object_by_handle(o_handle)); if obj.is_token() && !session.is_writable() { return CKR_ACTION_PROHIBITED; } - ret_to_rv!(token.destroy_object(object)) + ret_to_rv!(token.destroy_object(o_handle)) } extern "C" fn fn_get_object_size( s_handle: CK_SESSION_HANDLE, - object: CK_OBJECT_HANDLE, + o_handle: CK_OBJECT_HANDLE, size: CK_ULONG_PTR, ) -> CK_RV { let rstate = global_rlock!(STATE); let token = res_or_ret!(rstate.get_token_from_session(s_handle)); - let len = res_or_ret!(token.get_object_size(object)); + let len = res_or_ret!(token.get_object_size(o_handle)); unsafe { *size = len as CK_ULONG; } @@ -710,7 +708,7 @@ extern "C" fn fn_get_attribute_value( count: CK_ULONG, ) -> CK_RV { let rstate = global_rlock!(STATE); - let token = res_or_ret!(rstate.get_token_from_session(s_handle)); + let mut token = res_or_ret!(rstate.get_token_from_session_mut(s_handle)); let mut tmpl: &mut [CK_ATTRIBUTE] = unsafe { std::slice::from_raw_parts_mut(template, count as usize) }; ret_to_rv!(token.get_object_attrs(o_handle, &mut tmpl)) @@ -723,9 +721,9 @@ extern "C" fn fn_set_attribute_value( ) -> CK_RV { let rstate = global_rlock!(STATE); let session = res_or_ret!(rstate.get_session(s_handle)); - let mut token = - res_or_ret!(rstate.get_token_from_slot_mut(session.get_slot_id())); - let obj = res_or_ret!(token.get_object_by_handle(o_handle, true)); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); + let obj = res_or_ret!(token.get_object_by_handle(o_handle)); if obj.is_token() { if !token.is_logged_in(KRY_UNSPEC) { return CKR_USER_NOT_LOGGED_IN; @@ -745,8 +743,8 @@ extern "C" fn fn_find_objects_init( ) -> CK_RV { let rstate = global_rlock!(STATE); let mut session = res_or_ret!(rstate.get_session_mut(s_handle)); - let mut token = - res_or_ret!(rstate.get_token_from_slot_mut(session.get_slot_id())); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); let tmpl: &[CK_ATTRIBUTE] = unsafe { std::slice::from_raw_parts(template, count as usize) }; ret_to_rv!(session.new_search_operation(&mut token, tmpl)) @@ -823,11 +821,12 @@ extern "C" fn fn_encrypt_init( let mut session = res_or_ret!(rstate.get_session_mut(s_handle)); check_op_empty_or_fail!(session; Encryption; mechanism); let data: &CK_MECHANISM = unsafe { &*mechanism }; - let token = res_or_ret!(rstate.get_token_from_slot(session.get_slot_id())); - let obj = res_or_ret!(token.get_object_by_handle(key, true)); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); + let obj = res_or_ret!(token.get_object_by_handle(key)).clone(); let mech = res_or_ret!(token.get_mech(data.mechanism)); if mech.info().flags & CKF_ENCRYPT == CKF_ENCRYPT { - let operation = res_or_ret!(mech.encryption_new(data, obj)); + let operation = res_or_ret!(mech.encryption_new(data, &obj)); session.set_operation(Operation::Encryption(operation)); CKR_OK } else { @@ -936,11 +935,12 @@ extern "C" fn fn_decrypt_init( let mut session = res_or_ret!(rstate.get_session_mut(s_handle)); check_op_empty_or_fail!(session; Decryption; mechanism); let data: &CK_MECHANISM = unsafe { &*mechanism }; - let token = res_or_ret!(rstate.get_token_from_slot(session.get_slot_id())); - let obj = res_or_ret!(token.get_object_by_handle(key, true)); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); + let obj = res_or_ret!(token.get_object_by_handle(key)).clone(); let mech = res_or_ret!(token.get_mech(data.mechanism)); if mech.info().flags & CKF_DECRYPT == CKF_DECRYPT { - let operation = res_or_ret!(mech.decryption_new(data, obj)); + let operation = res_or_ret!(mech.decryption_new(data, &obj)); session.set_operation(Operation::Decryption(operation)); CKR_OK } else { @@ -1133,8 +1133,8 @@ extern "C" fn fn_digest_key( if operation.finalized() { return CKR_OPERATION_NOT_INITIALIZED; } - let token = res_or_ret!(rstate.get_token_from_slot(slot_id)); - let obj = res_or_ret!(token.get_object_by_handle(key, true)); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); + let obj = res_or_ret!(token.get_object_by_handle(key)); if res_or_ret!(obj.get_attr_as_ulong(CKA_CLASS)) != CKO_SECRET_KEY { return CKR_KEY_HANDLE_INVALID; } @@ -1193,11 +1193,12 @@ extern "C" fn fn_sign_init( let mut session = res_or_ret!(rstate.get_session_mut(s_handle)); check_op_empty_or_fail!(session; Sign; mechanism); let data: &CK_MECHANISM = unsafe { &*mechanism }; - let token = res_or_ret!(rstate.get_token_from_slot(session.get_slot_id())); - let obj = res_or_ret!(token.get_object_by_handle(key, true)); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); + let obj = res_or_ret!(token.get_object_by_handle(key)).clone(); let mech = res_or_ret!(token.get_mech(data.mechanism)); if mech.info().flags & CKF_SIGN == CKF_SIGN { - let operation = res_or_ret!(mech.sign_new(data, obj)); + let operation = res_or_ret!(mech.sign_new(data, &obj)); session.set_operation(Operation::Sign(operation)); CKR_OK } else { @@ -1333,11 +1334,12 @@ extern "C" fn fn_verify_init( let mut session = res_or_ret!(rstate.get_session_mut(s_handle)); check_op_empty_or_fail!(session; Verify; mechanism); let data: &CK_MECHANISM = unsafe { &*mechanism }; - let token = res_or_ret!(rstate.get_token_from_slot(session.get_slot_id())); - let obj = res_or_ret!(token.get_object_by_handle(key, true)); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); + let obj = res_or_ret!(token.get_object_by_handle(key)).clone(); let mech = res_or_ret!(token.get_mech(data.mechanism)); if mech.info().flags & CKF_VERIFY == CKF_VERIFY { - let operation = res_or_ret!(mech.verify_new(data, obj)); + let operation = res_or_ret!(mech.verify_new(data, &obj)); session.set_operation(Operation::Verify(operation)); CKR_OK } else { @@ -1489,8 +1491,8 @@ extern "C" fn fn_generate_key( fail_if_cka_token_true!(&*tmpl); } - let mut token = - res_or_ret!(rstate.get_token_from_slot_mut(session.get_slot_id())); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); let mech = res_or_ret!(token.get_mech(data.mechanism)); if mech.info().flags & CKF_GENERATE != CKF_GENERATE { @@ -1541,8 +1543,8 @@ extern "C" fn fn_generate_key_pair( fail_if_cka_token_true!(&*pubtmpl); } - let mut token = - res_or_ret!(rstate.get_token_from_slot_mut(session.get_slot_id())); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); let mech = res_or_ret!(token.get_mech(data.mechanism)); if mech.info().flags & CKF_GENERATE_KEY_PAIR != CKF_GENERATE_KEY_PAIR { @@ -1583,14 +1585,15 @@ extern "C" fn fn_wrap_key( let session = res_or_ret!(rstate.get_session(s_handle)); let ck_mech: &CK_MECHANISM = unsafe { &*mechanism }; - let token = res_or_ret!(rstate.get_token_from_slot(session.get_slot_id())); - let kobj = res_or_ret!(token.get_object_by_handle(key, true)); - let factory = res_or_ret!(token.get_obj_factory(kobj)); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); + let kobj = res_or_ret!(token.get_object_by_handle(key)).clone(); + let wkobj = res_or_ret!(token.get_object_by_handle(wrapping_key)).clone(); + let factory = res_or_ret!(token.get_obj_factory(&kobj)); let mech = res_or_ret!(token.get_mech(ck_mech.mechanism)); if mech.info().flags & CKF_WRAP != CKF_WRAP { return CKR_MECHANISM_INVALID; } - let wkobj = res_or_ret!(token.get_object_by_handle(wrapping_key, true)); /* key checks */ if !res_or_ret!(wkobj.get_attr_as_bool(CKA_WRAP)) { @@ -1606,8 +1609,8 @@ extern "C" fn fn_wrap_key( ret_to_rv!(mech.wrap_key( ck_mech, - wkobj, - kobj, + &wkobj, + &kobj, wrapped_key, pul_wrapped_key_len, factory, @@ -1634,9 +1637,9 @@ extern "C" fn fn_unwrap_key( if !session.is_writable() { fail_if_cka_token_true!(&*tmpl); } - let mut token = - res_or_ret!(rstate.get_token_from_slot_mut(session.get_slot_id())); - let kobj = res_or_ret!(token.get_object_by_handle(unwrapping_key, true)); + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); + let kobj = res_or_ret!(token.get_object_by_handle(unwrapping_key)).clone(); let factory = res_or_ret!(token.get_obj_factory_from_key_template(tmpl)); let data: &[u8] = unsafe { std::slice::from_raw_parts(wrapped_key, wrapped_key_len as usize) @@ -1651,7 +1654,7 @@ extern "C" fn fn_unwrap_key( return CKR_WRAPPING_KEY_HANDLE_INVALID; } - let result = mech.unwrap_key(ck_mech, kobj, data, tmpl, factory); + let result = mech.unwrap_key(ck_mech, &kobj, data, tmpl, factory); match result { Ok(obj) => { let kh = res_or_ret!(token.insert_object(s_handle, obj)); diff --git a/src/object.rs b/src/object.rs index 8609a904..75e4d69e 100644 --- a/src/object.rs +++ b/src/object.rs @@ -58,6 +58,7 @@ pub struct Object { handle: CK_OBJECT_HANDLE, session: CK_SESSION_HANDLE, attributes: Vec, + modified: bool, } impl Object { @@ -66,6 +67,7 @@ impl Object { handle: CK_INVALID_HANDLE, session: CK_INVALID_HANDLE, attributes: Vec::new(), + modified: false, } } @@ -78,6 +80,7 @@ impl Object { let uuid = Uuid::new_v4().to_string(); self.attributes .push(attribute::from_string(CKA_UNIQUE_ID, uuid)); + self.modified = true; } } @@ -88,8 +91,9 @@ impl Object { if attr.get_type() == CKA_UNIQUE_ID { continue; } - obj.attributes.push(attr.clone()) + obj.attributes.push(attr.clone()); } + obj.modified = true; Ok(obj) } @@ -101,6 +105,14 @@ impl Object { self.handle } + pub fn reset_modified(&mut self) { + self.modified = false; + } + + pub fn is_modified(&self) -> bool { + self.modified + } + pub fn set_session(&mut self, s: CK_SESSION_HANDLE) { self.session = s } @@ -127,6 +139,7 @@ impl Object { Some(idx) => self.attributes[idx] = a, None => self.attributes.push(a), } + self.modified = true; Ok(()) } @@ -138,13 +151,17 @@ impl Object { return Ok(false); } } - None => self.attributes.push(a), + None => { + self.attributes.push(a); + self.modified = true; + } } Ok(true) } pub fn del_attr(&mut self, ck_type: CK_ULONG) { self.attributes.retain(|a| a.get_type() != ck_type); + self.modified = true; } pub fn get_attributes(&self) -> &Vec { @@ -186,6 +203,14 @@ impl Object { } return err_rv!(CKR_KEY_FUNCTION_NOT_PERMITTED); } + + pub fn rough_size(&self) -> KResult { + let mut size = std::mem::size_of::() * self.attributes.len(); + for val in &self.attributes { + size += val.get_value().len(); + } + Ok(size) + } } bitflags! { @@ -499,9 +524,9 @@ pub trait CertFactory { attr_element!(CKA_TRUSTED; OAFlags::Defval; from_bool; val false), attr_element!(CKA_CERTIFICATE_CATEGORY; OAFlags::Defval; from_ulong; val CK_CERTIFICATE_CATEGORY_UNSPECIFIED), attr_element!(CKA_CHECK_VALUE; OAFlags::Ignored; from_ignore; val None), - attr_element!(CKA_START_DATE; OAFlags::Defval; from_date_bytes; val Vec::new()), - attr_element!(CKA_END_DATE; OAFlags::Defval; from_date_bytes; val Vec::new()), - attr_element!(CKA_PUBLIC_KEY_INFO; OAFlags::Defval; from_bytes; val Vec::new()), + attr_element!(CKA_START_DATE; OAFlags::empty(); from_date_bytes; val Vec::new()), + attr_element!(CKA_END_DATE; OAFlags::empty(); from_date_bytes; val Vec::new()), + attr_element!(CKA_PUBLIC_KEY_INFO; OAFlags::empty(); from_bytes; val Vec::new()), ] } @@ -628,8 +653,8 @@ pub trait CommonKeyFactory { vec![ attr_element!(CKA_KEY_TYPE; OAFlags::RequiredOnCreate; from_ulong; val CK_UNAVAILABLE_INFORMATION), attr_element!(CKA_ID; OAFlags::empty(); from_bytes; val Vec::new()), - attr_element!(CKA_START_DATE; OAFlags::Defval; from_date_bytes; val Vec::new()), - attr_element!(CKA_END_DATE; OAFlags::Defval; from_date_bytes; val Vec::new()), + attr_element!(CKA_START_DATE; OAFlags::empty(); from_date_bytes; val Vec::new()), + attr_element!(CKA_END_DATE; OAFlags::empty(); from_date_bytes; val Vec::new()), attr_element!(CKA_DERIVE; OAFlags::Defval; from_bool; val false), attr_element!(CKA_LOCAL; OAFlags::Defval | OAFlags::NeverSettable; from_bool; val false), attr_element!(CKA_KEY_GEN_MECHANISM; OAFlags::Defval | OAFlags::NeverSettable; from_ulong; val CK_UNAVAILABLE_INFORMATION), diff --git a/src/slot.rs b/src/slot.rs index 5b9ca26c..029b98ff 100644 --- a/src/slot.rs +++ b/src/slot.rs @@ -166,6 +166,6 @@ impl Slot { pub fn finalize(&mut self) -> KResult<()> { self.drop_all_sessions(); - self.token.read().unwrap().save() + self.token.write().unwrap().save() } } diff --git a/src/storage.rs b/src/storage.rs index 6f090691..6c969b3a 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -1,7 +1,29 @@ // Copyright 2024 Simo Sorce // See LICENSE.txt file for terms -// Currently only the json storga eis available. -// Later on will include others and a mechanism to chose which storage -// mechanism to actually use (at build time or run time). -include!("storage/json.rs"); +use super::error; +use super::interface; +use super::object; + +use error::KResult; +use interface::CK_ATTRIBUTE; +use object::Object; + +use std::fmt::Debug; + +pub trait Storage: Debug + Send + Sync { + fn open(&mut self, filename: &String) -> KResult<()>; + fn reinit(&mut self) -> KResult<()>; + fn flush(&mut self) -> KResult<()>; + fn fetch_by_uid(&mut self, uid: &String) -> KResult<&Object>; + fn get_cached_by_uid(&self, uid: &String) -> KResult<&Object>; + fn get_cached_by_uid_mut(&mut self, uid: &String) -> KResult<&mut Object>; + fn store(&mut self, uid: &String, obj: Object) -> KResult<()>; + fn get_all_cached(&self) -> Vec<&Object>; + fn search(&mut self, template: &[CK_ATTRIBUTE]) -> KResult>; + fn remove_by_uid(&mut self, uid: &String) -> KResult<()>; +} + +pub mod json; +pub mod memory; +pub mod sqlite; diff --git a/src/storage/json.rs b/src/storage/json.rs index 7ee2deba..6594188e 100644 --- a/src/storage/json.rs +++ b/src/storage/json.rs @@ -3,16 +3,16 @@ use data_encoding::BASE64; use serde::{Deserialize, Serialize}; -use serde_json::{ - from_reader, to_string, to_string_pretty, Map, Number, Value, -}; +use serde_json::{from_reader, to_string_pretty, Map, Number, Value}; -use super::attribute; -use super::err_rv; -use super::error; -use super::interface; -use super::object; -use super::token; +use super::super::attribute; +use super::super::err_rv; +use super::super::error; +use super::super::interface; +use super::super::object; + +use super::memory; +use super::Storage; use attribute::{AttrType, Attribute}; use error::{KError, KResult}; @@ -58,13 +58,6 @@ impl JsonObject { } jo } - - pub fn rough_size(&self) -> KResult { - match to_string(&self) { - Ok(js) => Ok(js.len()), - Err(_) => err_rv!(CKR_GENERAL_ERROR), - } - } } #[derive(Debug, Serialize, Deserialize)] @@ -73,7 +66,7 @@ pub struct JsonToken { } impl JsonToken { - pub fn load(filename: &String) -> KResult { + pub fn load(filename: &str) -> KResult { match std::fs::File::open(filename) { Ok(f) => match from_reader::(f) { Ok(jt) => Ok(jt), @@ -88,7 +81,7 @@ impl JsonToken { } } - pub fn to_objects(&self, to: &mut token::TokenObjects) -> KResult<()> { + pub fn prime_cache(&self, cache: &mut Box) -> KResult<()> { for jo in &self.objects { let mut obj = Object::new(); let mut uid: Option = None; @@ -150,19 +143,19 @@ impl JsonToken { } } match uid { - Some(u) => to.insert(u, obj), + Some(u) => cache.store(&u, obj)?, None => return err_rv!(CKR_DEVICE_ERROR), } } Ok(()) } - pub fn from_objects(to: &token::TokenObjects) -> JsonToken { + pub fn from_cache(cache: &mut Box) -> JsonToken { + let objs = cache.search(&[]).unwrap(); let mut jt = JsonToken { - objects: Vec::with_capacity(to.len()), + objects: Vec::with_capacity(objs.len()), }; - - for (_, o) in to.iter() { + for o in objs { if !o.is_token() { continue; } @@ -172,7 +165,7 @@ impl JsonToken { jt } - pub fn save(&self, filename: &String) -> KResult<()> { + pub fn save(&self, filename: &str) -> KResult<()> { let jstr = match to_string_pretty(&self) { Ok(j) => j, Err(e) => return Err(KError::JsonError(e)), @@ -183,3 +176,55 @@ impl JsonToken { } } } + +#[derive(Debug)] +pub struct JsonStorage { + filename: String, + cache: Box, +} + +impl Storage for JsonStorage { + fn open(&mut self, filename: &String) -> KResult<()> { + self.filename = filename.clone(); + let token = JsonToken::load(&self.filename)?; + token.prime_cache(&mut self.cache) + } + fn reinit(&mut self) -> KResult<()> { + // TODO + Ok(()) + } + fn flush(&mut self) -> KResult<()> { + let token = JsonToken::from_cache(&mut self.cache); + token.save(&self.filename) + } + fn fetch_by_uid(&mut self, uid: &String) -> KResult<&Object> { + self.cache.fetch_by_uid(uid) + } + fn get_cached_by_uid(&self, uid: &String) -> KResult<&Object> { + self.cache.get_cached_by_uid(uid) + } + fn get_cached_by_uid_mut(&mut self, uid: &String) -> KResult<&mut Object> { + self.cache.get_cached_by_uid_mut(uid) + } + fn store(&mut self, uid: &String, obj: Object) -> KResult<()> { + self.cache.store(uid, obj)?; + self.flush() + } + fn get_all_cached(&self) -> Vec<&Object> { + self.cache.get_all_cached() + } + fn search(&mut self, template: &[CK_ATTRIBUTE]) -> KResult> { + self.cache.search(template) + } + fn remove_by_uid(&mut self, uid: &String) -> KResult<()> { + self.cache.remove_by_uid(uid)?; + self.flush() + } +} + +pub fn json() -> Box { + Box::new(JsonStorage { + filename: String::from(""), + cache: memory::memory(), + }) +} diff --git a/src/storage/memory.rs b/src/storage/memory.rs new file mode 100644 index 00000000..0c110aba --- /dev/null +++ b/src/storage/memory.rs @@ -0,0 +1,79 @@ +// Copyright 2024 Simo Sorce +// See LICENSE.txt file for terms + +use super::super::error; +use super::super::interface; +use super::super::object; +use std::collections::HashMap; + +use super::Storage; + +use super::super::{err_not_found, err_rv}; +use error::{KError, KResult}; +use interface::*; +use object::Object; + +use std::fmt::Debug; + +#[derive(Debug)] +struct MemoryStorage { + objects: HashMap, +} + +impl Storage for MemoryStorage { + fn open(&mut self, _filename: &String) -> KResult<()> { + return err_rv!(CKR_GENERAL_ERROR); + } + fn reinit(&mut self) -> KResult<()> { + self.objects.clear(); + Ok(()) + } + fn flush(&mut self) -> KResult<()> { + Ok(()) + } + fn fetch_by_uid(&mut self, uid: &String) -> KResult<&Object> { + self.get_cached_by_uid(uid) + } + fn get_cached_by_uid(&self, uid: &String) -> KResult<&Object> { + match self.objects.get(uid) { + Some(o) => Ok(o), + None => err_not_found! {uid.clone()}, + } + } + fn get_cached_by_uid_mut(&mut self, uid: &String) -> KResult<&mut Object> { + match self.objects.get_mut(uid) { + Some(o) => Ok(o), + None => err_not_found! {uid.clone()}, + } + } + fn store(&mut self, uid: &String, obj: Object) -> KResult<()> { + self.objects.insert(uid.clone(), obj); + Ok(()) + } + fn get_all_cached(&self) -> Vec<&Object> { + let mut ret = Vec::<&Object>::with_capacity(self.objects.len()); + for (_, o) in self.objects.iter() { + ret.push(o); + } + ret + } + fn search(&mut self, template: &[CK_ATTRIBUTE]) -> KResult> { + let mut ret = Vec::<&Object>::new(); + for (_, o) in self.objects.iter() { + if o.match_template(template) { + ret.push(o); + } + } + Ok(ret) + } + fn remove_by_uid(&mut self, uid: &String) -> KResult<()> { + self.objects.remove(uid); + Ok(()) + } +} + +pub fn memory() -> Box { + Box::new(MemoryStorage { + objects: HashMap::new(), + }) +} diff --git a/src/storage/sqlite.rs b/src/storage/sqlite.rs new file mode 100644 index 00000000..3973fafb --- /dev/null +++ b/src/storage/sqlite.rs @@ -0,0 +1,360 @@ +// Copyright 2024 Simo Sorce +// See LICENSE.txt file for terms + +use rusqlite::{params, Connection, Rows, ToSql, Transaction}; +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; + +use super::super::error; +use super::super::interface; +use super::super::object; +use super::super::{err_not_found, err_rv}; + +use super::Storage; + +use error::{KError, KResult}; +use interface::*; +use object::Object; + +/* causes .or to fail to find which impl to use +impl From for KError { + fn from(error: rusqlite::Error) -> Self { + KError::RvError(error::CkRvError { rv: CKR_DEVICE_MEMORY }) + } +} +*/ + +fn bad_code(_error: T) -> KError { + KError::RvError(error::CkRvError { + rv: CKR_GENERAL_ERROR, + }) +} + +fn bad_storage(_error: T) -> KError { + KError::RvError(error::CkRvError { + rv: CKR_DEVICE_MEMORY, + }) +} + +const IS_DB_INITIALIZED: &str = + "SELECT count(*) FROM sqlite_master WHERE type='table' AND name='objects'"; +const DROP_DB_TABLE: &str = "DROP TABLE objects"; +const CREATE_DB_TABLE: &str = "CREATE TABLE objects (id int NOT NULL, attr int NOT NULL, val blob, enc int, UNIQUE (id, attr))"; + +/* search by filter constants */ +const SEARCH_ALL: &str = "SELECT * FROM objects"; +const SEARCH_NEST: &str = " WHERE id IN ( "; +const SEARCH_OBJ_ID: &str = "SELECT id FROM objects WHERE attr = ? AND val = ?"; +const SEARCH_CONCAT: &str = " INTERSECT "; +const SEARCH_CLOSE: &str = " )"; +const SEARCH_ORDER: &str = " ORDER by id"; + +const SEARCH_BY_SINGLE_ATTR: &str = "SELECT * FROM objects WHERE id IN (SELECT id FROM objects WHERE attr = ? AND val = ?)"; +const UPDATE_ATTR: &str = "INSERT OR REPLACE INTO objects VALUES (?, ?, ?, ?)"; +const DELETE_OBJ: &str = "DELETE FROM objects WHERE id = ?"; +const MAX_ID: &str = "SELECT IFNULL(MAX(id), 0) FROM objects"; + +#[derive(Debug)] +pub struct SqliteStorage { + filename: String, + conn: Arc>, + cache: HashMap, +} + +impl SqliteStorage { + fn is_initialized(&self) -> KResult<()> { + let conn = self.conn.lock().unwrap(); + let result = conn + .query_row_and_then(IS_DB_INITIALIZED, [], |row| row.get(0)) + .map_err(bad_storage)?; + match result { + 1 => Ok(()), + 0 => err_rv!(CKR_CRYPTOKI_NOT_INITIALIZED), + _ => err_rv!(CKR_DEVICE_MEMORY), + } + } + + fn db_reset(&mut self) -> KResult<()> { + let mut conn = self.conn.lock().unwrap(); + let mut tx = conn.transaction().map_err(bad_storage)?; + tx.set_drop_behavior(rusqlite::DropBehavior::Rollback); + /* the drop can fail when files are empty (new) */ + let _ = tx.execute(DROP_DB_TABLE, params![]); + tx.execute(CREATE_DB_TABLE, params![]) + .map_err(bad_storage)?; + tx.commit().map_err(bad_storage) + } + + fn rows_to_objects(mut rows: Rows) -> KResult> { + let mut objid = 0; + let mut objects = Vec::::new(); + while let Some(row) = rows.next().map_err(bad_storage)? { + let id: i32 = row.get(0).map_err(bad_storage)?; + let atype: CK_ULONG = row.get(1).map_err(bad_storage)?; + let value = row + .get_ref(2) + .map_err(bad_storage)? + .as_blob() + .map_err(bad_code)?; + /* TODO: enc */ + if objid != id { + objid = id; + objects.push(Object::new()); + } + if let Some(obj) = objects.last_mut() { + let ck_attr = CK_ATTRIBUTE { + type_: atype, + pValue: value.as_ptr() as *mut _, + ulValueLen: value.len() as CK_ULONG, + }; + /* makes a copy of the blob */ + let attr = ck_attr.to_attribute()?; + obj.set_attr(attr)?; + } else { + return err_rv!(CKR_GENERAL_ERROR); + } + } + Ok(objects) + } + + fn search_by_unique_id(conn: &Connection, uid: &String) -> KResult { + let mut stmt = conn.prepare(SEARCH_BY_SINGLE_ATTR).map_err(bad_code)?; + let rows = stmt + .query(params![CKA_UNIQUE_ID, uid.as_bytes()]) + .map_err(bad_code)?; + let mut objects = Self::rows_to_objects(rows)?; + match objects.len() { + 0 => err_not_found!(uid.clone()), + 1 => Ok(objects.pop().unwrap()), + _ => err_rv!(CKR_GENERAL_ERROR), + } + } + + fn search_with_filter( + conn: &Connection, + template: &[CK_ATTRIBUTE], + ) -> KResult> { + let mut search_query = String::from(SEARCH_ALL); + let mut subqcount = 0; + let mut search_params = + Vec::<&dyn ToSql>::with_capacity(template.len() * 2); + let mut params_holder = + Vec::<(CK_ULONG, &[u8])>::with_capacity(template.len()); + for attr in template { + /* add subqueries */ + if subqcount == 0 { + search_query.push_str(SEARCH_NEST); + } else { + search_query.push_str(SEARCH_CONCAT); + } + search_query.push_str(SEARCH_OBJ_ID); + /* add parameters */ + params_holder.push((attr.type_, unsafe { + /* template is guaranteed to stay around + * for the life of the function so it is + * safe enough */ + std::slice::from_raw_parts( + attr.pValue as *const u8, + attr.ulValueLen as usize, + ) + })); + subqcount += 1; + } + if subqcount > 0 { + /* reformat parameters for query */ + for p in params_holder.iter() { + search_params.push(&p.0 as &dyn ToSql); + search_params.push(&p.1 as &dyn ToSql); + } + search_query.push_str(SEARCH_CLOSE); + } + /* finally make sure results return ordered by id, + * this simplifies conversion to actual Objects */ + search_query.push_str(SEARCH_ORDER); + + let mut stmt = conn.prepare(&search_query).map_err(bad_code)?; + let rows = stmt.query(search_params.as_slice()).map_err(bad_code)?; + Ok(Self::rows_to_objects(rows)?) + } + + fn store_object( + tx: &mut Transaction, + uid: &String, + obj: &Object, + ) -> KResult<()> { + let objid = match Self::delete_object(tx, uid)? { + 0 => { + /* find new id to use for new object */ + let mut maxid = 0; + let mut stmt = tx.prepare(MAX_ID).map_err(bad_code)?; + let mut rows = stmt.query([]).map_err(bad_code)?; + while let Some(row) = rows.next().map_err(bad_storage)? { + maxid = row.get(0).map_err(bad_storage)?; + } + maxid + 1 + } + x => x, + }; + let mut stmt = tx.prepare(UPDATE_ATTR).map_err(bad_storage)?; + for a in obj.get_attributes() { + let _ = stmt + .execute(params![objid, a.get_type(), a.get_value(), 0]) + .map_err(bad_storage)?; + } + Ok(()) + } + + fn delete_object(tx: &mut Transaction, uid: &String) -> KResult { + let mut stmt = tx.prepare(SEARCH_OBJ_ID).map_err(bad_storage)?; + let objid = match stmt + .query_row(params![CKA_UNIQUE_ID, uid.as_bytes()], |row| row.get(0)) + { + Ok(r) => r, + Err(e) => match e { + rusqlite::Error::QueryReturnedNoRows => 0, + _ => return err_rv!(CKR_DEVICE_MEMORY), + }, + }; + /* remove old object */ + if objid != 0 { + stmt = tx.prepare(DELETE_OBJ).map_err(bad_code)?; + stmt.execute(params![objid]).map_err(bad_storage)?; + } + Ok(objid) + } + + fn cache_obj(&mut self, uid: &String, mut obj: Object) { + /* when inserting in cache we must clear the modified flag */ + obj.reset_modified(); + /* maintain handle/session when replacing */ + if let Some((uid_, old)) = self.cache.remove_entry(uid) { + /* FIXME: bug on old.is_modified() ? */ + obj.set_handle(old.get_handle()); + obj.set_session(old.get_session()); + self.cache.insert(uid_, obj); + } else { + self.cache.insert(uid.clone(), obj); + } + } +} + +impl Storage for SqliteStorage { + fn open(&mut self, filename: &String) -> KResult<()> { + self.filename = filename.clone(); + self.conn = match Connection::open(&self.filename) { + Ok(c) => Arc::new(Mutex::from(c)), + Err(_) => return err_rv!(CKR_TOKEN_NOT_PRESENT), + }; + self.cache.clear(); + self.is_initialized() + } + fn reinit(&mut self) -> KResult<()> { + self.db_reset() + } + fn flush(&mut self) -> KResult<()> { + let mut conn = self.conn.lock().unwrap(); + let mut tx = conn.transaction().map_err(bad_storage)?; + tx.set_drop_behavior(rusqlite::DropBehavior::Rollback); + for (uid, obj) in &mut self.cache { + if obj.is_modified() { + obj.reset_modified(); + if obj.is_token() { + Self::store_object(&mut tx, uid, obj)?; + } + } + } + tx.commit().map_err(bad_storage) + } + fn fetch_by_uid(&mut self, uid: &String) -> KResult<&Object> { + let is_token = match self.get_cached_by_uid(uid) { + Ok(obj) => obj.is_token(), + _ => true, + }; + if is_token { + let conn = self.conn.lock().unwrap(); + let obj = Self::search_by_unique_id(&conn, uid)?; + drop(conn); + self.cache_obj(uid, obj); + } + self.get_cached_by_uid(uid) + } + fn get_cached_by_uid(&self, uid: &String) -> KResult<&Object> { + if let Some(o) = self.cache.get(uid) { + return Ok(o); + } + err_not_found!(uid.clone()) + } + fn get_cached_by_uid_mut(&mut self, uid: &String) -> KResult<&mut Object> { + if !self.cache.contains_key(uid) { + let conn = self.conn.lock().unwrap(); + let obj = Self::search_by_unique_id(&conn, uid)?; + drop(conn); + self.cache_obj(uid, obj); + } + if let Some(o) = self.cache.get_mut(uid) { + return Ok(o); + } + err_not_found!(uid.clone()) + } + fn store(&mut self, uid: &String, obj: Object) -> KResult<()> { + if obj.is_token() { + let mut conn = self.conn.lock().unwrap(); + let mut tx = conn.transaction().map_err(bad_storage)?; + tx.set_drop_behavior(rusqlite::DropBehavior::Rollback); + Self::store_object(&mut tx, uid, &obj)?; + tx.commit().map_err(bad_storage)?; + } + self.cache_obj(uid, obj); + Ok(()) + } + fn get_all_cached(&self) -> Vec<&Object> { + let mut result = Vec::<&Object>::with_capacity(self.cache.len()); + for (_, o) in self.cache.iter() { + result.push(o); + } + result + } + fn search(&mut self, template: &[CK_ATTRIBUTE]) -> KResult> { + let conn = self.conn.lock().unwrap(); + let mut objects = Self::search_with_filter(&conn, template)?; + drop(conn); + for obj in objects.drain(..) { + /* if uid is not available we can only skip */ + let uid = match obj.get_attr_as_string(CKA_UNIQUE_ID) { + Ok(u) => u, + Err(_) => continue, + }; + self.cache_obj(&uid, obj); + } + let mut result = Vec::<&Object>::new(); + for (_, o) in self.cache.iter() { + if o.match_template(template) { + result.push(o); + } + } + Ok(result) + } + fn remove_by_uid(&mut self, uid: &String) -> KResult<()> { + let is_token = match self.get_cached_by_uid(uid) { + Ok(obj) => obj.is_token(), + _ => true, + }; + self.cache.remove(uid); + if is_token { + let mut conn = self.conn.lock().unwrap(); + let mut tx = conn.transaction().map_err(bad_storage)?; + tx.set_drop_behavior(rusqlite::DropBehavior::Rollback); + Self::delete_object(&mut tx, &uid)?; + tx.commit().map_err(bad_storage)?; + } + Ok(()) + } +} + +pub fn sqlite() -> Box { + Box::new(SqliteStorage { + filename: String::from(""), + conn: Arc::new(Mutex::from(Connection::open_in_memory().unwrap())), + cache: HashMap::new(), + }) +} diff --git a/src/tests.rs b/src/tests.rs index 9f83ccef..c3e63c21 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -50,7 +50,6 @@ static SLOTS: RwLock = RwLock::new(Slots { id: 0 }); struct TestData<'a> { slot: CK_SLOT_ID, filename: &'a str, - created: bool, finalize: Option>, sync: Option>, } @@ -62,110 +61,51 @@ impl TestData<'_> { TestData { slot: slots.id, filename: filename, - created: false, finalize: test_finalizer(), sync: Some(SYNC.read().unwrap()), } } - fn setup_db(&mut self) { - let test_token = serde_json::json!({ - "objects": [{ - "attributes": { - "CKA_UNIQUE_ID": "0", - "CKA_CLASS": 4, - "CKA_KEY_TYPE": 16, - "CKA_LABEL": "SO PIN", - "CKA_VALUE": "MTIzNDU2Nzg=", - "CKA_TOKEN": true - } - }, { - "attributes": { - "CKA_UNIQUE_ID": "1", - "CKA_CLASS": 4, - "CKA_KEY_TYPE": 16, - "CKA_LABEL": "User PIN", - "CKA_VALUE": "MTIzNDU2Nzg=", - "CKA_TOKEN": true - } - }, { - "attributes": { - "CKA_UNIQUE_ID": "2", - "CKA_CLASS": 2, - "CKA_KEY_TYPE": 0, - "CKA_DESTROYABLE": false, - "CKA_ID": "AQ==", - "CKA_LABEL": "Test RSA Key", - "CKA_MODIFIABLE": true, - "CKA_MODULUS": "AQIDBAUGBwg=", - "CKA_PRIVATE": false, - "CKA_PUBLIC_EXPONENT": "AQAB", - "CKA_TOKEN": true - } - }, { - "attributes": { - "CKA_UNIQUE_ID": "3", - "CKA_CLASS": 3, - "CKA_KEY_TYPE": 0, - "CKA_DESTROYABLE": false, - "CKA_ID": "AQ==", - "CKA_LABEL": "Test RSA Key", - "CKA_MODIFIABLE": false, - "CKA_MODULUS": "AQIDBAUGBwg=", - "CKA_PRIVATE": true, - "CKA_SENSITIVE": true, - "CKA_EXTRACTABLE": false, - "CKA_PUBLIC_EXPONENT": "AQAB", - "CKA_PRIVATE_EXPONENT": "AQAD", - "CKA_TOKEN": true - } - }, { - "attributes": { - "CKA_UNIQUE_ID": "4", - "CKA_CLASS": 2, - "CKA_KEY_TYPE": 3, - "CKA_DESTROYABLE": false, - "CKA_ID": "Ag==", - "CKA_LABEL": "Test EC Key", - "CKA_MODIFIABLE": true, - "CKA_PRIVATE": false, - "CKA_EC_PARAMS": "BggqhkjOPQMBBw==", - "CKA_EC_POINT": "BOaBBjTeoFaH/PYBjY7hCZOJTtdbESgdPzXZwt8YXWA6iAYamlZ0X8I6npsh0OlyTMrvYIo+JccaoUki/cROlEU=", - "CKA_TOKEN": true, - "CKA_VERIFY": true - } - }, { - "attributes": { - "CKA_UNIQUE_ID": "5", - "CKA_CLASS": 3, - "CKA_KEY_TYPE": 3, - "CKA_DESTROYABLE": false, - "CKA_ID": "Ag==", - "CKA_LABEL": "Test EC Key", - "CKA_MODIFIABLE": false, - "CKA_PRIVATE": true, - "CKA_SENSITIVE": true, - "CKA_EXTRACTABLE": false, - "CKA_EC_PARAMS": "BggqhkjOPQMBBw==", - "CKA_VALUE": "mtoobolazGJPX6gecD57oWxvwZl02fKc7BKwixExm5M=", - "CKA_TOKEN": true, - "CKA_SIGN": true - } - }] - }); - let file = std::fs::File::create(self.filename).unwrap(); - serde_json::to_writer_pretty(file, &test_token).unwrap(); - self.created = true; + fn setup_db<'a>(&mut self, source: Option<&'a str>) { + let basic = "testdata/test_basic.json"; + let filename = match source { + Some(s) => s, + None => basic, + }; + let test_data = storage::json::JsonToken::load(filename).unwrap(); + if self.filename.ends_with(".json") { + test_data.save(self.filename).unwrap(); + } else if self.filename.ends_with(".sql") { + let mut cache = storage::memory::memory(); + test_data.prime_cache(&mut cache).unwrap(); + let mut sql = storage::sqlite::sqlite(); + match sql.open(&self.filename.to_string()) { + Ok(()) => (), + Err(err) => match err { + KError::RvError(ref e) => { + if e.rv != CKR_CRYPTOKI_NOT_INITIALIZED { + panic!("Unexpected error: {}", e.rv); + } + } + _ => panic!("Unexpected error: {}", err), + }, + } + /* reset db in all cases */ + sql.reinit().unwrap(); + let objects = cache.search(&[]).unwrap(); + for obj in objects { + let uid = obj.get_attr_as_string(CKA_UNIQUE_ID).unwrap(); + sql.store(&uid, obj.clone()).unwrap() + } + } else { + panic!("Unknown file type"); + } } fn get_slot(&self) -> CK_SLOT_ID { self.slot } - fn mark_file_created(&mut self) { - self.created = true; - } - fn make_init_args(&self) -> CK_C_INITIALIZE_ARGS { let reserved: String = format!("{}:{}", self.filename, self.slot); @@ -194,16 +134,13 @@ impl TestData<'_> { /* winner finalized and completed the tests */ self.finalize = None; } - if self.created { - std::fs::remove_file(self.filename).unwrap_or(()); - } + std::fs::remove_file(self.filename).unwrap_or(()); } } -#[test] -fn test_token() { - let mut testdata = TestData::new("testdata/test_token.json"); - testdata.setup_db(); +fn test_token(name: &str) { + let mut testdata = TestData::new(name); + testdata.setup_db(None); let mut plist: *mut CK_FUNCTION_LIST = std::ptr::null_mut(); let pplist = &mut plist; @@ -225,10 +162,20 @@ fn test_token() { testdata.finalize(); } +#[test] +fn test_token_json() { + test_token("test_token.json"); +} + +#[test] +fn test_token_sql() { + test_token("test_token.sql"); +} + #[test] fn test_random() { - let mut testdata = TestData::new("testdata/test_random.json"); - testdata.setup_db(); + let mut testdata = TestData::new("test_random.json"); + testdata.setup_db(None); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -257,10 +204,9 @@ fn test_random() { testdata.finalize(); } -#[test] -fn test_login() { - let mut testdata = TestData::new("testdata/test_login.json"); - testdata.setup_db(); +fn test_login(name: &str) { + let mut testdata = TestData::new(name); + testdata.setup_db(None); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -348,10 +294,20 @@ fn test_login() { testdata.finalize(); } +#[test] +fn test_login_json() { + test_login("test_login.json"); +} + +#[test] +fn test_login_sql() { + test_login("test_login.sql"); +} + #[test] fn test_get_attr() { - let mut testdata = TestData::new("testdata/test_get_attr.json"); - testdata.setup_db(); + let mut testdata = TestData::new("test_get_attr.sql"); + testdata.setup_db(None); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -475,8 +431,8 @@ fn test_get_attr() { #[test] fn test_set_attr() { - let mut testdata = TestData::new("testdata/test_set_attr.json"); - testdata.setup_db(); + let mut testdata = TestData::new("test_set_attr.sql"); + testdata.setup_db(None); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -563,8 +519,8 @@ fn test_set_attr() { #[test] fn test_copy_objects() { - let mut testdata = TestData::new("testdata/test_copy_objects.json"); - testdata.setup_db(); + let mut testdata = TestData::new("test_copy_objects.sql"); + testdata.setup_db(None); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -679,8 +635,8 @@ fn test_copy_objects() { #[test] fn test_create_objects() { - let mut testdata = TestData::new("testdata/test_create_objects.json"); - testdata.setup_db(); + let mut testdata = TestData::new("test_create_objects.sql"); + testdata.setup_db(None); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -941,8 +897,8 @@ fn test_create_objects() { #[test] fn test_create_ec_objects() { - let mut testdata = TestData::new("testdata/test_create_ec_objects.json"); - testdata.setup_db(); + let mut testdata = TestData::new("test_create_ec_objects.sql"); + testdata.setup_db(None); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -1053,12 +1009,7 @@ fn test_create_ec_objects() { #[test] fn test_init_token() { - let mut testdata = TestData::new("testdata/test_init_token.json"); - /* skip setup, we are creating an unitiliaized token */ - - /* but mark the file as created, - * so it will be cleaned up when the test is complete */ - testdata.mark_file_created(); + let mut testdata = TestData::new("test_init_token.sql"); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -1240,8 +1191,8 @@ fn test_init_token() { #[test] fn test_get_mechs() { - let mut testdata = TestData::new("testdata/test_get_mechs.json"); - testdata.setup_db(); + let mut testdata = TestData::new("test_get_mechs.sql"); + testdata.setup_db(None); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -1335,7 +1286,8 @@ fn get_test_data( #[test] fn test_aes_operations() { - let mut testdata = TestData::new("testdata/test_aes_operations.json"); + let mut testdata = TestData::new("test_aes_operations.sql"); + testdata.setup_db(Some("testdata/test_aes_operations.json")); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -2172,7 +2124,8 @@ fn test_aes_operations() { #[test] fn test_rsa_operations() { - let mut testdata = TestData::new("testdata/test_rsa_operations.json"); + let mut testdata = TestData::new("test_rsa_operations.sql"); + testdata.setup_db(Some("testdata/test_rsa_operations.json")); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -2489,8 +2442,8 @@ fn test_rsa_operations() { #[test] fn test_session_objects() { - let mut testdata = TestData::new("testdata/test_session_objects.json"); - testdata.setup_db(); + let mut testdata = TestData::new("test_session_objects.sql"); + testdata.setup_db(None); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -2647,7 +2600,8 @@ fn test_session_objects() { #[test] fn test_ecc_operations() { - let mut testdata = TestData::new("testdata/test_ecc_operations.json"); + let mut testdata = TestData::new("test_ecc_operations.sql"); + testdata.setup_db(Some("testdata/test_ecc_operations.json")); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -2847,7 +2801,8 @@ fn test_ecc_operations() { #[test] fn test_hashes_digest() { - let mut testdata = TestData::new("testdata/test_hashes.json"); + let mut testdata = TestData::new("test_hashes.sql"); + testdata.setup_db(Some("testdata/test_hashes.json")); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -3404,7 +3359,8 @@ fn encrypt( #[test] fn test_signatures() { /* Test Vectors from python cryptography's pkcs1v15sign-vectors.txt */ - let mut testdata = TestData::new("testdata/test_sign_verify.json"); + let mut testdata = TestData::new("test_sign_verify.sql"); + testdata.setup_db(Some("testdata/test_sign_verify.json")); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; @@ -3706,8 +3662,8 @@ fn test_signatures() { #[test] fn test_key() { - let mut testdata = TestData::new("testdata/test_key.json"); - testdata.setup_db(); + let mut testdata = TestData::new("test_key.sql"); + testdata.setup_db(None); let mut args = testdata.make_init_args(); let args_ptr = &mut args as *mut CK_C_INITIALIZE_ARGS; diff --git a/src/token.rs b/src/token.rs index c37deb14..e2825076 100644 --- a/src/token.rs +++ b/src/token.rs @@ -16,13 +16,12 @@ use super::object; use super::rsa; use super::storage; -use super::{err_not_found, err_rv}; +use super::err_rv; use error::{KError, KResult}; use interface::*; use mechanism::Mechanisms; use object::{Object, ObjectFactories}; - -use std::collections::hash_map::Iter; +use storage::Storage; static TOKEN_LABEL: [CK_UTF8CHAR; 32usize] = *b"Kryoptic FIPS Token "; @@ -31,6 +30,9 @@ static MANUFACTURER_ID: [CK_UTF8CHAR; 32usize] = static TOKEN_MODEL: [CK_UTF8CHAR; 16usize] = *b"FIPS-140-3 v1 "; static TOKEN_SERIAL: [CK_UTF8CHAR; 16usize] = *b"0000000000000000"; +const SO_PIN_UID: &str = "0"; +const USER_PIN_UID: &str = "1"; + #[derive(Debug, Clone)] struct LoginData { pin: Option>, @@ -89,151 +91,40 @@ impl LoginData { } } -#[derive(Debug)] -pub struct TokenObjects { - objects: HashMap, - handles: HashMap, - next_handle: CK_OBJECT_HANDLE, +#[derive(Debug, Clone)] +pub struct Handles { + map: HashMap, + next: CK_OBJECT_HANDLE, } -impl TokenObjects { - fn new() -> TokenObjects { - TokenObjects { - objects: HashMap::new(), - handles: HashMap::new(), - next_handle: 1, +impl Handles { + pub fn new() -> Handles { + Handles { + map: HashMap::new(), + next: 1, } } - fn initialize(&mut self) { - self.objects = HashMap::new(); - self.handles = HashMap::new(); - self.next_handle = 1; - } - - pub fn len(&self) -> usize { - self.objects.len() - } - - fn get(&self, uid: &String) -> Option<&Object> { - self.objects.get(uid) - } - - pub fn get_mut(&mut self, uid: &String) -> Option<&mut Object> { - self.objects.get_mut(uid) - } - - pub fn insert(&mut self, uid: String, obj: Object) { - self.objects.insert(uid, obj); - } - - pub fn iter(&self) -> Iter<'_, String, Object> { - self.objects.iter() - } - - pub fn remove( + pub fn insert( &mut self, handle: CK_OBJECT_HANDLE, - session_only: bool, - ) -> KResult<()> { - let uid = match self.handles.get(&handle) { - Some(u) => u, - None => return err_rv!(CKR_OBJECT_HANDLE_INVALID), - }; - let obj = match self.objects.get(uid) { - Some(o) => o, - None => { - self.handles.remove(&handle); - return err_rv!(CKR_OBJECT_HANDLE_INVALID); - } - }; - if session_only && obj.is_token() { - return err_rv!(CKR_ACTION_PROHIBITED); - } - - self.objects.remove(uid); - self.handles.remove(&handle); - Ok(()) - } - - pub fn next_handle(&mut self) -> CK_OBJECT_HANDLE { - let next = self.next_handle; - self.next_handle += 1; - next - } - - fn get_by_handle(&self, handle: CK_OBJECT_HANDLE) -> KResult<&Object> { - match self.handles.get(&handle) { - Some(s) => match self.objects.get(s) { - Some(o) => Ok(o), - None => err_not_found! {s.clone()}, - }, - None => err_rv!(CKR_OBJECT_HANDLE_INVALID), - } - } - - fn get_by_handle_mut( - &mut self, - handle: CK_OBJECT_HANDLE, - ) -> KResult<&mut Object> { - match self.handles.get(&handle) { - Some(s) => match self.objects.get_mut(s) { - Some(o) => Ok(o), - None => err_not_found! {s.clone()}, - }, - None => err_rv!(CKR_OBJECT_HANDLE_INVALID), - } + value: String, + ) -> Option { + self.map.insert(handle, value) } - pub fn insert_handle(&mut self, oh: CK_OBJECT_HANDLE, uid: String) { - self.handles.insert(oh, uid); + pub fn get(&self, handle: CK_OBJECT_HANDLE) -> Option<&String> { + self.map.get(&handle) } - fn clear_private_session_objects(&mut self) { - let mut priv_uids = Vec::::new(); - for (_, obj) in &self.objects { - if obj.is_private() { - let oh = obj.get_handle(); - if oh != CK_INVALID_HANDLE { - let _ = self.handles.remove(&oh); - } - if !obj.is_token() { - /* not a token object, therefore we need to destroy it */ - let uid = match obj.get_attr_as_string(CKA_UNIQUE_ID) { - Ok(u) => u, - Err(_) => continue, - }; - priv_uids.push(uid.clone()); - } - } - } - - /* remove all private session objects */ - for uid in priv_uids { - self.objects.remove(&uid); - } + pub fn remove(&mut self, handle: CK_OBJECT_HANDLE) -> Option { + self.map.remove(&handle) } - pub fn clear_session_objects(&mut self, handle: CK_SESSION_HANDLE) { - let mut handles: Vec = Vec::new(); - for (_, obj) in &self.objects { - if obj.get_session() == handle { - handles.push(obj.get_handle()); - } - } - - for oh in handles { - let _ = self.remove(oh, true); - } - } - - pub fn object_rough_size( - &self, - handle: CK_OBJECT_HANDLE, - ) -> KResult { - let obj = self.get_by_handle(handle)?; - let jo = storage::JsonObject::from_object(obj); - jo.rough_size() + fn next(&mut self) -> CK_OBJECT_HANDLE { + let next = self.next; + self.next += 1; + next } } @@ -243,15 +134,24 @@ pub struct Token { filename: String, object_factories: ObjectFactories, mechanisms: Mechanisms, - objects: TokenObjects, - memory_only: bool, - dirty: bool, + storage: Box, + handles: Handles, so_login: LoginData, user_login: LoginData, } impl Token { pub fn new(filename: String) -> KResult { + /* when no filename is provided we assume a memory only + * token that has no backing store */ + let store = if filename.ends_with(".json") { + storage::json::json() + } else if filename.ends_with(".sql") { + storage::sqlite::sqlite() + } else { + storage::memory::memory() + }; + let mut token: Token = Token { info: CK_TOKEN_INFO { label: TOKEN_LABEL, @@ -276,7 +176,8 @@ impl Token { filename: filename, object_factories: ObjectFactories::new(), mechanisms: Mechanisms::new(), - objects: TokenObjects::new(), + storage: store, + handles: Handles::new(), so_login: LoginData { pin: None, max_attempts: 0, @@ -289,8 +190,6 @@ impl Token { attempts: 0, logged_in: false, }, - memory_only: false, - dirty: false, }; /* register mechanisms and factories */ @@ -301,26 +200,23 @@ impl Token { hash::register(&mut token.mechanisms, &mut token.object_factories); hmac::register(&mut token.mechanisms, &mut token.object_factories); - /* when no filename is provided we assume a memory only - * token that has no backing store */ if token.filename.len() > 0 { - match storage::JsonToken::load(&token.filename) { - Ok(jt) => { - jt.to_objects(&mut token.objects)?; + match token.storage.open(&token.filename) { + Ok(()) => { token.info.flags |= CKF_TOKEN_INITIALIZED; } Err(err) => match err { KError::RvError(ref e) => { + /* empty file is legal but leaves the token uninitialized */ if e.rv != CKR_CRYPTOKI_NOT_INITIALIZED { - /* empty file is legal but leaves the token uninitialized */ return Err(err); } + token.info.flags &= !CKF_TOKEN_INITIALIZED; } _ => return Err(err), }, } } else { - token.memory_only = true; token.info.flags &= !CKF_LOGIN_REQUIRED; token.info.flags |= CKF_TOKEN_INITIALIZED; } @@ -345,11 +241,13 @@ impl Token { label: String, pin: Vec, ) -> KResult<()> { - match self.objects.get_mut(&uid) { - Some(obj) => { + match self.storage.fetch_by_uid(&uid) { + Ok(o) => { + let mut obj = o.clone(); obj.set_attr(attribute::from_bytes(CKA_VALUE, pin))?; + self.storage.store(&uid, obj)?; } - None => { + Err(_) => { let mut obj = Object::new(); obj.set_attr(attribute::from_string( CKA_UNIQUE_ID, @@ -363,7 +261,7 @@ impl Token { ))?; obj.set_attr(attribute::from_string(CKA_LABEL, label))?; obj.set_attr(attribute::from_bytes(CKA_VALUE, pin))?; - self.objects.insert(uid, obj); + self.storage.store(&uid, obj)?; } } return Ok(()); @@ -379,20 +277,19 @@ impl Token { return ret; } self.so_login.logged_in = false; - self.objects.initialize(); - self.dirty = true; + match self.storage.reinit() { + Ok(()) => { + self.handles = Handles::new(); + } + Err(_) => return CKR_GENERAL_ERROR, + } /* add pin to so_object */ match self.store_pin_object( - "0".to_string(), + SO_PIN_UID.to_string(), "SO PIN".to_string(), pin.clone(), ) { - Ok(()) => (), - Err(_) => return CKR_GENERAL_ERROR, - } - - match self.save() { Ok(_) => { self.info.flags |= CKF_TOKEN_INITIALIZED; CKR_OK @@ -413,26 +310,76 @@ impl Token { } } + fn clear_private_session_objects(&mut self) { + let mut priv_uids = Vec::::new(); + for obj in &self.storage.get_all_cached() { + if obj.is_private() { + let oh = obj.get_handle(); + if oh != CK_INVALID_HANDLE { + let _ = self.handles.remove(oh); + } + if !obj.is_token() { + /* not a token object, therefore we need to destroy it */ + if let Ok(uid) = obj.get_attr_as_string(CKA_UNIQUE_ID) { + priv_uids.push(uid.clone()); + } + } + } + } + + /* remove all private session objects */ + for uid in priv_uids { + let _ = self.storage.remove_by_uid(&uid); + } + } + + fn clear_session_objects(&mut self, handle: CK_SESSION_HANDLE) { + let mut handles: Vec = Vec::new(); + for obj in &self.storage.get_all_cached() { + if obj.get_session() == handle { + if !obj.is_token() { + handles.push(obj.get_handle()); + } + } + } + + for h in handles { + if let Some(uid) = self.handles.remove(h) { + let _ = self.storage.remove_by_uid(&uid); + } + } + } + pub fn get_object_by_handle( - &self, - handle: CK_OBJECT_HANDLE, - checks: bool, + &mut self, + o_handle: CK_OBJECT_HANDLE, ) -> KResult<&Object> { - let obj = match self.objects.get_by_handle(handle) { - Ok(o) => o, - Err(e) => return Err(e), + let is_logged_in = self.is_logged_in(KRY_UNSPEC); + let obj = match self.handles.get(o_handle) { + Some(s) => self.storage.fetch_by_uid(s)?, + None => return err_rv!(CKR_OBJECT_HANDLE_INVALID), }; - if checks && !self.is_logged_in(KRY_UNSPEC) && obj.is_private() { + if !is_logged_in && obj.is_private() { return err_rv!(CKR_USER_NOT_LOGGED_IN); } Ok(obj) } - fn validate_pin_obj( - &self, - obj: &Object, - label: String, + fn fetch_pin_data( + &mut self, + uid: &str, + label: &str, ) -> KResult<(Vec, CK_ULONG)> { + let obj = match self.storage.fetch_by_uid(&uid.to_string()) { + Ok(o) => o, + Err(e) => match e { + KError::NotFound(_) => { + return err_rv!(CKR_USER_PIN_NOT_INITIALIZED); + } + KError::RvError(e) => return err_rv!(e.rv), + _ => return err_rv!(CKR_GENERAL_ERROR), + }, + }; if obj.get_attr_as_ulong(CKA_CLASS)? != CKO_SECRET_KEY { return err_rv!(CKR_GENERAL_ERROR); } @@ -453,12 +400,7 @@ impl Token { fn get_so_login_data(&mut self) -> KResult<()> { if self.so_login.pin.is_none() { - let obj = match self.objects.get(&"0".to_string()) { - Some(o) => o, - None => return err_rv!(CKR_GENERAL_ERROR), - }; - let (pin, max) = - self.validate_pin_obj(obj, "SO PIN".to_string())?; + let (pin, max) = self.fetch_pin_data(SO_PIN_UID, "SO PIN")?; self.so_login.pin = Some(pin); self.so_login.max_attempts = max; } @@ -467,12 +409,7 @@ impl Token { fn get_user_login_data(&mut self) -> KResult<()> { if self.user_login.pin.is_none() { - let obj = match self.objects.get(&"1".to_string()) { - Some(o) => o, - None => return err_rv!(CKR_USER_PIN_NOT_INITIALIZED), - }; - let (pin, max) = - self.validate_pin_obj(obj, "User PIN".to_string())?; + let (pin, max) = self.fetch_pin_data(USER_PIN_UID, "User PIN")?; self.user_login.pin = Some(pin); self.user_login.max_attempts = max; } @@ -537,7 +474,7 @@ impl Token { return ret; } - self.objects.clear_private_session_objects(); + self.clear_private_session_objects(); CKR_OK } @@ -576,7 +513,7 @@ impl Token { } /* update pin in storage */ match self.store_pin_object( - "1".to_string(), + USER_PIN_UID.to_string(), "User PIN".to_string(), pin.clone(), ) { @@ -595,7 +532,7 @@ impl Token { } /* update pin in storage */ match self.store_pin_object( - "0".to_string(), + SO_PIN_UID.to_string(), "SO PIN".to_string(), pin.clone(), ) { @@ -609,19 +546,11 @@ impl Token { /* If we set a PIN it means we switched to require Logins */ self.info.flags |= CKF_LOGIN_REQUIRED; - self.dirty = true; - match self.save() { - Ok(()) => CKR_OK, - Err(_) => CKR_GENERAL_ERROR, - } + CKR_OK } - pub fn save(&self) -> KResult<()> { - if !self.dirty || self.memory_only { - return Ok(()); - } - let jt = storage::JsonToken::from_objects(&self.objects); - jt.save(&self.filename) + pub fn save(&mut self) -> KResult<()> { + self.storage.flush() } pub fn insert_object( @@ -638,14 +567,13 @@ impl Token { if !self.is_logged_in(KRY_UNSPEC) { return err_rv!(CKR_USER_NOT_LOGGED_IN); } - self.dirty = true; } else { obj.set_session(s_handle); } - let handle = self.objects.next_handle(); + let handle = self.handles.next(); obj.set_handle(handle); - self.objects.insert_handle(handle, uid.clone()); - self.objects.insert(uid.clone(), obj); + self.handles.insert(handle, uid.clone()); + self.storage.store(&uid, obj)?; Ok(handle) } @@ -666,12 +594,18 @@ impl Token { &mut self, o_handle: CK_OBJECT_HANDLE, ) -> KResult<()> { - let obj = self.objects.get_by_handle(o_handle)?; + let obj = match self.handles.get(o_handle) { + Some(s) => self.storage.fetch_by_uid(s)?, + None => return err_rv!(CKR_OBJECT_HANDLE_INVALID), + }; if !obj.is_destroyable() { return err_rv!(CKR_ACTION_PROHIBITED); } - self.objects.remove(o_handle, false)?; - Ok(()) + if let Some(uid) = self.handles.remove(o_handle) { + self.storage.remove_by_uid(&uid) + } else { + err_rv!(CKR_OBJECT_HANDLE_INVALID) + } } pub fn get_token_info(&self) -> &CK_TOKEN_INFO { @@ -679,41 +613,39 @@ impl Token { } pub fn get_object_attrs( - &self, - handle: CK_OBJECT_HANDLE, + &mut self, + o_handle: CK_OBJECT_HANDLE, template: &mut [CK_ATTRIBUTE], ) -> KResult<()> { - match self.get_object_by_handle(handle, true) { - Ok(o) => self.object_factories.get_object_attributes(o, template), - Err(e) => match e { - KError::RvError(e) => { - if e.rv == CKR_USER_NOT_LOGGED_IN { - err_rv!(CKR_OBJECT_HANDLE_INVALID) - } else { - err_rv!(e.rv) - } - } - _ => Err(e), - }, + let is_logged = self.is_logged_in(KRY_UNSPEC); + let obj = match self.handles.get(o_handle) { + Some(s) => self.storage.fetch_by_uid(s)?, + None => return err_rv!(CKR_OBJECT_HANDLE_INVALID), + }; + if !is_logged && obj.is_private() { + /* do not reveal if the object exists or not */ + return err_rv!(CKR_OBJECT_HANDLE_INVALID); } + self.object_factories.get_object_attributes(obj, template) } pub fn set_object_attrs( &mut self, - handle: CK_OBJECT_HANDLE, + o_handle: CK_OBJECT_HANDLE, template: &mut [CK_ATTRIBUTE], ) -> KResult<()> { - let obj = match self.objects.get_by_handle_mut(handle) { - Ok(o) => o, - Err(e) => return Err(e), + let uid = match self.handles.get(o_handle) { + Some(u) => u, + None => return err_rv!(CKR_OBJECT_HANDLE_INVALID), }; - self.object_factories.set_object_attributes(obj, template)?; - self.dirty = true; - Ok(()) + let mut obj = self.storage.fetch_by_uid(uid)?.clone(); + self.object_factories + .set_object_attributes(&mut obj, template)?; + self.storage.store(uid, obj) } pub fn drop_session_objects(&mut self, handle: CK_SESSION_HANDLE) { - self.objects.clear_session_objects(handle); + self.clear_session_objects(handle); } pub fn get_mechs_num(&self) -> usize { @@ -738,7 +670,11 @@ impl Token { &self, o_handle: CK_OBJECT_HANDLE, ) -> KResult { - self.objects.object_rough_size(o_handle) + /* no need to force fetch from storage, this is always just an estimate */ + match self.handles.get(o_handle) { + Some(s) => self.storage.get_cached_by_uid(s)?.rough_size(), + None => err_rv!(CKR_OBJECT_HANDLE_INVALID), + } } pub fn copy_object( @@ -747,7 +683,14 @@ impl Token { o_handle: CK_OBJECT_HANDLE, template: &[CK_ATTRIBUTE], ) -> KResult { - let obj = self.objects.get_by_handle(o_handle)?; + let is_logged_in = self.is_logged_in(KRY_UNSPEC); + let obj = match self.handles.get(o_handle) { + Some(s) => self.storage.fetch_by_uid(s)?, + None => return err_rv!(CKR_OBJECT_HANDLE_INVALID), + }; + if !is_logged_in && obj.is_private() { + return err_rv!(CKR_USER_NOT_LOGGED_IN); + } let newobj = self.object_factories.copy(obj, template)?; self.insert_object(s_handle, newobj) } @@ -758,8 +701,10 @@ impl Token { ) -> KResult> { let mut handles = Vec::::new(); let mut needs_handle = Vec::::new(); - for (_, o) in self.objects.iter() { - if !self.is_logged_in(KRY_UNSPEC) && o.is_private() { + let is_logged_in = self.is_logged_in(KRY_UNSPEC); + let ret = self.storage.search(template)?; + for o in ret { + if !is_logged_in && o.is_private() { continue; } @@ -770,27 +715,29 @@ impl Token { } } - if o.match_template(template) { - let oh = o.get_handle(); - if oh == CK_INVALID_HANDLE { - let uid = match o.get_attr_as_string(CKA_UNIQUE_ID) { - Ok(s) => s, - Err(_) => return err_rv!(CKR_GENERAL_ERROR), - }; - needs_handle.push(uid.clone()); - } else { - handles.push(oh); - } + let oh = o.get_handle(); + if oh == CK_INVALID_HANDLE { + let uid = match o.get_attr_as_string(CKA_UNIQUE_ID) { + Ok(s) => s, + Err(_) => return err_rv!(CKR_GENERAL_ERROR), + }; + needs_handle.push(uid.clone()); + } else { + handles.push(oh); } } while let Some(uid) = needs_handle.pop() { - let oh = self.objects.next_handle(); - let obj = match self.objects.get_mut(&uid) { - Some(o) => o, - None => continue, + /* do not return internal PIN objects */ + if uid == SO_PIN_UID || uid == USER_PIN_UID { + continue; + } + let oh = self.handles.next(); + let obj = match self.storage.get_cached_by_uid_mut(&uid) { + Ok(o) => o, + Err(_) => continue, }; obj.set_handle(oh); - self.objects.insert_handle(oh, uid); + self.handles.insert(oh, uid); handles.push(oh); } Ok(handles) diff --git a/testdata/test_aes_operations.json b/testdata/test_aes_operations.json index 7a89b97b..44121417 100644 --- a/testdata/test_aes_operations.json +++ b/testdata/test_aes_operations.json @@ -43,7 +43,6 @@ "CKA_TOKEN": true, "CKA_VALUE": "HbvrLxmrtEivhJeWJEoZ1w==" } - }, { "attributes": { "CKA_UNIQUE_ID": "1011", @@ -209,7 +208,6 @@ "CKA_TOKEN": true, "CKA_VALUE": "AAe9/Vy9YCeNzAkSAAAAAQ==" } - }, { "attributes": { "CKA_UNIQUE_ID": "1041", diff --git a/testdata/test_basic.json b/testdata/test_basic.json new file mode 100644 index 00000000..fab0c8da --- /dev/null +++ b/testdata/test_basic.json @@ -0,0 +1,91 @@ +{ + "objects": [ + { + "attributes": { + "CKA_UNIQUE_ID": "0", + "CKA_CLASS": 4, + "CKA_KEY_TYPE": 16, + "CKA_LABEL": "SO PIN", + "CKA_VALUE": "MTIzNDU2Nzg=", + "CKA_TOKEN": true + } + }, + { + "attributes": { + "CKA_UNIQUE_ID": "1", + "CKA_CLASS": 4, + "CKA_KEY_TYPE": 16, + "CKA_LABEL": "User PIN", + "CKA_VALUE": "MTIzNDU2Nzg=", + "CKA_TOKEN": true + } + }, + { + "attributes": { + "CKA_UNIQUE_ID": "2", + "CKA_CLASS": 2, + "CKA_KEY_TYPE": 0, + "CKA_DESTROYABLE": false, + "CKA_ID": "AQ==", + "CKA_LABEL": "Test RSA Key", + "CKA_MODIFIABLE": true, + "CKA_MODULUS": "AQIDBAUGBwg=", + "CKA_PRIVATE": false, + "CKA_PUBLIC_EXPONENT": "AQAB", + "CKA_TOKEN": true + } + }, + { + "attributes": { + "CKA_UNIQUE_ID": "3", + "CKA_CLASS": 3, + "CKA_KEY_TYPE": 0, + "CKA_DESTROYABLE": false, + "CKA_ID": "AQ==", + "CKA_LABEL": "Test RSA Key", + "CKA_MODIFIABLE": false, + "CKA_MODULUS": "AQIDBAUGBwg=", + "CKA_PRIVATE": true, + "CKA_SENSITIVE": true, + "CKA_EXTRACTABLE": false, + "CKA_PUBLIC_EXPONENT": "AQAB", + "CKA_PRIVATE_EXPONENT": "AQAD", + "CKA_TOKEN": true + } + }, + { + "attributes": { + "CKA_UNIQUE_ID": "4", + "CKA_CLASS": 2, + "CKA_KEY_TYPE": 3, + "CKA_DESTROYABLE": false, + "CKA_ID": "Ag==", + "CKA_LABEL": "Test EC Key", + "CKA_MODIFIABLE": true, + "CKA_PRIVATE": false, + "CKA_EC_PARAMS": "BggqhkjOPQMBBw==", + "CKA_EC_POINT": "BOaBBjTeoFaH/PYBjY7hCZOJTtdbESgdPzXZwt8YXWA6iAYamlZ0X8I6npsh0OlyTMrvYIo+JccaoUki/cROlEU=", + "CKA_TOKEN": true, + "CKA_VERIFY": true + } + }, + { + "attributes": { + "CKA_UNIQUE_ID": "5", + "CKA_CLASS": 3, + "CKA_KEY_TYPE": 3, + "CKA_DESTROYABLE": false, + "CKA_ID": "Ag==", + "CKA_LABEL": "Test EC Key", + "CKA_MODIFIABLE": false, + "CKA_PRIVATE": true, + "CKA_SENSITIVE": true, + "CKA_EXTRACTABLE": false, + "CKA_EC_PARAMS": "BggqhkjOPQMBBw==", + "CKA_VALUE": "mtoobolazGJPX6gecD57oWxvwZl02fKc7BKwixExm5M=", + "CKA_TOKEN": true, + "CKA_SIGN": true + } + } + ] +}