Skip to content

Commit

Permalink
Fix memory and json storage
Browse files Browse the repository at this point in the history
Change these two databases to properly handle the move of token and user
info out of the database objects space.

Signed-off-by: Simo Sorce <[email protected]>
  • Loading branch information
simo5 committed Dec 11, 2024
1 parent 332e11f commit b09c082
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 27 deletions.
1 change: 1 addition & 0 deletions src/storage/aci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ fn decrypt_data(

const MAX_LOGIN_ATTEMPTS: CK_ULONG = 10;

#[derive(Clone, Debug)]
pub struct StorageAuthInfo {
pub default_pin: bool,
pub user_data: Option<Vec<u8>>,
Expand Down
4 changes: 2 additions & 2 deletions src/storage/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ fn checked_pin(pin: &[u8]) -> &[u8] {
pin
}

const SO_ID: &str = "SO";
const USER_ID: &str = "USER";
pub const SO_ID: &str = "SO";
pub const USER_ID: &str = "USER";

fn get_pin_uid(user_type: CK_USER_TYPE) -> Result<&'static str> {
match user_type {
Expand Down
26 changes: 19 additions & 7 deletions src/storage/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
use crate::error::Result;
use crate::interface::*;
use crate::object::Object;
use crate::storage::aci::StorageACI;
use crate::storage::format::{StdStorageFormat, StorageRaw};
use crate::storage::aci;
use crate::storage::format;
use crate::storage::{memory, Storage, StorageDBInfo, StorageTokenInfo};

mod objects {
Expand All @@ -16,10 +16,10 @@ use objects::*;
#[derive(Debug)]
pub struct JsonStorage {
filename: String,
cache: Box<dyn StorageRaw>,
cache: Box<dyn format::StorageRaw>,
}

impl StorageRaw for JsonStorage {
impl format::StorageRaw for JsonStorage {
fn is_initialized(&self) -> Result<()> {
self.cache.is_initialized()
}
Expand Down Expand Up @@ -57,7 +57,19 @@ impl StorageRaw for JsonStorage {
self.cache.fetch_token_info()
}
fn store_token_info(&mut self, info: &StorageTokenInfo) -> Result<()> {
self.cache.store_token_info(info)
self.cache.store_token_info(info)?;
self.flush()
}
fn fetch_user(&self, uid: &str) -> Result<aci::StorageAuthInfo> {
self.cache.fetch_user(uid)
}
fn store_user(
&mut self,
uid: &str,
data: &aci::StorageAuthInfo,
) -> Result<()> {
self.cache.store_user(uid, data)?;
self.flush()
}
}

Expand All @@ -75,9 +87,9 @@ impl StorageDBInfo for JsonDBInfo {
},
cache: memory::raw_store(),
});
Ok(Box::new(StdStorageFormat::new(
Ok(Box::new(format::StdStorageFormat::new(
raw_store,
StorageACI::new(true),
aci::StorageACI::new(true),
)))
}

Expand Down
132 changes: 124 additions & 8 deletions src/storage/json_objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ use crate::attribute::string_to_ck_date;
use crate::attribute::{AttrType, Attribute};
use crate::error::{Error, Result};
use crate::interface::*;
use crate::misc::copy_sized_string;
use crate::object::Object;
use crate::storage::format::StorageRaw;
use crate::storage::aci;
use crate::storage::format;
use crate::storage::StorageTokenInfo;

use data_encoding::BASE64;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -56,11 +59,42 @@ impl JsonObject {
}
jo
}
fn from_user(uid: &str, info: &aci::StorageAuthInfo) -> JsonObject {
let mut ju = JsonObject {
attributes: Map::new(),
};
ju.attributes
.insert("name".to_string(), Value::String(uid.to_string()));
ju.attributes
.insert("default_pin".to_string(), Value::Bool(info.default_pin));
ju.attributes.insert(
"attempts".to_string(),
Value::Number(Number::from(info.cur_attempts)),
);
if let Some(data) = &info.user_data {
ju.attributes.insert(
"data".to_string(),
Value::String(BASE64.encode(data.as_slice())),
);
}
ju
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct JsonTokenInfo {
label: String,
manufacturer: String,
model: String,
serial: String,
flags: CK_ULONG,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct JsonObjects {
objects: Vec<JsonObject>,
users: Option<Vec<JsonObject>>,
token: Option<JsonTokenInfo>,
}

impl JsonObjects {
Expand All @@ -71,7 +105,69 @@ impl JsonObjects {
}
}

pub fn prime_store(&self, store: &mut Box<dyn StorageRaw>) -> Result<()> {
pub fn prime_store(
&self,
store: &mut Box<dyn format::StorageRaw>,
) -> Result<()> {
if let Some(t) = &self.token {
let mut info = StorageTokenInfo {
label: [0; 32],
manufacturer: [0; 32],
model: [0; 16],
serial: [0; 16],
flags: 0,
};
copy_sized_string(t.label.as_bytes(), &mut info.label);
copy_sized_string(
t.manufacturer.as_bytes(),
&mut info.manufacturer,
);
copy_sized_string(t.model.as_bytes(), &mut info.model);
copy_sized_string(t.serial.as_bytes(), &mut info.serial);
info.flags = t.flags;
store.store_token_info(&info)?;
}
if let Some(users) = &self.users {
for ju in users {
let mut uid = String::new();
let mut info = aci::StorageAuthInfo::default();
for (key, val) in &ju.attributes {
match key.as_str() {
"name" => match val.as_str() {
Some(s) => uid.push_str(s),
None => return Err(CKR_DEVICE_ERROR)?,
},
"default_pin" => match val.as_bool() {
Some(b) => info.default_pin = b,
None => return Err(CKR_DEVICE_ERROR)?,
},
"attempts" => match val.as_u64() {
Some(u) => {
info.cur_attempts = CK_ULONG::try_from(u)?
}
None => return Err(CKR_DEVICE_ERROR)?,
},
"data" => match val.as_str() {
Some(s) => {
let len = match BASE64.decode_len(s.len()) {
Ok(l) => l,
Err(_) => return Err(CKR_DEVICE_ERROR)?,
};
let mut v = vec![0; len];
match BASE64.decode_mut(s.as_bytes(), &mut v) {
Ok(l) => v.resize(l, 0),
Err(_) => return Err(CKR_DEVICE_ERROR)?,
}
info.user_data = Some(v);
}
None => return Err(CKR_DEVICE_ERROR)?,
},
_ => (), /* ignore unknown */
}
}
store.store_user(uid.as_str(), &info)?;
}
}
for jo in &self.objects {
let mut obj = Object::new();
for (key, val) in &jo.attributes {
Expand Down Expand Up @@ -127,19 +223,39 @@ impl JsonObjects {
Ok(())
}

pub fn from_store(store: &mut Box<dyn StorageRaw>) -> JsonObjects {
pub fn from_store(store: &mut Box<dyn format::StorageRaw>) -> JsonObjects {
let objs = store.search(&[]).unwrap();
let mut jt = JsonObjects {
objects: Vec::with_capacity(objs.len()),
};
let mut jobjs = Vec::with_capacity(objs.len());
for o in objs {
if !o.is_token() {
continue;
}
jt.objects.push(JsonObject::from_object(&o));
jobjs.push(JsonObject::from_object(&o));
}

let info = store.fetch_token_info().unwrap();
let jtoken = JsonTokenInfo {
label: String::from_utf8(info.label.to_vec()).unwrap(),
manufacturer: String::from_utf8(info.manufacturer.to_vec())
.unwrap(),
model: String::from_utf8(info.model.to_vec()).unwrap(),
serial: String::from_utf8(info.serial.to_vec()).unwrap(),
flags: info.flags,
};

let mut jusers = Vec::new();
for id in [format::SO_ID, format::USER_ID] {
match store.fetch_user(id) {
Ok(u) => jusers.push(JsonObject::from_user(id, &u)),
Err(_) => (),
}
}

jt
JsonObjects {
objects: jobjs,
users: Some(jusers),
token: Some(jtoken),
}
}

pub fn save(&self, filename: &str) -> Result<()> {
Expand Down
35 changes: 26 additions & 9 deletions src/storage/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,23 @@
use std::collections::HashMap;
use std::fmt::Debug;

use crate::attribute::Attribute;
use crate::error::{Error, Result};
use crate::interface::*;
use crate::misc::copy_sized_string;
use crate::object::Object;
use crate::storage::aci::StorageACI;
use crate::storage::format::{StdStorageFormat, StorageRaw};
use crate::storage::aci;
use crate::storage::format;
use crate::storage::{Storage, StorageDBInfo, StorageTokenInfo};

#[derive(Debug)]
struct MemoryStorage {
objects: HashMap<String, Object>,
token_info: StorageTokenInfo,
users: HashMap<String, aci::StorageAuthInfo>,
}

impl StorageRaw for MemoryStorage {
impl format::StorageRaw for MemoryStorage {
fn is_initialized(&self) -> Result<()> {
if self.objects.len() != 0 {
if self.token_info.flags & CKF_TOKEN_INITIALIZED != 0 {
Ok(())
} else {
Err(CKR_CRYPTOKI_NOT_INITIALIZED)?
Expand Down Expand Up @@ -75,13 +74,31 @@ impl StorageRaw for MemoryStorage {
self.token_info.model = info.model;
self.token_info.serial = info.serial;
self.token_info.flags = info.flags;
Ok(())
}

fn fetch_user(&self, uid: &str) -> Result<aci::StorageAuthInfo> {
match self.users.get(uid) {
Some(u) => Ok(u.clone()),
None => Err(CKR_USER_PIN_NOT_INITIALIZED)?,
}
}

fn store_user(
&mut self,
uid: &str,
data: &aci::StorageAuthInfo,
) -> Result<()> {
self.users.insert(uid.to_string(), data.clone());
Ok(())
}
}

pub fn raw_store() -> Box<dyn StorageRaw> {
pub fn raw_store() -> Box<dyn format::StorageRaw> {
Box::new(MemoryStorage {
objects: HashMap::new(),
token_info: StorageTokenInfo::default(),
users: HashMap::new(),
})
}

Expand All @@ -100,9 +117,9 @@ impl StorageDBInfo for MemoryDBInfo {
None => false,
};
let raw_store = raw_store();
Ok(Box::new(StdStorageFormat::new(
Ok(Box::new(format::StdStorageFormat::new(
raw_store,
StorageACI::new(encrypt),
aci::StorageACI::new(encrypt),
)))
}

Expand Down
3 changes: 2 additions & 1 deletion src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const TOKEN_MODEL: &str = "FIPS-140-3 v1";
#[cfg(not(feature = "fips"))]
const TOKEN_MODEL: &str = "v1";

#[derive(Clone, Debug)]
pub struct StorageTokenInfo {
pub label: [CK_UTF8CHAR; 32usize],
pub manufacturer: [CK_UTF8CHAR; 32usize],
Expand Down Expand Up @@ -105,7 +106,7 @@ pub trait Storage: Debug + Send + Sync {
) -> Result<()>;
}

mod aci;
pub mod aci;
pub mod format;

#[cfg(feature = "jsondb")]
Expand Down

0 comments on commit b09c082

Please sign in to comment.