//! This library implements the functionality used by the KeyMint Strongbox //! Trusty application.
use alloc::{rc::Rc, vec::Vec}; use android_system_desktop_security_gsc::aidl::android::system::desktop::security::gsc::IGsc::IGsc; use binder::Strong; use core::{cell::RefCell, fmt}; use kmr_common::{km_err, km_verr, Error, ErrorKind, ErrorLocation}; use kmr_ta::{HardwareInfo, RpcInfo, RpcInfoV3}; use kmr_wire::keymint::ErrorCode; use log::{debug, error, trace}; use tipc::{
service_dispatcher, ConnectResult, Deserialize, Handle, Manager, MessageResult, PortCfg,
Serialize, Serializer, Service, TipcError, Uuid,
}; use tpm_commands::{
TpmRequestBuildError, TpmRequestMessage, TpmResponseMessage, TpmvRequest, TpmvRequestBuild,
}; use trusty_std::alloc::TryAllocFrom; use zerocopy::{FromBytes, IntoBytes, KnownLayout, Unaligned};
use kmr_wire::legacy::{ self, AppendUdsCertificateResponse, ClearUdsCertificateResponse, TrustyMessageId,
TrustyPerformOpReq, TrustyPerformOpRsp,
};
fn log_formatter(record: &log::Record) -> String { // line number should be present, so keeping it simple by just returning a 0. let line = record.line().unwrap_or(0); let file = record.file().unwrap_or("unknown file");
format!("strongbox: {}: {}:{} {}\n", record.level(), file, line, record.args())
}
/// Main loop handler for the KeyMint TA. pubfn handle_port_connections(hw_info: HardwareInfo, rpc_info: RpcInfo) -> Result<(), Error> { let sb_ta = Rc::new(RefCell::new(StrongBox::new(hw_info, rpc_info)?));
let ns_service = KMService::new(sb_ta); let legacy_service = KMLegacyService::new();
letmut dispatcher = KMServiceDispatcher::<2>::new()
.map_err(|e| km_err!(UnknownError, "could not create multi-service dispatcher: {:?}", e))?; let cfg = PortCfg::new(KM_NS_TIPC_SRV_PORT)
.map_err(|e| {
km_err!(
UnknownError, "could not create port config for {}: {:?}",
KM_NS_TIPC_SRV_PORT,
e
)
})?
.allow_ns_connect();
dispatcher.add_service(Rc::new(ns_service), cfg).map_err(|e| {
km_err!(UnknownError, "could not add non-secure service to dispatcher: {:?}", e)
})?;
let cfg = PortCfg::new(KM_NS_LEGACY_TIPC_SRV_PORT)
.map_err(|e| {
km_err!(
UnknownError, "could not create port config for {}: {:?}",
KM_NS_LEGACY_TIPC_SRV_PORT,
e
)
})?
.allow_ta_connect()
.allow_ns_connect();
dispatcher.add_service(Rc::new(legacy_service), cfg).map_err(|e| {
km_err!(UnknownError, "could not add secure service to dispatcher: {:?}", e)
})?;
let buffer = [0u8; 4096]; let manager =
Manager::<_, _, PORT_COUNT, MAX_CONNECTION_COUNT>::new_with_dispatcher(dispatcher, buffer)
.map_err(|e| km_err!(UnknownError, "could not create service manager: {:?}", e))?;
manager
.run_event_loop()
.map_err(|e| km_err!(UnknownError, "service manager received error: {:?}", e))?;
Err(km_err!(SecureHwCommunicationFailed, "KeyMint TA handler terminated unexpectedly."))
}
/// TIPC service implementation for communication with the HAL service in Android. struct KMService {
sb_ta: Rc<RefCell<StrongBox>>,
}
impl KMService { /// Create a service implementation. fn new(sb_ta: Rc<RefCell<StrongBox>>) -> Self {
KMService { sb_ta }
}
/// Process an incoming request message, returning the response as a collection of fragments /// that are each small enough to send over the channel. fn handle_message(&self, req_data: &[u8]) -> Result<Vec<Vec<u8>>, Error> { let resp = self.sb_ta.borrow_mut().process(req_data);
kmr_ta::split_rsp(resp.as_slice(), KEYMINT_MAX_MESSAGE_CONTENT_SIZE)
}
}
impl Service for KMService { type Connection = Context; type Message = KMMessage;
fn on_message(
&self,
connection: &Self::Connection,
handle: &Handle,
msg: Self::Message,
) -> tipc::Result<MessageResult> {
trace!("KeyMint Strongbox TA: received a message from {:?}.", connection.uuid); let resp_vec = self.handle_message(&msg.0).map_err(|e| match e.kind() {
ErrorKind::Hal(_, msg) => {
log_error(format_args!("{msg} in handling the message"), e.location());
TipcError::InvalidData
}
ErrorKind::Alloc(msg) => {
log_error(format_args!("{msg} in handling the message"), e.location());
TipcError::AllocError
}
_ => TipcError::UnknownError,
})?; for resp in resp_vec {
handle.send(&KMMessage(resp))?;
}
Ok(MessageResult::MaintainConnection)
}
}
/// TIPC service implementation for communication with components outside Trusty (notably the /// bootloader and provisioning tools), using legacy (C++) message formats. struct KMLegacyService;
impl KMLegacyService { /// Create a service implementation. fn new() -> Self {
KMLegacyService
}
/// Process an incoming request message, returning the corresponding response. fn handle_message(&self, req_msg: TrustyPerformOpReq) -> Result<TrustyPerformOpRsp, Error> { let _cmd_code = req_msg.code();
fn error_from_tpm(error_code: u32) -> Error { if error_code == GSC_KEY_MAX_OPS_EXCEEDED { return km_err!(TooManyOperations, "too many operations");
}
// Check if it is a SBS error. if error_code & GSC_TAG_MASK == GSC_STRONGBOX_SUBSET_TAG { iflet Ok(cast_code) =
ErrorCode::try_from((GSC_STRONGBOX_SUBSET_TAG as i32) - (error_code as i32))
{ return km_verr!(cast_code, "converted from SBS 0x{:X}", error_code);
}
}
letmut resp_buffer = client
.transmit(req.as_bytes())
.map_err(|_| km_err!(SecureHwCommunicationFailed, "transmit"))?; let rsp = TpmResponseMessage::<[u8]>::mut_from_bytes(&mut resp_buffer)
.map_err(|_| km_err!(EncodingError, "parsing tpm response"))?; if rsp.header.error_code == 0 { let ret = GRSP::mut_from_bytes(&mut rsp.response)
.map_err(|_| km_err!(EncodingError, "parsing keymint response"))?;
ret.try_into()
} else {
Err(error_from_tpm(rsp.header.error_code.get()))
}
}
#[cfg(test)] mod tests { usesuper::*; use gsc_svc_client::GscServiceClient; use kmr_wire::keymint::*; use kmr_wire::*; use std::fmt::Write;
/// TODO drop this when it is stabilized in std.
macro_rules! assert_matches {
($first:expr, $($second:pat_param)|+ $(if $third:expr)?) => { let a = $first; if !matches!(&a, $($second)|+ $(if $third)?) {
panic!( "'{}' does not match '{}'; Got '{:?}'",
stringify!($first),
stringify!($($second)|+ $(if $third)?),
a
);
}
};
}
macro_rules! expect_eq {
($first:expr, $second:expr) => {{ let a = $first; let b = $second; if a != b {
log::error!( "line {}: '{:?}' ('{}') does not equal '{:?}' ('{}')",
line!(),
a,
stringify!($first),
b,
stringify!($second),
); false
} else { true
}
}};
}
macro_rules! expect_ge {
($first:expr, $second:expr) => {{ let a = $first; let b = $second; if a < b {
log::error!( "line {}: '{:?}' ('{}') not less than '{:?}' ('{}')",
line!(),
a,
stringify!($first),
b,
stringify!($second),
); false
} else { true
}
}};
}
macro_rules! expect_lt {
($first:expr, $second:expr) => {{ let a = $first; let b = $second; if a >= b {
log::error!( "line {}: '{:?}' ('{}') not less than '{:?}' ('{}')",
line!(),
a,
stringify!($first),
b,
stringify!($second),
); false
} else { true
}
}};
}
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.