Skip to content

Commit

Permalink
[hsmtool] Add a SPX+ implementation for PKCS11 Elementary Files
Browse files Browse the repository at this point in the history
Create a SPHINCS+ implementation that uses key material from PKCS#11
Elementary Files (aka CKO_DATA objects).

This implementation stores key material on a secure token, and loads the
key material to perform the sphincs+ operations.  This is not as secure
as signing within an HSM security boundary, but it provides
token-protected storage for key material when an HSM-based
implementation is not available.

Signed-off-by: Chris Frantz <[email protected]>
  • Loading branch information
cfrantz committed Dec 4, 2024
1 parent dc38b30 commit 7171f28
Show file tree
Hide file tree
Showing 12 changed files with 452 additions and 20 deletions.
5 changes: 4 additions & 1 deletion sw/host/hsmtool/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ rust_library(
"src/commands/object/list.rs",
"src/commands/object/mod.rs",
"src/commands/object/read.rs",
"src/commands/object/write.rs",
"src/commands/object/show.rs",
"src/commands/object/update.rs",
"src/commands/object/write.rs",
"src/commands/rsa/decrypt.rs",
"src/commands/rsa/encrypt.rs",
"src/commands/rsa/export.rs",
Expand All @@ -44,6 +44,7 @@ rust_library(
"src/lib.rs",
"src/module.rs",
"src/profile.rs",
"src/spxef/mod.rs",
"src/util/attribute/attr.rs",
"src/util/attribute/attribute_type.rs",
"src/util/attribute/certificate_type.rs",
Expand All @@ -54,6 +55,7 @@ rust_library(
"src/util/attribute/mechanism_type.rs",
"src/util/attribute/mod.rs",
"src/util/attribute/object_class.rs",
"src/util/ef.rs",
"src/util/escape.rs",
"src/util/helper.rs",
"src/util/key/ecdsa.rs",
Expand Down Expand Up @@ -91,6 +93,7 @@ rust_library(
"@crate_index//:strum",
"@crate_index//:thiserror",
"@crate_index//:typetag",
"@crate_index//:zeroize",
"@lowrisc_serde_annotate//serde_annotate",
],
)
Expand Down
4 changes: 3 additions & 1 deletion sw/host/hsmtool/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,18 @@ impl Dispatch for Commands {
}
}

#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, Annotate)]
pub struct BasicResult {
success: bool,
#[serde(skip_serializing_if = "AttrData::is_none")]
id: AttrData,
#[serde(skip_serializing_if = "AttrData::is_none")]
label: AttrData,
#[serde(skip_serializing_if = "Option::is_none")]
#[annotate(format = block)]
value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[annotate(format = block)]
error: Option<String>,
}

Expand Down
4 changes: 4 additions & 0 deletions sw/host/hsmtool/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,8 @@ pub enum HsmError {
DerError(String),
#[error("This operation requires the acorn library")]
AcornUnavailable,
#[error("Parse error: {0}")]
ParseError(String),
#[error("Unknown application: {0}")]
UnknownApplication(String),
}
24 changes: 12 additions & 12 deletions sw/host/hsmtool/src/hsmtool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use log::LevelFilter;
use std::path::PathBuf;

use hsmtool::commands::{print_command, print_result, Commands, Dispatch, Format};
use hsmtool::module::{self, Module};
use hsmtool::module::{self, Module, SpxModule};
use hsmtool::profile::Profile;
use hsmtool::util::attribute::AttributeMap;

Expand Down Expand Up @@ -47,9 +47,8 @@ struct Args {
#[arg(long, env = "HSMTOOL_MODULE")]
module: String,

/// Path to the `acorn` shared library.
#[arg(long, env = "HSMTOOL_ACORN")]
acorn: Option<String>,
#[arg(long, env = "HSMTOOL_SPX_MODULE", help=SpxModule::HELP)]
spx_module: Option<SpxModule>,

/// HSM Token to use.
#[arg(short, long, env = "HSMTOOL_TOKEN")]
Expand Down Expand Up @@ -85,7 +84,7 @@ fn main() -> Result<()> {
.transpose()?;

// Initialize the HSM module interface.
let mut hsm = Module::initialize(&args.module, args.acorn.as_deref()).context(
let mut hsm = Module::initialize(&args.module).context(
"Loading the PKCS11 module usually depends on several environent variables. Check HSMTOOL_MODULE, SOFTHSM2_CONF or your HSM's documentation.")?;

// Initialize the list of all valid attribute types early. Disable logging
Expand All @@ -99,18 +98,19 @@ fn main() -> Result<()> {
return print_command(args.format, args.color, args.command.leaf());
}

let session = if let Some(profile) = &args.profile {
if let Some(profile) = &args.profile {
let profiles = Profile::load(&args.profiles)?;
let profile = profiles
.get(profile)
.ok_or_else(|| anyhow!("Profile {profile:?} not found."))?;
Some(hsm.connect(&profile.token, Some(profile.user), profile.pin.as_deref())?)
hsm.connect(&profile.token, Some(profile.user), profile.pin.as_deref())?;
} else if let Some(token) = &args.token {
Some(hsm.connect(token, args.user, args.pin.as_deref())?)
} else {
None
};
hsm.connect(token, args.user, args.pin.as_deref())?;
}
if let Some(spx_module) = &args.spx_module {
hsm.initialize_spx(spx_module)?;
}

let result = args.command.run(&(), &hsm, session.as_ref());
let result = args.command.run(&(), &hsm, hsm.get_session());
print_result(args.format, args.color, args.quiet, result)
}
1 change: 1 addition & 0 deletions sw/host/hsmtool/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ pub mod commands;
pub mod error;
pub mod module;
pub mod profile;
pub mod spxef;
pub mod util;
60 changes: 54 additions & 6 deletions sw/host/hsmtool/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,76 @@ use cryptoki::session::UserType;
use cryptoki::slot::Slot;
use cryptoki::types::AuthPin;
use serde::de::{Deserialize, Deserializer};
use std::rc::Rc;
use std::str::FromStr;

use crate::error::HsmError;
use crate::spxef::SpxEf;
use acorn::{Acorn, SpxInterface};

#[derive(Debug, Clone)]
pub enum SpxModule {
Acorn(String),
Pkcs11Ef,
}

impl SpxModule {
pub const HELP: &'static str =
"Type of sphincs+ module [allowed values: acorn:<libpath>, pkcs11-ef]";
}

impl FromStr for SpxModule {
type Err = HsmError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s[..6].eq_ignore_ascii_case("acorn:") {
Ok(SpxModule::Acorn(s[6..].into()))
} else if s.eq_ignore_ascii_case("pkcs11-ef") {
Ok(SpxModule::Pkcs11Ef)
} else {
Err(HsmError::ParseError(format!("unknown SpxModule {s:?}")))
}
}
}

pub struct Module {
pub pkcs11: Pkcs11,
pub session: Option<Rc<Session>>,
pub acorn: Option<Box<dyn SpxInterface>>,
pub token: Option<String>,
}

impl Module {
pub fn initialize(module: &str, acorn: Option<&str>) -> Result<Self> {
pub fn initialize(module: &str) -> Result<Self> {
let pkcs11 = Pkcs11::new(module)?;
pkcs11.initialize(CInitializeArgs::OsThreads)?;
let acorn = acorn.map(Acorn::new).transpose()?;
let acorn = acorn.map(|a| a as Box<dyn SpxInterface>);
Ok(Module {
pkcs11,
acorn,
session: None,
acorn: None,
token: None,
})
}

pub fn initialize_spx(&mut self, module: &SpxModule) -> Result<()> {
let module = match module {
SpxModule::Acorn(libpath) => Acorn::new(libpath)? as Box<dyn SpxInterface>,
SpxModule::Pkcs11Ef => {
let session = self
.session
.as_ref()
.map(Rc::clone)
.ok_or(HsmError::SessionRequired)?;
SpxEf::new(session) as Box<dyn SpxInterface>
}
};
self.acorn = Some(module);
Ok(())
}

pub fn get_session(&self) -> Option<&Session> {
self.session.as_ref().map(Rc::as_ref)
}

pub fn get_token(&self, label: &str) -> Result<Slot> {
let slots = self.pkcs11.get_slots_with_token()?;
for slot in slots {
Expand All @@ -49,7 +96,7 @@ impl Module {
token: &str,
user: Option<UserType>,
pin: Option<&str>,
) -> Result<Session> {
) -> Result<()> {
let slot = self.get_token(token)?;
let session = self.pkcs11.open_rw_session(slot)?;
if let Some(user) = user {
Expand All @@ -59,7 +106,8 @@ impl Module {
.context("Failed HSM Login")?;
}
self.token = Some(token.into());
Ok(session)
self.session = Some(Rc::new(session));
Ok(())
}
}

Expand Down
Loading

0 comments on commit 7171f28

Please sign in to comment.