use core::ffi::CStr; use core::mem; pubuse err::HwkeyError; use sys::*; use tipc::{Deserialize, Handle, Serialize, Serializer, TipcError}; use trusty_std::alloc::{TryAllocFrom, Vec};
/// A HwkeySession is a Handle. type HwkeySession = Handle;
/// Connection to the hwkey service. #[derive(Debug, Eq, PartialEq)] pubstruct Hwkey(HwkeySession);
impl Hwkey { /// Attempt to open a hwkey session. /// /// # Examples /// /// ``` /// let hwkey_session = Hwkey::open().expect("could not open hwkey session"); /// ``` /// pubfn open() -> Result<Self, TipcError> { let port =
CStr::from_bytes_with_nul(HWKEY_PORT).expect("HWKEY_PORT was not null terminated");
HwkeySession::connect(port).map(Self)
}
/// Starts a request to derive a key from a context. /// /// # Returns /// /// A [`DerivedKeyRequest`] request builder /// functionality. /// /// # Examples /// /// ``` /// let hwkey_session = Hwkey::open().expect("could not open hwkey session"); /// let request_builder = hwkey_session.derive_key_req(); /// ``` /// pubfn derive_key_req(&self) -> DerivedKeyRequest<'_> {
DerivedKeyRequest::new(&self)
}
/// Gets the keyslot data referenced by slot_id. /// /// # Arguments /// /// * `slot_id` - The name of the keyslot, must be null-terminated. /// * `keyslot_data` - The buffer into which the keyslot data will be populated. /// /// # Returns /// /// A truncated prefix of the input keyslot_data buffer that contains /// the key bytes. /// /// # Examples /// /// ``` /// let hwkey_session = Hwkey::open().expect("could not open hwkey session"); /// let buf = &mut [0u8; 2048 as usize]; /// let keyslot = CStr::from_bytes_with_nul(b"keyslot_name\0").unwrap(); /// let keyslot_data = /// hwkey_session.get_keyslot_data(keyslot, buf).expect("could not retrieve keyslot data"); /// ``` /// pubfn get_keyslot_data<'a>(
&self,
slot_id: &CStr,
keyslot_data: &'a mut [u8],
) -> Result<&'a [u8], HwkeyError> { let slot_id = slot_id.to_bytes();
// slot_id is at least one byte because of null byte; // check for empty slot_id string or empty keyslot_data if slot_id.len() <= 0 {
log::error!("slot_id cannot be an empty string"); return Err(HwkeyError::NotValid);
}
if keyslot_data.is_empty() {
log::error!("keyslot_data cannot be empty"); return Err(HwkeyError::NotValid);
}
/// Derive a versioned, device-specific key from provided context. /// /// # Arguments /// /// * `src` - The context from which the key will be derived. If /// empty, `key_buf` must be empty as well. /// * `key_buf` - The buffer into which the key will be written. If /// empty, no key will be generated and only the current versions /// may be queried. /// * `args` - Key derivation options. /// /// # Returns /// /// The DeriveResult containing information used in derivation. /// fn derive(
&self,
src: &[u8],
key_buf: &mut [u8],
args: DerivedKeyRequest,
) -> Result<DeriveResult, HwkeyError> { if src.len() == 0 && key_buf.len() != 0 {
log::error!("if key context is empty, key buffer must also be empty"); return Err(HwkeyError::NotValid);
}
/// Queries the current OS version. /// /// # Returns /// /// The current [`OsRollbackVersion`] to be incorporated /// into key derivation. /// /// # Examples /// /// ``` /// let hwkey_session = Hwkey::open().expect("could not open hwkey session"); /// let os_rollback_version = hwkey_session /// .query_current_os_version(RollbackVersionSource::RunningVersion) /// .expect("could not query version"); /// ``` pubfn query_current_os_version(
&self,
rollback_source: RollbackVersionSource,
) -> Result<OsRollbackVersion, HwkeyError> { let derive_request = self
.derive_key_req()
.rollback_version_source(rollback_source)
.os_rollback_version(OsRollbackVersion::Current); self.derive(&[], &mut [], derive_request).map(|res| res.os_rollback_version)
}
}
/// The KDF algorithm version the hwkey service will use. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pubenum KdfVersion { /// Tell the hwkey service to choose the best KDF algorithm version.
Best, /// Specify KDF version hwkey service should use.
Version(u32),
}
impl Into<u32> for KdfVersion { /// Converts a [`KdfVersion`] into an [`i32`]. fn into(self) -> u32 { matchself { Self::Best => 0, Self::Version(v) => v,
}
}
}
impl From<u32> for KdfVersion { /// Converts an [`i32`] into a [`KdfVersion`]. fn from(v: u32) -> KdfVersion { if v == 0 {
KdfVersion::Best
} else {
KdfVersion::Version(v)
}
}
}
/// the OS rollback version to be incorporated /// into the key derivation. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pubenum OsRollbackVersion { /// The latest available version will be used.
Current, /// A specific version will be used.
Version(u32),
}
impl TryInto<i32> for OsRollbackVersion { type Error = HwkeyError; /// Tries to convert a [`OsRollbackVersion`] into an [`i32`]. fn try_into(self) -> Result<i32, HwkeyError> { matchself {
OsRollbackVersion::Current => Ok(HWKEY_ROLLBACK_VERSION_CURRENT),
OsRollbackVersion::Version(version) => Ok(version.try_into()?),
}
}
}
impl TryFrom<i32> for OsRollbackVersion { type Error = HwkeyError; /// Tries to convert an [`i32`] into an [`OsRollbackVersion`]. fn try_from(v: i32) -> Result<OsRollbackVersion, HwkeyError> { match v {
HWKEY_ROLLBACK_VERSION_CURRENT => Ok(OsRollbackVersion::Current),
n => Ok(OsRollbackVersion::Version(n.try_into()?)),
}
}
}
/// Specifies whether the rollback version must /// have been committed. If /// [`RollbackVersionSource::CommittedVersion`] /// is specified, the system must guarantee that software /// with a lower rollback version cannot ever run on a future /// boot. #[derive(Copy, Clone, Debug)] pubenum RollbackVersionSource { /// Gate the derived key based on the anti-rollback counter that has been /// committed to fuses or stored. A version of Trusty with a version smaller /// than this value should never run on the device again. The latest key may /// not be available the first few times a new version of Trusty runs on the /// device, because the counter may not be committed immediately. This /// version source may not allow versions > 0 on some devices (i.e. rollback /// versions cannot be committed).
CommittedVersion, /// Gate the derived key based on the anti-rollback version in the signed /// image of Trusty that is currently running. The latest key should be /// available immediately, but the Trusty image may be rolled back on a /// future boot. Care should be taken that Trusty still works if the image is /// rolled back and access to this key is lost. Care should also be taken /// that Trusty cannot infer this key if it rolls back to a previous version. /// For example, storing the latest version of this key in Trusty’s storage /// would allow it to be retrieved after rollback.
RunningVersion,
}
impl Into<u32> for RollbackVersionSource { /// Converts a [`RollbackVersionSource`] into a [`u32`]. fn into(self) -> u32 { matchself { Self::CommittedVersion => {
hwkey_rollback_version_source_HWKEY_ROLLBACK_COMMITTED_VERSION as u32
} Self::RunningVersion => {
hwkey_rollback_version_source_HWKEY_ROLLBACK_RUNNING_VERSION as u32
}
}
}
}
/// The result of deriving a key. #[derive(Debug, Eq, PartialEq)] pubstruct DeriveResult { /// The KDF algorithm version used in key derivation. pub kdf_version: KdfVersion, /// The OS rollback version used in key derivation. pub os_rollback_version: OsRollbackVersion,
}
/// A builder for a derived key request. May /// only be created via Hwkey::derive_key_req, /// which will default to values backwards-compatible /// with the unversioned key derivation functionality /// provided by the hwkey service. pubstruct DerivedKeyRequest<'a> { /// The version of the KDF to use. /// [`KdfVersion::Best`] will be assumed, and /// the latest version will be used.
kdf_version: KdfVersion, /// If true, the derived key will be consistent and shared across the entire /// family of devices, given the same input. If false, the derived key will /// be unique to the particular device it was derived on.
shared_key: bool, /// Specifies whether the @rollback_version must have been committed. If /// [`RollbackVersionSource::CommittedVersion`] is specified, the system /// must guarantee that software with a lower rollback version cannot /// ever run on a future boot.
rollback_version_source: RollbackVersionSource, /// The OS rollback version to be incorporated into the key /// derivation. Must be less than or equal to the current Trusty OS rollback /// version from [`RollbackVersionSource`]. If set to /// [`OsRollbackVersion::Current`] the latest available version will be used /// and will be written back to the struct.
os_rollback_version: OsRollbackVersion, /// Hwkey session
session: &'a Hwkey,
}
/// Sets the KDF algorithm version used in key derivation. pubfn kdf(mutself, kdf_version: KdfVersion) -> Self { self.kdf_version = kdf_version; self
}
/// Tells derivation service to generate a shared key, /// which will be consistent and shared across the entire /// family of devices, given the same input. pubfn shared_key(mutself) -> Self { self.shared_key = true; self
}
/// Tells derivation service to generate a key which will /// be unique to the particular device it was derived on. /// This key should never be available outside of /// this device. pubfn unique_key(mutself) -> Self { self.shared_key = false; self
}
/// Sets the rollback version source used in key derivation. pubfn rollback_version_source(mutself, src: RollbackVersionSource) -> Self { self.rollback_version_source = src; self
}
/// Sets the OS rollback version used in key derivation. /// Must be less than or equal to the current Trusty rollback version /// from [`RollbackVersionSource`]. pubfn os_rollback_version(mutself, v: OsRollbackVersion) -> Self { self.os_rollback_version = v; self
}
/// Derive a versioned, device-specific key from the provided context. /// /// # Arguments /// /// * `src` - The context from which the key will be derived. If /// empty, `key_buf` must be empty as well. /// * `key_buf` - The buffer into which the key will be written. If /// empty, no key will be generated and only the current versions /// may be queried. /// /// # Returns /// /// The DeriveResult containing information used in derivation. /// /// # Examples /// /// ``` /// let hwkey_session = Hwkey::open().expect("could not open hwkey session"); /// let buf = &mut [0u8; 32 as usize]; /// let DeriveResult { kdf_version, os_rollback_version } = hwkey_session /// .derive_key_req() /// .derive(b"thirtytwo-bytes-of-nonsense-data", buf) /// .expect("could not derive key"); /// ``` /// /// ``` /// let hwkey_session = Hwkey::open().expect("could not open hwkey session"); /// let buf = &mut [0u8; 128 as usize]; /// let DeriveResult { kdf_version, os_rollback_version } = hwkey_session /// .derive_key_req() /// .unique_key() /// .kdf(KdfVersion::Best) /// .os_rollback_version(OsRollbackVersion::Current) /// .rollback_version_source(RollbackVersionSource::RunningVersion) /// .derive(b"thirtytwo-bytes-of-nonsense-data", buf) /// .expect("could not derive key"); /// ``` /// pubfn derive(self, src: &[u8], key_buf: &mut [u8]) -> Result<DeriveResult, HwkeyError> { self.session.derive(src, key_buf, self)
}
}
impl<'s> Serialize<'s> for HwkeyDeriveVersionedMsg<'s> { fn serialize<'a: 's, S: Serializer<'s>>(
&'a self,
serializer: &mut S,
) -> Result<S::Ok, S::Error> { // SAFETY: // hwkey_derive_versioned_msg.header is a fully-initialized, // repr(C) struct that outlives the Serializer lifetime. // All other serialized attributes are trivial types with // a corresponding C repr. unsafe {
serializer.serialize_as_bytes(&self.msg.header)?;
serializer.serialize_as_bytes(&self.msg.kdf_version)?;
serializer.serialize_as_bytes(&self.msg.rollback_version_source)?;
}
for rv in &self.msg.rollback_versions { unsafe {
serializer.serialize_as_bytes(rv)?;
}
}
// TODO: replace owned payload with references when // GATs are available for use in Deserialize trait #[derive(Eq, PartialEq, Debug)] struct HwkeyResponse {
kdf_version: u32,
status: u32,
cmd: u32,
payload: Vec<u8>,
}
impl Deserialize for HwkeyResponse { type Error = HwkeyError; const MAX_SERIALIZED_SIZE: usize = HWKEY_MAX_MSG_SIZE as usize; fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> { let header_size = mem::size_of::<hwkey_msg>(); if bytes.len() < header_size {
log::error!("response too small to be valid"); return Err(HwkeyError::BadLen);
} // SAFETY: We have validated that the buffer contains enough data to // represent a hwkey_msg. The constructed lifetime here does not // outlive the function and thus cannot outlive the lifetime of the // buffer. let msg = unsafe { &*(bytes.as_ptr() as *const hwkey_msg) };
// TODO: replace owned payload with references when // GATs are available for use in Deserialize trait struct HwkeyDeriveVersionedResponse {
cmd: u32,
status: u32,
os_rollback_version: i32,
kdf_version: u32,
payload: Vec<u8>,
}
impl Deserialize for HwkeyDeriveVersionedResponse { type Error = HwkeyError;
const MAX_SERIALIZED_SIZE: usize = HWKEY_MAX_MSG_SIZE as usize;
fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> { let header_size = mem::size_of::<hwkey_derive_versioned_msg>(); if bytes.len() < header_size {
log::error!("response too small to be valid"); return Err(HwkeyError::BadLen);
}
// SAFETY: We have validated that the buffer contains enough data to // represent a hwkey_derive_versioned_msg. let msg = unsafe { &*(bytes.as_ptr() as *const hwkey_derive_versioned_msg) };
// the rest of the buffer should be the key data if bytes.len() - header_size != msg.key_len as usize {
log::error!( "response payload size ({:?}) != key length ({:?})",
bytes.len() - header_size,
msg.key_len
); return Err(HwkeyError::BadLen);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.