Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Storage Layer #106

Merged
merged 3 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/codespell.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash

CODESPELL="codespell --ignore-words-list=gost,sorce,clen,ot,crate"
CODESPELL="codespell --ignore-words-list=gost,sorce,clen,ot,crate,aci"

result=0
echo "Running codespell on source code..."
Expand Down
14 changes: 10 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pkg-config = "0.3"

[dependencies]
asn1 = "0.16.2"
bimap = "0.6.3"
bitflags = "2.4.1"
cfg-if = "1.0.0"
constant_time_eq = "0.3.0"
Expand All @@ -37,7 +38,7 @@ num-integer = "0.1.45"
num-traits = "0.2.17"
once_cell = "1.18.0"
paste = "1.0.15"
rusqlite = "0.31.0"
rusqlite = { version = "0.31.0", optional = true }
serde = { version = "1.0.180", features = ["derive"] }
serde_json = "1.0.104"
serial_test = "3.1.1"
Expand All @@ -58,10 +59,15 @@ sp800_108 = []
sshkdf = []
tlskdf = []

# tese are always required, so easier to specify this way
basic = [ "aes", "hmac", "pbkdf2" ]
# Databases
jsondb = ["memorydb"]
memorydb = []
sqlitedb = ["dep:rusqlite"]

#select everythign by default
# these are always required, so easier to specify this way
basic = [ "aes", "hmac", "pbkdf2", "sqlitedb" ]

#select everything by default
# Use --no-default-features --features basic, xxx for custom selections
default = [ "basic", "ecc", "eddsa", "hash", "hkdf", "rsa", "sp800_108", "sshkdf", "tlskdf"]

Expand Down
123 changes: 83 additions & 40 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub struct Slot {
impl Slot {
pub fn new() -> Slot {
Slot {
slot: 0,
slot: u32::MAX,
description: None,
manufacturer: None,
dbtype: None,
Expand All @@ -48,7 +48,7 @@ impl Slot {
#[cfg(test)]
pub fn with_db(dbtype: &str, dbpath: Option<String>) -> Slot {
Slot {
slot: 0,
slot: u32::MAX,
description: None,
manufacturer: None,
dbtype: Some(dbtype.to_string()),
Expand All @@ -71,17 +71,18 @@ impl Config {
Config { slots: Vec::new() }
}

#[cfg(test)]
pub fn add_slot(&mut self, slot: Slot) -> Result<()> {
for s in &self.slots {
if slot.slot == s.slot {
if slot.slot == u32::MAX || slot.slot == s.slot {
return Err(interface::KRR_SLOT_CONFIG)?;
}
}
self.slots.push(slot);
Ok(())
}

pub fn find_conf() -> Result<String> {
fn find_conf() -> Result<String> {
/* First check for our own env var,
* this has the highest precedence */
match env::var("KRYOPTIC_CONF") {
Expand Down Expand Up @@ -110,82 +111,124 @@ impl Config {
}
}

pub fn from_file(filename: &str) -> Result<Config> {
fn from_file(filename: &str) -> Result<Config> {
let config_str = fs::read_to_string(filename)?;
let conf: Config = toml::from_str(&config_str).map_err(config_error)?;
Ok(conf)
}

pub fn from_legacy_conf_string(name: &str) -> Result<Config> {
fn from_legacy_conf_string(name: &str) -> Result<Config> {
let mut conf = Config { slots: Vec::new() };
/* backwards compatibility where we used to only specify
* a file, this does not support all older options, just
* the more common one of specifying a .sql file with no
* slot specification. */
if name.ends_with(".sql") {
match storage::name_to_type(name) {
match storage::suffix_to_type(name) {
Ok(typ_) => {
let mut slot = Slot::new();
slot.dbtype = Some(typ_.to_string());
slot.dbpath = Some(name.to_string());
/* if this fails there will be no slots defined */
let _ = conf.add_slot(slot);
let _ = conf.slots.push(slot);
}
Err(_) => (),
}
}
return Ok(conf);
Ok(conf)
}

fn fix_slot_numbers(&mut self) {
let mut slotnum: u32 = 0;
/* if there are any slot missing a valid slot number
* we are going to allocate slots numbers after the highest
* properly configured one. Note that the config file format
* requires slot numbers, so this generally happens for legacy
* or init args configurations only, ie a single slot */
let mut missing = false;
for slot in &self.slots {
if slot.slot != u32::MAX {
if slotnum <= slot.slot {
simo5 marked this conversation as resolved.
Show resolved Hide resolved
slotnum = slot.slot + 1;
}
} else {
missing = true;
}
}
if missing {
for slot in &mut self.slots {
if slot.slot == u32::MAX {
slot.slot = slotnum;
slotnum += 1;
}
}
}
}

pub fn default_config() -> Result<Config> {
let filename = Self::find_conf()?;

match Self::from_file(&filename) {
Ok(conf) => return Ok(conf),
Err(e) => {
/* attempt fallback, return original error on fail */
match Self::from_legacy_conf_string(&filename) {
Ok(mut conf) => {
conf.fix_slot_numbers();
return Ok(conf);
}
Err(_) => return Err(e),
}
}
}
}

pub fn from_init_args(&mut self, args: &str) -> Result<()> {
let assign_slot: bool;
let mut conf = if args.starts_with("kryoptic_conf=") {
assign_slot = false;
let conf = if args.starts_with("kryoptic_conf=") {
let comps: Vec<&str> = args.splitn(2, '=').collect();
Self::from_file(comps[1])?
} else {
assign_slot = true;
Self::from_legacy_conf_string(args)?
};

if assign_slot {
/* check if it has already been loaded */
for s in &self.slots {
if s.dbtype.as_deref() == conf.slots[0].dbtype.as_deref()
&& s.dbpath.as_deref() == conf.slots[0].dbpath.as_deref()
{
conf.slots[0].slot = s.slot;
}
}
}

/* check and add slots */
for mut slot in conf.slots {
let mut slotnum: u32 = 0;
let mut found = false;
/* check if it has already been loaded */
for s in &self.slots {
if assign_slot {
if slotnum <= s.slot {
slotnum += s.slot + 1;
}
} else if s.slot == slot.slot {
if s.dbtype.as_deref() != slot.dbtype.as_deref() {
return Err(interface::CKR_ARGUMENTS_BAD)?;
if slot.slot == u32::MAX {
if s.dbtype.as_deref() == slot.dbtype.as_deref()
&& s.dbpath.as_deref() == slot.dbpath.as_deref()
{
/* already loaded so we just match the slot number */
found = true;
slot.slot = s.slot;
}
if s.dbpath.as_deref() != slot.dbpath.as_deref() {
return Err(interface::CKR_ARGUMENTS_BAD)?;
} else {
if slot.slot != s.slot {
if s.dbtype.as_deref() == slot.dbtype.as_deref()
&& s.dbpath.as_deref() == slot.dbpath.as_deref()
{
/* already loaded in a different slot, fail! */
return Err(interface::CKR_ARGUMENTS_BAD)?;
}
} else {
if s.dbtype.as_deref() != slot.dbtype.as_deref() {
return Err(interface::CKR_ARGUMENTS_BAD)?;
}
if s.dbpath.as_deref() != slot.dbpath.as_deref() {
return Err(interface::CKR_ARGUMENTS_BAD)?;
}
/* already present skip adding */
found = true;
}
/* already present skip adding */
found = true;
}
}
if assign_slot {
slot.slot = slotnum;
}
if !found {
self.add_slot(slot)?;
self.slots.push(slot);
}
}
self.fix_slot_numbers();
Ok(())
}
}
78 changes: 42 additions & 36 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,35 +390,18 @@ struct GlobalConfig {
conf: Config,
}

impl GlobalConfig {
fn empty_config() -> GlobalConfig {
GlobalConfig {
conf: Config::new(),
}
}

fn default_config() -> GlobalConfig {
/* if there is no config file we get an empty config */
let filename = match Config::find_conf() {
Ok(f) => f,
Err(_) => return Self::empty_config(),
};
/* if the file is not accessible or malformed we set an empty config,
* an error will be returned later at fn_initialize() time */
let conf = if let Ok(c) = Config::from_file(&filename) {
c
} else if let Ok(c) = Config::from_legacy_conf_string(&filename) {
c
} else {
return Self::empty_config();
};

GlobalConfig { conf: conf }
}
}

static CONFIG: Lazy<RwLock<GlobalConfig>> =
Lazy::new(|| RwLock::new(GlobalConfig::default_config()));
static CONFIG: Lazy<RwLock<GlobalConfig>> = Lazy::new(|| {
/* if there is no config file or the configuration is malformed,
* set an empty config, an error will be returned later at
* fn_initialize() time */
let global_conf = GlobalConfig {
conf: match Config::default_config() {
Ok(conf) => conf,
Err(_) => Config::new(),
},
};
RwLock::new(global_conf)
});

extern "C" fn fn_initialize(_init_args: CK_VOID_PTR) -> CK_RV {
let mut gconf = global_wlock!(noinitcheck CONFIG);
Expand Down Expand Up @@ -463,7 +446,12 @@ extern "C" fn fn_initialize(_init_args: CK_VOID_PTR) -> CK_RV {

#[cfg(test)]
fn force_load_config() -> CK_RV {
let testconf = GlobalConfig::default_config();
let testconf = GlobalConfig {
conf: match Config::default_config() {
Ok(conf) => conf,
Err(e) => return e.rv(),
},
};
if testconf.conf.slots.len() == 0 {
return CKR_GENERAL_ERROR;
}
Expand Down Expand Up @@ -537,7 +525,7 @@ extern "C" fn fn_init_token(
if res_or_ret!(rstate.has_sessions(slot_id)) {
return CKR_SESSION_EXISTS;
}
let vpin: Vec<u8> = bytes_to_vec!(pin, pin_len);
let vpin = bytes_to_slice!(pin, pin_len, u8);
let vlabel: Vec<u8> = if label.is_null() {
vec![0x20u8; 32]
} else {
Expand Down Expand Up @@ -565,7 +553,7 @@ extern "C" fn fn_init_pin(
return CKR_USER_NOT_LOGGED_IN;
}

let vpin: Vec<u8> = bytes_to_vec!(pin, pin_len);
let vpin = bytes_to_slice!(pin, pin_len, u8);

ret_to_rv!(token.set_pin(CKU_USER, &vpin, &vec![0u8; 0]))
}
Expand All @@ -581,12 +569,30 @@ extern "C" fn fn_set_pin(
if !session.is_writable() {
return CKR_SESSION_READ_ONLY;
}
let vpin: Vec<u8> = bytes_to_vec!(new_pin, new_len);
let vold: Vec<u8> = bytes_to_vec!(old_pin, old_len);
let vpin = bytes_to_slice!(new_pin, new_len, u8);
let vold = bytes_to_slice!(old_pin, old_len, u8);

if vpin.len() == 0 || vold.len() == 0 {
return CKR_PIN_INVALID;
}

let slot_id = session.get_slot_id();
let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id));
ret_to_rv!(token.set_pin(CK_UNAVAILABLE_INFORMATION, &vpin, &vold))
let do_logout = if token.is_logged_in(KRY_UNSPEC) {
false
} else {
ok_or_ret!(token.login(CKU_USER, &vold));
true
};

let ret =
ret_to_rv!(token.set_pin(CK_UNAVAILABLE_INFORMATION, &vpin, &vold));

if do_logout {
let _ = token.logout();
}

ret
}
extern "C" fn fn_open_session(
slot_id: CK_SLOT_ID,
Expand Down Expand Up @@ -673,7 +679,7 @@ extern "C" fn fn_login(
return CKR_SESSION_READ_ONLY_EXISTS;
}
}
let vpin: Vec<u8> = bytes_to_vec!(pin, pin_len);
let vpin = bytes_to_slice!(pin, pin_len, u8);
let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id));
if user_type == CKU_CONTEXT_SPECIFIC {
let session = res_or_ret!(rstate.get_session_mut(s_handle));
Expand Down
1 change: 1 addition & 0 deletions src/pkcs11/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub const KRA_SERIAL_NUMBER: CK_ATTRIBUTE_TYPE = KRY_VENDOR_OFFSET + 6;
/* Errors */
pub const KRR_TOKEN_NOT_INITIALIZED: CK_ULONG = KRY_VENDOR_OFFSET + 1;
pub const KRR_SLOT_CONFIG: CK_ULONG = KRY_VENDOR_OFFSET + 2;
pub const KRR_CONFIG_ERROR: CK_ULONG = KRY_VENDOR_OFFSET + 3;

pub const KRY_UNSPEC: CK_ULONG = CK_UNAVAILABLE_INFORMATION;

Expand Down
Loading