use super::{Object, Payload, WrappedObject, DEFAULT_AUTHENTICATION_KEY_LABEL};
use crate::{
authentication::{self, DEFAULT_AUTHENTICATION_KEY_ID},
mockhsm::{Error, ErrorKind},
object::{Handle, Id, Info, Label, Origin, Type},
serialization::{deserialize, serialize},
wrap, Algorithm, Capability, Domain,
};
use aes::cipher::consts::{U13, U8};
use ccm::aead::{AeadInPlace, KeyInit};
use std::collections::{btree_map::Iter as MapIter, BTreeMap as Map};
pub(crate) type Aes128Ccm = ccm::Ccm<aes::Aes128, U8, U13>;
pub(crate) type Aes256Ccm = ccm::Ccm<aes::Aes256, U8, U13>;
#[allow(clippy::large_enum_variant)]
pub(crate) enum AesCcmKey {
Aes128Ccm(Aes128Ccm),
Aes256Ccm(Aes256Ccm),
}
impl AesCcmKey {
#[allow(clippy::ptr_arg)]
pub fn encrypt_in_place(
&self,
nonce: &wrap::Nonce,
associated_data: &[u8],
buffer: &mut Vec<u8>,
) -> Result<(), Error> {
match self {
AesCcmKey::Aes128Ccm(ccm) => {
ccm.encrypt_in_place(&nonce.0.into(), associated_data, buffer)
}
AesCcmKey::Aes256Ccm(ccm) => {
ccm.encrypt_in_place(&nonce.0.into(), associated_data, buffer)
}
}
.map_err(|_| format_err!(ErrorKind::CryptoError, "error encrypting wrapped object!").into())
}
#[allow(clippy::ptr_arg)]
pub fn decrypt_in_place(
&self,
nonce: &wrap::Nonce,
associated_data: &[u8],
buffer: &mut Vec<u8>,
) -> Result<(), Error> {
match self {
AesCcmKey::Aes128Ccm(ccm) => {
ccm.decrypt_in_place(&nonce.0.into(), associated_data, buffer)
}
AesCcmKey::Aes256Ccm(ccm) => {
ccm.decrypt_in_place(&nonce.0.into(), associated_data, buffer)
}
}
.map_err(|_| format_err!(ErrorKind::CryptoError, "error decrypting wrapped object!").into())
}
}
#[derive(Debug)]
pub(crate) struct Objects(Map<Handle, Object>);
impl Default for Objects {
fn default() -> Self {
let mut objects = Map::new();
let authentication_key_handle =
Handle::new(DEFAULT_AUTHENTICATION_KEY_ID, Type::AuthenticationKey);
let authentication_key_info = Info {
object_id: DEFAULT_AUTHENTICATION_KEY_ID,
object_type: Type::AuthenticationKey,
algorithm: Algorithm::Authentication(authentication::Algorithm::YubicoAes),
capabilities: Capability::all(),
delegated_capabilities: Capability::all(),
domains: Domain::all(),
length: authentication::key::SIZE as u16,
sequence: 1,
origin: Origin::Imported,
label: DEFAULT_AUTHENTICATION_KEY_LABEL.into(),
};
let authentication_key_payload = Payload::AuthenticationKey(authentication::Key::default());
let _ = objects.insert(
authentication_key_handle,
Object {
object_info: authentication_key_info,
payload: authentication_key_payload,
},
);
Objects(objects)
}
}
impl Objects {
pub fn generate(
&mut self,
object_id: Id,
object_type: Type,
algorithm: Algorithm,
label: Label,
capabilities: Capability,
delegated_capabilities: Capability,
domains: Domain,
) {
let payload = Payload::generate(algorithm);
let length = payload.len();
let object_info = Info {
object_id,
object_type,
algorithm,
capabilities,
delegated_capabilities,
domains,
length,
sequence: 1,
origin: Origin::Generated,
label,
};
let handle = Handle::new(object_id, object_type);
let object = Object {
object_info,
payload,
};
assert!(self.0.insert(handle, object).is_none());
}
pub fn get(&self, object_id: Id, object_type: Type) -> Option<&Object> {
self.0.get(&Handle::new(object_id, object_type))
}
pub fn put(
&mut self,
object_id: Id,
object_type: Type,
algorithm: Algorithm,
label: Label,
capabilities: Capability,
delegated_capabilities: Capability,
domains: Domain,
data: &[u8],
) {
let payload = Payload::new(algorithm, data);
let length = payload.len();
let object_info = Info {
object_id,
object_type,
algorithm,
capabilities,
delegated_capabilities,
domains,
length,
sequence: 1,
origin: Origin::Imported,
label,
};
let handle = Handle::new(object_id, object_type);
let object = Object {
object_info,
payload,
};
assert!(self.0.insert(handle, object).is_none());
}
pub fn remove(&mut self, object_id: Id, object_type: Type) -> Option<Object> {
self.0.remove(&Handle::new(object_id, object_type))
}
pub fn wrap_obj(
&mut self,
wrap_key_id: Id,
object_id: Id,
object_type: Type,
nonce: &wrap::Nonce,
) -> Result<Vec<u8>, Error> {
let wrap_key = self.get_wrap_key(wrap_key_id)?;
let object_to_wrap = match self.get(object_id, object_type) {
Some(o) => o,
None => fail!(
ErrorKind::ObjectNotFound,
"no such {:?} object: {:?}",
object_type,
object_id
),
};
if !object_to_wrap
.object_info
.capabilities
.contains(Capability::EXPORTABLE_UNDER_WRAP)
{
fail!(
ErrorKind::AccessDenied,
"object {:?} of type {:?} does not have EXPORT_UNDER_WRAP capability",
object_id,
object_type
);
}
let mut object_info = object_to_wrap.object_info.clone();
match object_info.origin {
Origin::Generated => object_info.origin = Origin::WrappedGenerated,
Origin::Imported => object_info.origin = Origin::WrappedImported,
Origin::WrappedGenerated | Origin::WrappedImported => (),
}
let mut wrapped_object = serialize(&WrappedObject {
object_info,
data: object_to_wrap.payload.to_bytes(),
})
.unwrap();
wrap_key
.encrypt_in_place(nonce, b"", &mut wrapped_object)
.unwrap();
Ok(wrapped_object)
}
pub fn unwrap_obj<V: Into<Vec<u8>>>(
&mut self,
wrap_key_id: Id,
nonce: &wrap::Nonce,
ciphertext: V,
) -> Result<Handle, Error> {
let wrap_key = self.get_wrap_key(wrap_key_id)?;
let mut wrapped_data: Vec<u8> = ciphertext.into();
wrap_key.decrypt_in_place(nonce, b"", &mut wrapped_data)?;
let unwrapped_object: WrappedObject = deserialize(&wrapped_data).unwrap();
let payload = Payload::new(
unwrapped_object.object_info.algorithm,
&unwrapped_object.data,
);
let object_key = Handle::new(
unwrapped_object.object_info.object_id,
unwrapped_object.object_info.object_type,
);
let object = Object {
object_info: unwrapped_object.object_info,
payload,
};
assert!(self.0.insert(object_key.clone(), object).is_none());
Ok(object_key)
}
pub fn iter(&self) -> Iter<'_> {
self.0.iter()
}
fn get_wrap_key(&self, wrap_key_id: Id) -> Result<AesCcmKey, Error> {
let wrap_key = match self.get(wrap_key_id, Type::WrapKey) {
Some(k) => k,
None => fail!(
ErrorKind::ObjectNotFound,
"no such wrap key: {:?}",
wrap_key_id
),
};
match wrap_key.algorithm().wrap().unwrap() {
wrap::Algorithm::Aes128Ccm => Ok(AesCcmKey::Aes128Ccm(
Aes128Ccm::new_from_slice(&wrap_key.payload.to_bytes()).unwrap(),
)),
wrap::Algorithm::Aes256Ccm => Ok(AesCcmKey::Aes256Ccm(
Aes256Ccm::new_from_slice(&wrap_key.payload.to_bytes()).unwrap(),
)),
unsupported => fail!(
ErrorKind::UnsupportedAlgorithm,
"unsupported wrap key algorithm: {:?}",
unsupported
),
}
}
}
pub(crate) type Iter<'a> = MapIter<'a, Handle, Object>;