// Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Types and macros for communication between HAL and TA // Allow missing docs in this crate as the types here are generally 1:1 with the HAL // interface definitions. #![allow(missing_docs)] #![no_std] extern crate alloc; use crate::cbor::{cbor_type_error, AsCborValue, CborError}; use alloc::{vec, vec::Vec}; use authgraph_derive::AsCborValue; use ciborium::value::Value; use enumn::N; pub mod cbor; pub mod fragmentation; #[cfg(test)] mod tests; /// Length of a session identifier in bytes pub const SESSION_ID_LEN: usize = 32; // Request/Response pairs corresponding to each of the methods on the `IAuthGraphKeyExchange` // interface. Structures that have a single field containing CBOR-encoded data are directly // expanded. #[derive(Debug, Clone, PartialEq, Eq, AsCborValue)] pub struct CreateRequest {} #[derive(Debug, Clone, PartialEq, Eq, AsCborValue)] pub struct CreateResponse { pub ret: SessionInitiationInfo, } #[derive(Debug, Clone, PartialEq, Eq, AsCborValue)] pub struct InitRequest { // Note that the AIDL definition for this field has type `PubKey`, which allows either a // `PlainPubKey` or a `SignedPubKey`, to allow for re-used in identity chains. However, only // the `PlainPubKey` variant appears here. pub peer_pub_key: Vec, // PlainPubKey.cddl pub peer_id: Vec, // Identity.cddl pub peer_nonce: Vec, pub peer_version: i32, } #[derive(Debug, Clone, PartialEq, Eq, AsCborValue)] pub struct InitResponse { pub ret: KeInitResult, } #[derive(Debug, Clone, PartialEq, Eq, AsCborValue)] pub struct FinishRequest { // Note that the AIDL definition for this field has type `PubKey`, which allows either a // `PlainPubKey` or a `SignedPubKey`, to allow for re-used in identity chains. However, only // the `PlainPubKey` variant appears here. pub peer_pub_key: Vec, // PlainPubKey.cddl pub peer_id: Vec, // Identity.cddl pub peer_signature: Vec, // SessionIdSignature.cddl pub peer_nonce: Vec, pub peer_version: i32, pub own_key: Key, } #[derive(Debug, Clone, PartialEq, Eq, AsCborValue)] pub struct FinishResponse { pub ret: SessionInfo, } #[derive(Debug, Clone, PartialEq, Eq, AsCborValue)] pub struct AuthenticationCompleteRequest { pub peer_signature: Vec, // SessionIdSignature.cddl pub shared_keys: [Vec; 2], // Arc.cddl } #[derive(Debug, Clone, PartialEq, Eq, AsCborValue)] pub struct AuthenticationCompleteResponse { pub ret: [Vec; 2], // Arc.cddl } // Rust `struct`s corresponding to AIDL messages on the `IAuthGraphKeyExchange` interface. // Structures that have a single field containing CBOR-encoded data are directly expanded. #[derive(Debug, Clone, PartialEq, Eq, AsCborValue)] pub struct SessionInitiationInfo { pub ke_key: Key, pub identity: Vec, // Identity.cddl pub nonce: Vec, pub version: i32, } #[derive(Debug, Clone, PartialEq, Eq, AsCborValue)] pub struct SessionInfo { pub shared_keys: [Vec; 2], // Arc.cddl pub session_id: Vec, pub session_id_signature: Vec, // SessionIdSignature.cddl } #[derive(Debug, Clone, PartialEq, Eq, AsCborValue)] pub struct KeInitResult { pub session_init_info: SessionInitiationInfo, pub session_info: SessionInfo, } #[derive(Debug, Clone, PartialEq, Eq, AsCborValue)] pub struct Key { // Note that the AIDL definition for this field has type `PubKey`, which allows either a // `PlainPubKey` or a `SignedPubKey`, to allow for re-used in identity chains. However, only // the `PlainPubKey` variant appears here. pub pub_key: Option>, // PlainPubKey.cddl pub arc_from_pbk: Option>, // Arc.cddl } #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, N)] pub enum AuthGraphOperationCode { Create = 0x10, Init = 0x11, Finish = 0x12, AuthenticationComplete = 0x13, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum PerformOpReq { Create(CreateRequest), Init(InitRequest), Finish(FinishRequest), AuthenticationComplete(AuthenticationCompleteRequest), } impl Code for PerformOpReq { fn code(&self) -> AuthGraphOperationCode { match self { Self::Create(_) => AuthGraphOperationCode::Create, Self::Init(_) => AuthGraphOperationCode::Init, Self::Finish(_) => AuthGraphOperationCode::Finish, Self::AuthenticationComplete(_) => AuthGraphOperationCode::AuthenticationComplete, } } } impl AsCborValue for PerformOpReq { fn from_cbor_value(value: Value) -> Result { let mut a = match value { Value::Array(a) if a.len() == 2 => a, _ => return crate::cbor_type_error(&value, "arr len 2"), }; let val = a.remove(1); let code = i32::from_cbor_value(a.remove(0))?; let code = AuthGraphOperationCode::n(code).ok_or(CborError::NonEnumValue)?; Ok(match code { AuthGraphOperationCode::Create => Self::Create(CreateRequest::from_cbor_value(val)?), AuthGraphOperationCode::Init => Self::Init(InitRequest::from_cbor_value(val)?), AuthGraphOperationCode::Finish => Self::Finish(FinishRequest::from_cbor_value(val)?), AuthGraphOperationCode::AuthenticationComplete => { Self::AuthenticationComplete(AuthenticationCompleteRequest::from_cbor_value(val)?) } }) } fn to_cbor_value(self) -> Result { Ok(Value::Array(match self { Self::Create(req) => vec![req.value(), req.to_cbor_value()?], Self::Init(req) => vec![req.value(), req.to_cbor_value()?], Self::Finish(req) => vec![req.value(), req.to_cbor_value()?], Self::AuthenticationComplete(req) => vec![req.value(), req.to_cbor_value()?], })) } } #[derive(Debug, Clone, PartialEq, Eq)] pub enum PerformOpRsp { Create(CreateResponse), Init(InitResponse), Finish(FinishResponse), AuthenticationComplete(AuthenticationCompleteResponse), } impl Code for PerformOpRsp { fn code(&self) -> AuthGraphOperationCode { match self { Self::Create(_) => AuthGraphOperationCode::Create, Self::Init(_) => AuthGraphOperationCode::Init, Self::Finish(_) => AuthGraphOperationCode::Finish, Self::AuthenticationComplete(_) => AuthGraphOperationCode::AuthenticationComplete, } } } impl AsCborValue for PerformOpRsp { fn from_cbor_value(value: Value) -> Result { let mut a = match value { Value::Array(a) if a.len() == 2 => a, _ => return crate::cbor_type_error(&value, "arr len 2"), }; let val = a.remove(1); let code = i32::from_cbor_value(a.remove(0))?; let code = AuthGraphOperationCode::n(code).ok_or(CborError::NonEnumValue)?; Ok(match code { AuthGraphOperationCode::Create => Self::Create(CreateResponse::from_cbor_value(val)?), AuthGraphOperationCode::Init => Self::Init(InitResponse::from_cbor_value(val)?), AuthGraphOperationCode::Finish => Self::Finish(FinishResponse::from_cbor_value(val)?), AuthGraphOperationCode::AuthenticationComplete => { Self::AuthenticationComplete(AuthenticationCompleteResponse::from_cbor_value(val)?) } }) } fn to_cbor_value(self) -> Result { Ok(Value::Array(match self { Self::Create(req) => vec![req.value(), req.to_cbor_value()?], Self::Init(req) => vec![req.value(), req.to_cbor_value()?], Self::Finish(req) => vec![req.value(), req.to_cbor_value()?], Self::AuthenticationComplete(req) => vec![req.value(), req.to_cbor_value()?], })) } } // Result of an operation, as an error code and a response message (only present when // `error_code` is zero). #[derive(Debug, Clone, PartialEq, Eq, AsCborValue)] pub struct PerformOpResponse { pub error_code: ErrorCode, pub rsp: Option, } #[derive(Debug, Clone, Copy, PartialEq, Eq, AsCborValue)] #[repr(i32)] pub enum ErrorCode { // Internal error codes corresponding to values in `Error.aidl`. /// Success Ok = 0, /// Invalid peer nonce for key agreement InvalidPeerNonce = -1, /// Invalid key agreement public key by the peer InvalidPeerKeKey = -2, /// Invalid identity of the peer InvalidIdentity = -3, /// Invalid certificate chain in the identity of the peer InvalidCertChain = -4, /// Invalid signature by the peer InvalidSignature = -5, /// Invalid key agreement key created by a particular party themselves to be used as a handle InvalidKeKey = -6, /// Invalid public key in the `Key` struct InvalidPubKeyInKey = -7, /// Invalid private key arc in the `Key` struct InvalidPrivKeyArcInKey = -8, /// Invalid shared key arcs InvalidSharedKeyArcs = -9, /// Memory allocation failed MemoryAllocationFailed = -10, /// The protocol version negotiated with the sink is incompatible IncompatibleProtocolVersion = -11, // Error codes corresponding to Binder error values. /// Internal processing error InternalError = -12, /// Unimplemented Unimplemented = -13, } /// Trait that associates an [`AuthGraphOperationCode`] with a message. pub trait Code { /// Return the enum value associated with the underlying type of this item. fn code(&self) -> AuthGraphOperationCode; /// Return a [`Value`] holding the enum value. fn value(&self) -> Value { Value::Integer((self.code() as i32).into()) } } macro_rules! impl_code { { $req:ident => $code:ident } => { impl Code for $req { fn code(&self) -> AuthGraphOperationCode { AuthGraphOperationCode::$code } } } } impl_code!(CreateRequest => Create); impl_code!(InitRequest => Init); impl_code!(FinishRequest => Finish); impl_code!(AuthenticationCompleteRequest => AuthenticationComplete); impl_code!(CreateResponse => Create); impl_code!(InitResponse => Init); impl_code!(FinishResponse => Finish); impl_code!(AuthenticationCompleteResponse => AuthenticationComplete);