mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-15 08:30:02 +00:00
add an emulated keystore for hosted mode
this is a dummy keystore so we can test other UX operations. the full keystore will be a lot harder to write.
This commit is contained in:
parent
1ee1239494
commit
b2f32b7b6f
6 changed files with 192 additions and 5 deletions
|
|
@ -60,6 +60,7 @@ aes = { path = "../aes" }
|
|||
byteorder = "1.4.3" # used by keywrap
|
||||
# hardware acceleration adaptations are inserted into a fork of the main branch.
|
||||
hex = { version = "0.4.3", default-features = false, features = [] }
|
||||
hkdf = "0.12.4"
|
||||
|
||||
#[dependencies.curve25519-dalek]
|
||||
#version = "=4.1.2" # note this is patched to our fork in ./Cargo.toml
|
||||
|
|
@ -77,13 +78,24 @@ cramium-soc = ["utralib/cramium-soc"]
|
|||
board-baosec = [
|
||||
"utralib/cramium-soc",
|
||||
"ux-api/board-baosec",
|
||||
"keystore-api/gen2",
|
||||
"modals/no-gam",
|
||||
] # USB form factor token
|
||||
loader-baosec = ["ux-api/loader-baosec"]
|
||||
test-baosec = ["ux-api/loader-baosec"]
|
||||
hosted-baosec = [] # emulated hardware on x86 platform
|
||||
board-baosor = ["utralib/cramium-soc"] # Precursor form factor
|
||||
hosted-baosec = [
|
||||
"keystore-api/gen2",
|
||||
"modals/no-gam",
|
||||
] # emulated hardware on x86 platform
|
||||
board-baosor = [
|
||||
"utralib/cramium-soc",
|
||||
"keystore-api/gen2",
|
||||
] # Precursor form factor
|
||||
loader-baosor = []
|
||||
board-dabao = ["utralib/cramium-soc"] # Dev board form factor
|
||||
board-dabao = [
|
||||
"utralib/cramium-soc",
|
||||
"keystore-api/gen2",
|
||||
] # Dev board form factor
|
||||
loader-dabao = []
|
||||
|
||||
policy-menu = [
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ impl Keystore {
|
|||
Message::new_blocking_scalar(Opcode::GetDna.to_usize().unwrap(), 0, 0, 0, 0),
|
||||
)
|
||||
.unwrap();
|
||||
if let xous::Result::Scalar2(val1, val2) = response {
|
||||
if let xous::Result::Scalar5(val1, val2, _, _, _) = response {
|
||||
(val1 as u64) | ((val2 as u64) << 32)
|
||||
} else {
|
||||
panic!("get_dna() failed with internal error");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use keystore_api::*;
|
||||
|
||||
mod platform;
|
||||
|
||||
fn main() -> ! {
|
||||
log_server::init_wait().unwrap();
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
|
|
@ -9,5 +11,5 @@ fn main() -> ! {
|
|||
// TODO: limit connections to this server?? once we know all that will connect
|
||||
let keys_sid = xns.register_name(SERVER_NAME_KEYS, None).expect("can't register server");
|
||||
|
||||
loop {}
|
||||
platform::keystore(keys_sid);
|
||||
}
|
||||
|
|
|
|||
9
services/keystore/src/platform.rs
Normal file
9
services/keystore/src/platform.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#[cfg(feature = "board-baosec")]
|
||||
mod baosec;
|
||||
#[cfg(feature = "board-baosec")]
|
||||
pub use baosec::*;
|
||||
|
||||
#[cfg(feature = "hosted-baosec")]
|
||||
mod hosted;
|
||||
#[cfg(feature = "hosted-baosec")]
|
||||
pub use hosted::*;
|
||||
3
services/keystore/src/platform/baosec.rs
Normal file
3
services/keystore/src/platform/baosec.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
use xous::SID;
|
||||
|
||||
pub fn keystore(sid: &SID) -> ! { loop {} }
|
||||
161
services/keystore/src/platform/hosted.rs
Normal file
161
services/keystore/src/platform/hosted.rs
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
use std::convert::TryInto;
|
||||
|
||||
use aes::Aes256;
|
||||
use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit, generic_array::GenericArray};
|
||||
use hkdf::Hkdf;
|
||||
use keystore_api::*;
|
||||
use sha2::Sha256;
|
||||
use xous::SID;
|
||||
use xous_ipc::Buffer;
|
||||
|
||||
/// Any old key for the hosted mode testing. 0 is as good a number as any other.
|
||||
const WELL_KNOWN_KEY: &'static str = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
|
||||
pub fn keystore(sid: SID) -> ! {
|
||||
let mut msg_opt = None;
|
||||
|
||||
loop {
|
||||
xous::reply_and_receive_next(sid, &mut msg_opt).unwrap();
|
||||
let msg = msg_opt.as_mut().unwrap();
|
||||
let opcode = num_traits::FromPrimitive::from_usize(msg.body.id()).unwrap_or(Opcode::InvalidCall);
|
||||
log::debug!("{:?}", opcode);
|
||||
match opcode {
|
||||
Opcode::AesOracle => {
|
||||
let mut buffer =
|
||||
unsafe { Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) };
|
||||
// as_flat saves a copy step, but we have to deserialize some enums manually
|
||||
let mut aes_op = buffer.to_original::<AesOp, _>().unwrap();
|
||||
let op = match aes_op.aes_op {
|
||||
// seems stupid, but we have to do this because we want to have zeroize on the AesOp
|
||||
// record, and it means we can't have Copy on this.
|
||||
AesOpType::Decrypt => AesOpType::Decrypt,
|
||||
AesOpType::Encrypt => AesOpType::Encrypt,
|
||||
};
|
||||
let mut ikm = [0u8; 32];
|
||||
hex::encode_to_slice(WELL_KNOWN_KEY, &mut ikm).unwrap();
|
||||
let hk = Hkdf::<Sha256>::new(None, &ikm);
|
||||
let mut okm = [0u8; 32];
|
||||
hk.expand(&aes_op.domain.as_bytes(), &mut okm)
|
||||
.expect("32 is a valid length for Sha256 to output");
|
||||
let cipher = Aes256::new(GenericArray::from_slice(&okm));
|
||||
|
||||
// deserialize the specifier
|
||||
match aes_op.block {
|
||||
AesBlockType::SingleBlock(b) => {
|
||||
match op {
|
||||
AesOpType::Decrypt => cipher.decrypt_block(&mut b.try_into().unwrap()),
|
||||
AesOpType::Encrypt => cipher.encrypt_block(&mut b.try_into().unwrap()),
|
||||
}
|
||||
aes_op.block = AesBlockType::SingleBlock(b);
|
||||
}
|
||||
AesBlockType::ParBlock(mut pb) => {
|
||||
match op {
|
||||
AesOpType::Decrypt => {
|
||||
for block in pb.iter_mut() {
|
||||
cipher.decrypt_block(block.try_into().unwrap());
|
||||
}
|
||||
}
|
||||
AesOpType::Encrypt => {
|
||||
for block in pb.iter_mut() {
|
||||
cipher.encrypt_block(block.try_into().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
aes_op.block = AesBlockType::ParBlock(pb);
|
||||
}
|
||||
};
|
||||
buffer.replace(aes_op).unwrap();
|
||||
}
|
||||
Opcode::AesKwp => {
|
||||
let mut ikm = [0u8; 32];
|
||||
hex::encode_to_slice(WELL_KNOWN_KEY, &mut ikm).unwrap();
|
||||
let mut buffer =
|
||||
unsafe { Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) };
|
||||
let mut kwp = buffer.to_original::<KeyWrapper, _>().unwrap();
|
||||
use aes_kw::Kek;
|
||||
use aes_kw::KekAes256;
|
||||
let keywrapper: KekAes256 = Kek::from(ikm);
|
||||
match kwp.op {
|
||||
KeyWrapOp::Wrap => {
|
||||
match keywrapper.wrap_with_padding_vec(&kwp.data[..kwp.len as usize]) {
|
||||
Ok(wrapped) => {
|
||||
for (&src, dst) in wrapped.iter().zip(kwp.data.iter_mut()) {
|
||||
*dst = src;
|
||||
}
|
||||
kwp.len = wrapped.len() as u32;
|
||||
kwp.result = None;
|
||||
// this is an un-used field but...why not?
|
||||
kwp.expected_len = wrapped.len() as u32;
|
||||
}
|
||||
Err(e) => {
|
||||
kwp.result = Some(match e {
|
||||
aes_kw::Error::IntegrityCheckFailed => KeywrapError::IntegrityCheckFailed,
|
||||
aes_kw::Error::InvalidDataSize => KeywrapError::InvalidDataSize,
|
||||
aes_kw::Error::InvalidKekSize { size } => {
|
||||
log::info!("invalid size {}", size); // weird. can't name this _size
|
||||
KeywrapError::InvalidKekSize
|
||||
}
|
||||
aes_kw::Error::InvalidOutputSize { expected } => {
|
||||
log::info!("invalid output size {}", expected);
|
||||
KeywrapError::InvalidOutputSize
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
KeyWrapOp::Unwrap => {
|
||||
match keywrapper.unwrap_with_padding_vec(&kwp.data[..kwp.len as usize]) {
|
||||
Ok(wrapped) => {
|
||||
for (&src, dst) in wrapped.iter().zip(kwp.data.iter_mut()) {
|
||||
*dst = src;
|
||||
}
|
||||
kwp.len = wrapped.len() as u32;
|
||||
kwp.result = None;
|
||||
// this is an un-used field but...why not?
|
||||
kwp.expected_len = wrapped.len() as u32;
|
||||
}
|
||||
Err(e) => {
|
||||
kwp.result = Some(match e {
|
||||
aes_kw::Error::IntegrityCheckFailed => KeywrapError::IntegrityCheckFailed,
|
||||
aes_kw::Error::InvalidDataSize => KeywrapError::InvalidDataSize,
|
||||
aes_kw::Error::InvalidKekSize { size } => {
|
||||
log::info!("invalid size {}", size); // weird. can't name this _size
|
||||
KeywrapError::InvalidKekSize
|
||||
}
|
||||
aes_kw::Error::InvalidOutputSize { expected } => {
|
||||
log::info!("invalid output size {}", expected);
|
||||
KeywrapError::InvalidOutputSize
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer.replace(kwp).unwrap();
|
||||
}
|
||||
Opcode::ClearPasswordCacheEntry => {
|
||||
if let Some(scalar) = msg.body.scalar_message_mut() {
|
||||
// no passwords, nothing to clear: always return success
|
||||
scalar.arg1 = 1;
|
||||
}
|
||||
}
|
||||
Opcode::EnsurePassword => {
|
||||
if let Some(scalar) = msg.body.scalar_message_mut() {
|
||||
let pws: PasswordState = PasswordState::Correct;
|
||||
(scalar.arg1, scalar.arg2, scalar.arg3) = pws.into();
|
||||
log::info!("Password is always ensured in hosted mode");
|
||||
}
|
||||
}
|
||||
Opcode::GetDna => {
|
||||
// dummy DNA value
|
||||
if let Some(scalar) = msg.body.scalar_message_mut() {
|
||||
scalar.arg1 = 0x1234_5678;
|
||||
scalar.arg2 = 0xface_cafe;
|
||||
}
|
||||
}
|
||||
Opcode::InvalidCall => {
|
||||
log::error!("Invalid call in keystore: {:?}", opcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue