• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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