1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 //////////////////////////////////////////////////////////////////////////////// 16 17 //! Traits representing crypto abstractions and device specific functionality 18 use crate::data_structures::{ 19 AuthenticatedConnectionState, ClientId, PersistentClientContext, PersistentInstanceContext, 20 }; 21 use crate::error::Error; 22 use alloc::boxed::Box; 23 use alloc::sync::Arc; 24 use authgraph_core::key::{CertChain, InstanceIdentifier, Policy}; 25 use authgraph_core::traits::{EcDsa, Rng}; 26 use authmgr_common::signed_connection_request::TransportID; 27 28 /// The cryptographic functionality that must be provided by an implementation of AuthMgr BE 29 pub struct CryptoTraitImpl { 30 /// Implementation of ECDSA functionality 31 pub ecdsa: Box<dyn EcDsa>, 32 /// Implementation of secure random number generation 33 pub rng: Box<dyn Rng>, 34 } 35 36 /// Trait defining device specific functionality 37 pub trait Device: Send { 38 /// Return the transport ID of the AuthMgr BE get_self_transport_id(&self) -> Result<TransportID, Error>39 fn get_self_transport_id(&self) -> Result<TransportID, Error>; 40 41 /// Secure storage invariant: we cannot allow a non-persistent pVM connect to secure storage 42 /// without the secure storage knowing that it is a non-persistent client. Therefore, the 43 /// AuthMgr BE should know whether a given pVM is persistent. In the first version of the 44 /// trusted HAL project, we only support persistent pVM clients, therefore, in the first 45 /// version, this could simply return true. When non-persistent pVMs are supported, it is 46 /// expected that the AuthMgr BE learns via some out-of-band mechanism the instance ids of the 47 /// persistence pVMs on the device. is_persistent_instance(&self, instance_id: &InstanceIdentifier) -> Result<bool, Error>48 fn is_persistent_instance(&self, instance_id: &InstanceIdentifier) -> Result<bool, Error>; 49 50 /// Connect to the trusted service identified by `service_name` and hand over the client 51 /// connection along with the client's unique sequence number. 52 /// The client connection is an object of the trait implementation: `RawConnection`. At the end 53 /// of this method, the vendor implementation must close the handle to the file descriptor 54 /// underlying this connection such that: 55 /// 1) if the `handover_client_connection` is successful, the underlying file description 56 /// should be kept open for the client and the trusted service to be able to communicate. 57 /// 2) if the `handover_client_connection` failed, then this is the last handle to the file 58 /// description underlying this connection from the AuthMgr BE side, and therefore, closing 59 /// the handle to it should close the underlying file description. handover_client_connection( &self, service_name: &str, client_seq_number: i32, client_conn_handle: Box<dyn RawConnection>, is_persistent: bool, ) -> Result<(), Error>60 fn handover_client_connection( 61 &self, 62 service_name: &str, 63 client_seq_number: i32, 64 client_conn_handle: Box<dyn RawConnection>, 65 is_persistent: bool, 66 ) -> Result<(), Error>; 67 68 /// Check whether the persistent instance with the given instance id and the dice cert chain is 69 /// allowed to be created. is_persistent_instance_creation_allowed( &self, instance_id: &InstanceIdentifier, dice_chain: &CertChain, ) -> Result<bool, Error>70 fn is_persistent_instance_creation_allowed( 71 &self, 72 instance_id: &InstanceIdentifier, 73 dice_chain: &CertChain, 74 ) -> Result<bool, Error>; 75 } 76 77 /// Trait defining RPC connection specific functionality required by AuthMgr BE 78 pub trait RpcConnection: Send { 79 /// Return the transport ID of the instance that is on the other end of the connection get_peer_transport_id(&self) -> Result<TransportID, Error>80 fn get_peer_transport_id(&self) -> Result<TransportID, Error>; 81 82 /// Store the re-usable information about the pvm and its clients in the connection state, to be 83 /// used for serving multiple client authorization requests from an already authenticated pvm store_authenticated_state( &mut self, connection_state: AuthenticatedConnectionState, ) -> Result<(), Error>84 fn store_authenticated_state( 85 &mut self, 86 connection_state: AuthenticatedConnectionState, 87 ) -> Result<(), Error>; 88 89 /// Return the state if the state has been stored for this connecction. Since the state is 90 /// stored only after the peer on the other side of the connection is authenticated, the 91 /// existence of a connection state is also an indication that the connection is authenticated. get_authenticated_state(&self) -> Result<Option<&AuthenticatedConnectionState>, Error>92 fn get_authenticated_state(&self) -> Result<Option<&AuthenticatedConnectionState>, Error>; 93 94 /// Return the mutable state if the state has been stored for this connection. Since the state 95 /// is stored only after the peer on the other side of the connection is authenticated, the 96 /// existence of a connection state is also an indication that the connection is authenticated. get_mutable_authenticated_state( &mut self, ) -> Result<Option<&mut AuthenticatedConnectionState>, Error>97 fn get_mutable_authenticated_state( 98 &mut self, 99 ) -> Result<Option<&mut AuthenticatedConnectionState>, Error>; 100 101 /// Delete the state stored associated with the connection. This is called when the connection 102 /// is closed. remove_authenticated_state(&mut self) -> Result<(), Error>103 fn remove_authenticated_state(&mut self) -> Result<(), Error>; 104 } 105 106 /// Trait defining the raw connection specific functionality required by AuthMgr BE. 107 /// This is the out-of-band connection setup between the AuthMgr FE and AuthMgr BE, to be handedover 108 /// for the communication between a client in the pvm and the trusted service in TEE. 109 /// The handingover of the connection from the AuthMgr BE to the trusted service happens once the 110 /// client is authorized. AuthMgr BE invokes the `handover_client_connection` method of the `Device` 111 /// trait by passing an object of this trait implementation. Once the connection - which usually is 112 /// represented by a file descriptor - is handed over to the trusted service, the AuthMgr BE vendor 113 /// code should make sure that its handle to the underlying file descriptor is closed, but the 114 /// underlying file description is still open for the client and the trusted service to be able to 115 /// continue communication. 116 pub trait RawConnection: Send { 117 /// Return the transport ID of the instance that is on the other end of the connection get_peer_transport_id(&self) -> Result<TransportID, Error>118 fn get_peer_transport_id(&self) -> Result<TransportID, Error>; 119 120 /// Return the raw file descriptor id of the underlying connection. This method is not called by 121 /// the authmgr backend core library. Rather, this is added for use of the vendor 122 /// implementations of `handover_client_connection` which is passed in an implementation of 123 /// this `RawConnection` trait. 124 /// 125 /// Note that as per the Rust I/O safety guidelines: 126 /// (<https://doc.rust-lang.org/stable/std/io/index.html#io-safety>) it is unsound to take an 127 /// integer and treat it as a file descriptor. We refrain from using an `OwnedFd` here to 128 /// preserve the no_std property of this crate. Therefore, the implementations should make sure 129 /// that an object of this trait owns the file descriptor underlying the connection. 130 /// 131 /// Also note that we transfer the ownership of the object into this function to make sure this 132 /// method cannot be called twice on the same object. Therefore, the implementation of this 133 /// method should make sure that the object's destructor doesn't get called at the end of this 134 /// method, in order to make sure that the underlying connection stays alive for the client and 135 /// the trusted service to communicate. into_raw_fd(self: Box<Self>) -> i32136 fn into_raw_fd(self: Box<Self>) -> i32; 137 } 138 139 /// Following traits define the storage related functionality for AuthMgr BE. The AuthMgr BE 140 /// need to store three types of information: 141 /// 1) The latest global sequence number - this is used to assign a unique id for instances and 142 /// clients. Uniqueness is preserved across factory resets because this is stored in the 143 /// persistent storage. It is important to preserve the uniqueness across factory resets in order 144 /// to prevent "use-after-destroy" threats described in the AuthMgr threat model. 145 /// 146 /// 2) Instance contexts - information related to an instance, such as the instance sequence number, 147 /// DICE policy, etc. The information contained in an instance context may vary depending on 148 /// whether the instance is persistent or not. The path to the storage of an instance context is 149 /// uniquely identified by the instance identifier - so that the storage artifact containing the 150 /// instance context can be queried during the authentication protocol, given the instance id - 151 /// which is usually extracted from the DICE chain of the instance. 152 /// 153 /// 3) Client contexts - information related to a client in an instance, such as client sequence 154 /// number, DICE policy for the client's DICE certificate, etc. The information contained in a 155 /// client context may vary depending on whether the client is persistent or not. The path to the 156 /// storage of a client context is uniquely identified by the instance sequence number and the 157 /// client id - so that the storage artifact containing the client context can be queried during 158 /// phase 2 of the protocol, given the instance sequence number given by phase 1 of the 159 /// protocol and the client id provided by the AuthMgr FE in phase 2. 160 /// 161 /// TODO: b/398286643 162 /// The storage trait will be simplified to have just two methods to read and write a file 163 /// as mentioned in the above bug, once the encoding and decoding is implemented for the relevant 164 /// structures. 165 /// We require the vendor to implement the Storage trait for both persistent and non-persistent 166 /// storage because this reduces the potential errors in the vendor code which otherwise would have 167 /// to handle a boolean passed to each trait method, indicating whether the method should deal with 168 /// the persistent or non persistent storage. We move that complexity to the generic code by having 169 /// the Storage trait implemented for the two types of storage. 170 pub trait Storage: Send { 171 /// Instance context 172 type InstanceContext; 173 /// Client context 174 type ClientContext; 175 176 /// Use this method to update the instance's DICE policy in the secure storage. update_instance_policy_in_storage( &mut self, instance_id: &Arc<InstanceIdentifier>, latest_dice_policy: &Arc<Policy>, ) -> Result<(), Error>177 fn update_instance_policy_in_storage( 178 &mut self, 179 instance_id: &Arc<InstanceIdentifier>, 180 latest_dice_policy: &Arc<Policy>, 181 ) -> Result<(), Error>; 182 183 /// Use this method to update the client's DICE policy. update_client_policy_in_storage( &mut self, instance_seq_number: i32, client_id: &Arc<ClientId>, latest_dice_policy: &Arc<Policy>, ) -> Result<(), Error>184 fn update_client_policy_in_storage( 185 &mut self, 186 instance_seq_number: i32, 187 client_id: &Arc<ClientId>, 188 latest_dice_policy: &Arc<Policy>, 189 ) -> Result<(), Error>; 190 191 /// Retrieve the information stored in the secure storage for the instance identified by the 192 /// given instance identifier, if it exists in the AuthMgr BE's secure storage, 193 /// otherwise, return None. read_instance_context( &self, instance_id: &Arc<InstanceIdentifier>, ) -> Result<Option<Self::InstanceContext>, Error>194 fn read_instance_context( 195 &self, 196 instance_id: &Arc<InstanceIdentifier>, 197 ) -> Result<Option<Self::InstanceContext>, Error>; 198 199 /// Create the context for a particular pvm instance in the secure storage. The implementation 200 /// of this method should make sure that there are no other instances created same instance id. 201 /// This is important to enforce Trust On First Use (TOFU). create_instance_context( &mut self, instance_id: &Arc<InstanceIdentifier>, instance_info: Self::InstanceContext, ) -> Result<(), Error>202 fn create_instance_context( 203 &mut self, 204 instance_id: &Arc<InstanceIdentifier>, 205 instance_info: Self::InstanceContext, 206 ) -> Result<(), Error>; 207 208 /// Retrieve the information stored in the secure storage for the client identified by the 209 /// sequence number of the instance it belongs to and the client id, if it exists in the 210 /// AuthMgr BE's secure storage, otherwise, return None. read_client_context( &self, instance_seq_number: i32, client_id: &Arc<ClientId>, ) -> Result<Option<Self::ClientContext>, Error>211 fn read_client_context( 212 &self, 213 instance_seq_number: i32, 214 client_id: &Arc<ClientId>, 215 ) -> Result<Option<Self::ClientContext>, Error>; 216 217 /// Initialize the secure storage for a particular client. The implementation of this method 218 /// should make sure that there are no clients created with the same client id for the given 219 /// instance. create_client_context( &mut self, instance_seq_number: i32, client_id: &Arc<ClientId>, client_info: Self::ClientContext, ) -> Result<(), Error>220 fn create_client_context( 221 &mut self, 222 instance_seq_number: i32, 223 client_id: &Arc<ClientId>, 224 client_info: Self::ClientContext, 225 ) -> Result<(), Error>; 226 } 227 228 /// Trait defining the persistent storage specific functionality. 229 /// (This is temporary, until b/398286643 is resolved) 230 pub trait PersistentStorage: 231 Storage<InstanceContext = PersistentInstanceContext, ClientContext = PersistentClientContext> 232 { 233 /// Retrieve the global sequence number stored in the factory-reset surviving secure storage of 234 /// the AuthMgr BE. If it does not already exist, initialize it from 0. get_or_create_global_sequence_number(&mut self) -> Result<i32, Error>235 fn get_or_create_global_sequence_number(&mut self) -> Result<i32, Error>; 236 237 /// Increment the global sequence number stored in the factory-reset surviving secure storage of 238 /// the AuthMgr BE. Return the latest global sequence number if successful andan error if it 239 /// does not exist in the AuthMgr BE's secure storage. increment_global_sequence_number(&mut self) -> Result<i32, Error>240 fn increment_global_sequence_number(&mut self) -> Result<i32, Error>; 241 } 242