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 //! Reference implementation of the `IAuthMgrAuthorization.aidl` for the AuthMgr Backend. 18 // TODO: remove this 19 #![allow(dead_code)] 20 use crate::{ 21 am_err, 22 data_structures::{ 23 AuthStartedPvm, AuthStartedPvms, AuthenticatedConnectionState, AuthenticatedPvms, 24 AuthorizedClient, AuthorizedClientFullDiceArtifacts, AuthorizedClientsGlobalList, ClientId, 25 DiceArtifacts, MemoryLimits, PendingClientAuthorization, PendingClientAuthorizations, 26 PersistentClientContext, PersistentInstanceContext, VERSION_PERSISTENT_CLIENT_CONTEXT, 27 VERSION_PERSISTENT_INSTANCE_CONTEXT, 28 }, 29 error::{Error, ErrorCode}, 30 traits::{CryptoTraitImpl, Device, PersistentStorage, RawConnection, RpcConnection}, 31 try_to_vec, 32 }; 33 use alloc::boxed::Box; 34 use alloc::sync::Arc; 35 use authgraph_core::key::{CertChain, DiceChainEntry, InstanceIdentifier, Policy}; 36 use authmgr_common::{ 37 extend_dice_policy_with, match_dice_cert_with_policy, match_dice_chain_with_policy, 38 signed_connection_request::{Challenge, ConnectionRequest}, 39 Token, 40 }; 41 use coset::CborSerializable; 42 43 /// Data structure encapsulating AuthMgr backend. 44 /// Note that we assume the use of AuthMgrBE in single threaded environments. It is planned for the 45 /// future to make AuthMgrBE usable in multi-threaded environments b/369207531 and to make all 46 /// allocations fallible b/401550040. 47 pub struct AuthMgrBE { 48 crypto: CryptoTraitImpl, 49 device: Box<dyn Device>, 50 persistent_storage: Box<dyn PersistentStorage>, 51 auth_started_pvms: AuthStartedPvms, 52 auth_completed_pvms: AuthenticatedPvms, 53 latest_global_sequence_number: LatestGlobalSeqNum, 54 pending_client_authorizations: PendingClientAuthorizations, 55 authorized_clients: AuthorizedClientsGlobalList, 56 memory_limits: MemoryLimits, 57 } 58 59 /// Data structure encapsulating the global sequence number - which is used to assign a unique 60 /// identifier to the instances and clients by the AuthMgr BE 61 pub struct LatestGlobalSeqNum(i32); 62 63 impl LatestGlobalSeqNum { 64 /// Constructs an instance of the in-memory global sequence number given the latest global 65 /// sequence number which is read from the persistent storage new(latest_global_seq_num: i32) -> Self66 pub fn new(latest_global_seq_num: i32) -> Self { 67 Self(latest_global_seq_num) 68 } 69 70 /// Return the current global sequence number and increment the global sequence number in the 71 /// persistent storage and in this in-memory instance fetch_and_increment( &mut self, persistent_storage: &mut dyn PersistentStorage, ) -> Result<i32, Error>72 pub fn fetch_and_increment( 73 &mut self, 74 persistent_storage: &mut dyn PersistentStorage, 75 ) -> Result<i32, Error> { 76 let current_global_seq_num = self.0; 77 self.0 = persistent_storage.increment_global_sequence_number()?; 78 Ok(current_global_seq_num) 79 } 80 } 81 82 impl AuthMgrBE { 83 /// Initialize AuthMgr BE new( crypto: CryptoTraitImpl, device: Box<dyn Device>, mut persistent_storage: Box<dyn PersistentStorage>, memory_limits: MemoryLimits, ) -> Result<Self, Error>84 pub fn new( 85 crypto: CryptoTraitImpl, 86 device: Box<dyn Device>, 87 mut persistent_storage: Box<dyn PersistentStorage>, 88 memory_limits: MemoryLimits, 89 ) -> Result<Self, Error> { 90 let auth_started_pvms = AuthStartedPvms::new(memory_limits.capacity_auth_started_pvms)?; 91 let auth_completed_pvms = 92 AuthenticatedPvms::new(memory_limits.capacity_auth_completed_pvms)?; 93 let pending_client_authorizations = PendingClientAuthorizations::new( 94 memory_limits.capacity_auth_completed_pvms, 95 memory_limits.max_clients_per_pvm, 96 )?; 97 let authorized_clients = AuthorizedClientsGlobalList::new( 98 memory_limits.capacity_auth_completed_pvms * memory_limits.max_clients_per_pvm, 99 )?; 100 // If this is the first time the AuthMgr BE is running after the first boot of the device, 101 // initialize the global sequence number, otherwise, read it from the AuthMgr BE's storage 102 let latest_global_sequence_number = 103 LatestGlobalSeqNum(persistent_storage.get_or_create_global_sequence_number()?); 104 Ok(AuthMgrBE { 105 crypto, 106 device, 107 persistent_storage, 108 auth_started_pvms, 109 auth_completed_pvms, 110 latest_global_sequence_number, 111 pending_client_authorizations, 112 authorized_clients, 113 memory_limits, 114 }) 115 } 116 117 /// Step 1 of phase 1 init_authentication( &mut self, connection: &dyn RpcConnection, cert_chain: &[u8], ext_instance_id: Option<&[u8]>, ) -> Result<Challenge, Error>118 pub fn init_authentication( 119 &mut self, 120 connection: &dyn RpcConnection, 121 cert_chain: &[u8], 122 ext_instance_id: Option<&[u8]>, 123 ) -> Result<Challenge, Error> { 124 // Check if the connection is already authenticated by retrieving the connection state 125 if connection.get_authenticated_state()?.is_some() { 126 return Err(am_err!( 127 InstanceAlreadyAuthenticated, 128 "connection is already authenticated" 129 )); 130 } 131 132 // Retrieve the transport ID 133 let transport_id = connection.get_peer_transport_id()?; 134 135 // Decode the DICE certificate chain 136 let cert_chain = CertChain::from_slice(cert_chain) 137 .map_err(|_e| am_err!(InvalidDiceCertChain, "failed to decode the DICE cert chain."))?; 138 139 // First, extract the instance identifier from the DICE chain. Only if it is not present, 140 // check if a valid instance identifier is provided via the optional parameter 141 let instance_id: InstanceIdentifier = 142 match cert_chain.extract_instance_identifier_in_guest_os_entry()? { 143 Some(id) => id, 144 None => ext_instance_id.map(|id| id.to_vec()).ok_or(am_err!( 145 InvalidInstanceIdentifier, 146 "Instance identifier is neither present in the DICE cert chain, 147 nor in the optional argument" 148 ))?, 149 }; 150 151 // Check for duplicated authentication attempts. 152 // We check with the instance id and transport id separately, and not with the combination 153 // of the two, because the latter allows the same pVM to be spawned twice (resulting in two 154 // different transport ids and the same instance id) and connected, which we want to avoid. 155 if self.auth_completed_pvms.has_instance_id(&instance_id) { 156 return Err(am_err!( 157 InstanceAlreadyAuthenticated, 158 "duplicated authentication attempt with the instance id: {:?}!", 159 instance_id 160 )); 161 } 162 if self.auth_completed_pvms.has_transport_id(transport_id) { 163 return Err(am_err!( 164 InstanceAlreadyAuthenticated, 165 "duplicated authentication attempt with the transport id: {:?}!", 166 transport_id 167 )); 168 } 169 // We filter duplicated entries in `AuthStartedPvms` via the transport id only. 170 // We do not filter via instance id here in order to prevent a potental DoS attack where an 171 // impersonating pVM starts authentication with a genuine pVM's instance id, but never 172 // completes. 173 if self.auth_started_pvms.has_transport_id(transport_id) { 174 return Err(am_err!( 175 AuthenticationAlreadyStarted, 176 "duplicated attempt to start authentication!" 177 )); 178 } 179 let mut challenge = [0; 32]; 180 self.crypto.rng.fill_bytes(&mut challenge); 181 // TODO: b/401550040. Use fallible allocation when Rust supports it. 182 self.auth_started_pvms.insert(AuthStartedPvm { 183 transport_id, 184 instance_id: Arc::new(instance_id), 185 challenge, 186 cert_chain: Arc::new(cert_chain), 187 }); 188 Ok(challenge) 189 } 190 191 /// Step 2 of phase 1 complete_authentication( &mut self, connection: &mut dyn RpcConnection, signed_response: &[u8], dice_policy: &[u8], ) -> Result<(), Error>192 pub fn complete_authentication( 193 &mut self, 194 connection: &mut dyn RpcConnection, 195 signed_response: &[u8], 196 dice_policy: &[u8], 197 ) -> Result<(), Error> { 198 // Check if the connection is already authenticated by retrieving the connection state 199 if connection.get_authenticated_state()?.is_some() { 200 return Err(am_err!( 201 InstanceAlreadyAuthenticated, 202 "connection is already authenticated" 203 )); 204 } 205 206 // Retrieve the transport ID 207 let peer_transport_id = connection.get_peer_transport_id()?; 208 // Check for duplicated authentication attempts to enforce Trust On First Use (TOFU). 209 if self.auth_completed_pvms.has_transport_id(peer_transport_id) { 210 return Err(am_err!( 211 InstanceAlreadyAuthenticated, 212 "duplicated authentication attempt!" 213 )); 214 } 215 let auth_started_entry = 216 self.auth_started_pvms.take_via_transport_id(peer_transport_id).ok_or(am_err!( 217 AuthenticationNotStarted, 218 "An authentication started pVM was not found for the given transport id" 219 ))?; 220 if self.auth_completed_pvms.has_instance_id(&auth_started_entry.instance_id) { 221 return Err(am_err!( 222 InstanceAlreadyAuthenticated, 223 "duplicated authentication attempt!" 224 )); 225 } 226 // Validate the DICE cert chain and retrieve the signature verification key 227 let sig_verification_key = 228 (*auth_started_entry.cert_chain).validate(&*self.crypto.ecdsa).map_err(|_e| { 229 am_err!(InvalidDiceCertChain, "failed to validate the DICE cert chain.") 230 })?; 231 232 // Authenticate the client by validating their signature on the response to the challenge. 233 // Construct the expected `ConnectionRequest` CBOR structure as the payload of the signature 234 let expected_conn_req = ConnectionRequest::new_for_ffa_transport( 235 auth_started_entry.challenge, 236 peer_transport_id, 237 self.device.get_self_transport_id()?, 238 ); 239 expected_conn_req 240 .verify(signed_response, &sig_verification_key, &*self.crypto.ecdsa) 241 .map_err(|_e| { 242 am_err!( 243 SignatureVerificationFailed, 244 "failed to verify signature on the connection request" 245 ) 246 })?; 247 248 let given_dice_policy = Arc::new(Policy(try_to_vec(dice_policy)?)); 249 let is_persistent = self.device.is_persistent_instance(&auth_started_entry.instance_id)?; 250 let instance_seq_number = if is_persistent { 251 self.handle_instance_in_persistent_storage( 252 &auth_started_entry.instance_id, 253 &given_dice_policy, 254 &auth_started_entry.cert_chain, 255 )? 256 } else { 257 // TODO: b/399707150 258 return Err(am_err!(Unimplemented, "Non persistent instances are not yet supported.")); 259 }; 260 // Construct the connection state 261 let connection_state = AuthenticatedConnectionState::new( 262 Arc::clone(&auth_started_entry.instance_id), 263 auth_started_entry.transport_id, 264 instance_seq_number, 265 DiceArtifacts { 266 cert_chain: Arc::clone(&auth_started_entry.cert_chain), 267 policy: given_dice_policy, 268 }, 269 sig_verification_key, 270 is_persistent, 271 self.memory_limits.max_clients_per_pvm, 272 )?; 273 connection.store_authenticated_state(connection_state)?; 274 auth_started_entry 275 .mark_as_authenticated(&mut self.auth_started_pvms, &mut self.auth_completed_pvms)?; 276 Ok(()) 277 } 278 279 /// Step 1 of phase 2 280 /// A new connection should be used for client authorization. The AuthMgr-BE TA implementation 281 /// should make sure that it fails gracefully, if a connection that is already used for instance 282 /// authentication is attempted to be used for client authorization. init_connection_for_client( &mut self, client_connection: Box<dyn RawConnection>, token: Token, ) -> Result<(), Error>283 pub fn init_connection_for_client( 284 &mut self, 285 client_connection: Box<dyn RawConnection>, 286 token: Token, 287 ) -> Result<(), Error> { 288 // Check if this request comes from a pVM which has an AuthMgr FE that is already 289 // authenticated with the AuthMgr BE. 290 let client_transport_id = client_connection.get_peer_transport_id()?; 291 if !self.auth_completed_pvms.has_transport_id(client_transport_id) { 292 return Err(am_err!( 293 InstanceNotAuthenticated, 294 "the transport id is not associated with a pVM that has an 295 authenticated AuthMgr FE." 296 )); 297 } 298 299 // Add the connection and the token to the pending client authorization list. 300 self.pending_client_authorizations 301 .insert(client_transport_id, PendingClientAuthorization { token, client_connection })?; 302 Ok(()) 303 } 304 305 /// Step 2 of phase 2 authorize_and_connect_client_to_trusted_service( &mut self, connection: &mut dyn RpcConnection, client_id: &[u8], service_name: &str, token: Token, client_dice_cert: &[u8], client_dice_policy: &[u8], ) -> Result<(), Error>306 pub fn authorize_and_connect_client_to_trusted_service( 307 &mut self, 308 connection: &mut dyn RpcConnection, 309 client_id: &[u8], 310 service_name: &str, 311 token: Token, 312 client_dice_cert: &[u8], 313 client_dice_policy: &[u8], 314 ) -> Result<(), Error> { 315 // Check whether the connection is already authenticated. 316 let state = connection.get_mutable_authenticated_state()?.ok_or(am_err!( 317 ConnectionNotAuthenticated, 318 "phase 2 of the AuthMgr protocol can only be invoked on an authenticated connection." 319 ))?; 320 // Retrieve the new connection corresponding to this request from pending authorizations 321 let pending_authorization = 322 self.pending_client_authorizations.take(state.transport_id, token).ok_or(am_err!( 323 NoConnectionToAuthorize, 324 "no pending authorization found for the transport id: {:?} and token: {:?}", 325 state.transport_id, 326 token 327 ))?; 328 329 let client_id = Arc::new(ClientId(try_to_vec(client_id)?)); 330 let given_policy = Arc::new(Policy(try_to_vec(client_dice_policy)?)); 331 let given_dice_cert = DiceChainEntry::from_slice(client_dice_cert)?; 332 let is_persistent = state.is_persistent; 333 let instance_seq_number = state.instance_seq_number; 334 // In what follows, we do the following: 335 // 1. Read from the cache to see if this client is already authorized in the current boot 336 // cycle of the pVM instance. If the client is in the cache, enforce rollback protection 337 // for the client in the cache. This includes running the dice chain to policy matching 338 // checks and if they are successful, updating both the storage and the cache if the 339 // policy has been updated. 340 // 2. If the client is not in the cache, read the client context from the storage. 341 // a) If the client context is in the storage, enforce rollback protection for the client 342 // in the storage. 343 // b) If the client is not in the stroge, create the instance context in the storage. 344 // c) Insert the client into the cache. 345 let mut authorized_client = state.get_mutable_authorized_client(&client_id); 346 let (client_seq_number, policy_need_update) = match authorized_client { 347 Some(ref mut client) => { 348 let client_seq_number = client.sequence_number; 349 let policy_need_update = !(given_policy == client.policy); 350 self.enforce_rollback_protection_for_client_in_cache( 351 instance_seq_number, 352 is_persistent, 353 client, 354 &given_dice_cert, 355 &given_policy, 356 )?; 357 (client_seq_number, policy_need_update) 358 } 359 None => { 360 // If not, read from the storage 361 let client_seq_number = if is_persistent { 362 self.handle_client_in_persistent_storage( 363 instance_seq_number, 364 &client_id, 365 &given_dice_cert, 366 &given_policy, 367 )? 368 } else { 369 // TODO: b/399707150 370 return Err(am_err!( 371 Unimplemented, 372 "Non persistent instances are not yet supported." 373 )); 374 }; 375 // Insert into the cache 376 state.insert_authorized_client(AuthorizedClient { 377 client_id: Arc::clone(&client_id), 378 sequence_number: client_seq_number, 379 policy: Arc::clone(&given_policy), 380 })?; 381 (client_seq_number, false) 382 } 383 }; 384 // Update the cache containing the global list of authorized clients with their full DICE 385 // artifacts to be used by the "policy matching as a service" offered by AuthMgr-BE 386 self.update_global_list_of_authorized_clients( 387 state, 388 client_seq_number, 389 &client_id, 390 &given_dice_cert, 391 &given_policy, 392 policy_need_update, 393 )?; 394 // Handover the authorized client to the requested trusted service 395 // TODO: Upon successful handover, update the connected services for the client in the cache 396 // and the storage, if needed 397 self.device.handover_client_connection( 398 service_name, 399 client_seq_number, 400 pending_authorization.client_connection, 401 is_persistent, 402 ) 403 } 404 405 /// This should be called by the TEE environment upon closing of every connection established 406 /// between AuthMgr FE and AuthMgr BE "for the purpose of authenticating AuthMgr FE 407 /// to AuthMgr BE" - i.e. the connections established in phase 1, in order to clear the cache. clear_cache_upon_main_connection_close( &mut self, connection: &mut dyn RpcConnection, ) -> Result<(), Error>408 pub fn clear_cache_upon_main_connection_close( 409 &mut self, 410 connection: &mut dyn RpcConnection, 411 ) -> Result<(), Error> { 412 let transport_id = connection.get_peer_transport_id()?; 413 self.auth_started_pvms.remove_via_transport_id(transport_id); 414 self.auth_completed_pvms.remove_via_transport_id(transport_id); 415 self.pending_client_authorizations.remove_via_transport_id(transport_id); 416 self.authorized_clients.remove_via_transport_id(transport_id); 417 connection.remove_authenticated_state()?; 418 Ok(()) 419 } 420 421 // A helper method for creating/updating the instance context in the secure storage and 422 // enforcing rollback protection for a persistent pvm. handle_instance_in_persistent_storage( &mut self, instance_id: &Arc<InstanceIdentifier>, given_policy: &Arc<Policy>, dice_chain: &CertChain, ) -> Result<i32, Error>423 fn handle_instance_in_persistent_storage( 424 &mut self, 425 instance_id: &Arc<InstanceIdentifier>, 426 given_policy: &Arc<Policy>, 427 dice_chain: &CertChain, 428 ) -> Result<i32, Error> { 429 match self.persistent_storage.read_instance_context(instance_id)? { 430 Some(instance_ctx) => { 431 self.enforce_rollback_protection_for_pvm( 432 instance_id, 433 given_policy, 434 &instance_ctx.dice_policy, 435 dice_chain, 436 true, 437 )?; 438 Ok(instance_ctx.sequence_number) 439 } 440 None => { 441 if !match_dice_chain_with_policy(dice_chain, given_policy)? { 442 return Err(am_err!( 443 DicePolicyMatchingFailed, 444 "the DICE chain doesn't match the given DICE policy." 445 )); 446 } 447 if !self.device.is_persistent_instance_creation_allowed(instance_id, dice_chain)? { 448 return Err(am_err!( 449 InstanceContextCreationDenied, 450 "the given persistent instance cannot be created" 451 )); 452 } 453 let sequence_number = self 454 .latest_global_sequence_number 455 .fetch_and_increment(&mut *self.persistent_storage)?; 456 self.persistent_storage.create_instance_context( 457 instance_id, 458 PersistentInstanceContext { 459 version: VERSION_PERSISTENT_INSTANCE_CONTEXT, 460 sequence_number, 461 dice_policy: Arc::clone(given_policy), 462 }, 463 )?; 464 Ok(sequence_number) 465 } 466 } 467 } 468 469 // A helper function for enforcing rollback protection on a pvm instance. enforce_rollback_protection_for_pvm( &mut self, instance_id: &Arc<InstanceIdentifier>, given_policy: &Arc<Policy>, stored_policy: &Policy, dice_chain: &CertChain, is_persistent: bool, ) -> Result<(), Error>470 fn enforce_rollback_protection_for_pvm( 471 &mut self, 472 instance_id: &Arc<InstanceIdentifier>, 473 given_policy: &Arc<Policy>, 474 stored_policy: &Policy, 475 dice_chain: &CertChain, 476 is_persistent: bool, 477 ) -> Result<(), Error> { 478 // First, match the given policy and the dice chain 479 if !match_dice_chain_with_policy(dice_chain, given_policy)? { 480 return Err(am_err!( 481 DicePolicyMatchingFailed, 482 "the DICE chain doesn't match the given DICE policy." 483 )); 484 } 485 if *stored_policy != **given_policy { 486 if !match_dice_chain_with_policy(dice_chain, stored_policy)? { 487 return Err(am_err!( 488 DicePolicyMatchingFailed, 489 "the DICE chain doesn't match the stored DICE policy." 490 )); 491 } 492 if is_persistent { 493 self.persistent_storage 494 .update_instance_policy_in_storage(instance_id, given_policy)?; 495 } else { 496 // TODO: b/399707150 497 return Err(am_err!( 498 Unimplemented, 499 "Non persistent instances are not yet supported." 500 )); 501 } 502 } 503 Ok(()) 504 } 505 506 // A helper method to enforce rollback protection for a client already in the cache. enforce_rollback_protection_for_client_in_cache( &mut self, instance_seq_number: i32, is_persistent: bool, authorized_client: &mut AuthorizedClient, given_dice_cert: &DiceChainEntry, given_policy: &Arc<Policy>, ) -> Result<(), Error>507 fn enforce_rollback_protection_for_client_in_cache( 508 &mut self, 509 instance_seq_number: i32, 510 is_persistent: bool, 511 authorized_client: &mut AuthorizedClient, 512 given_dice_cert: &DiceChainEntry, 513 given_policy: &Arc<Policy>, 514 ) -> Result<(), Error> { 515 self.enforce_rollback_protection_for_client( 516 instance_seq_number, 517 &authorized_client.client_id, 518 given_dice_cert, 519 given_policy, 520 &authorized_client.policy, 521 is_persistent, 522 )?; 523 if *authorized_client.policy != **given_policy { 524 // Update the policy in the cache as well 525 authorized_client.update_policy(given_policy); 526 } 527 Ok(()) 528 } 529 handle_client_in_persistent_storage( &mut self, instance_seq_number: i32, client_id: &Arc<ClientId>, given_dice_cert: &DiceChainEntry, given_policy: &Arc<Policy>, ) -> Result<i32, Error>530 fn handle_client_in_persistent_storage( 531 &mut self, 532 instance_seq_number: i32, 533 client_id: &Arc<ClientId>, 534 given_dice_cert: &DiceChainEntry, 535 given_policy: &Arc<Policy>, 536 ) -> Result<i32, Error> { 537 match self.persistent_storage.read_client_context(instance_seq_number, client_id)? { 538 Some(client_ctx) => { 539 self.enforce_rollback_protection_for_client( 540 instance_seq_number, 541 client_id, 542 given_dice_cert, 543 given_policy, 544 &client_ctx.dice_policy, 545 true, 546 )?; 547 Ok(client_ctx.sequence_number) 548 } 549 None => { 550 if !match_dice_cert_with_policy(given_dice_cert, given_policy)? { 551 return Err(am_err!( 552 DicePolicyMatchingFailed, 553 "the client's DICE leaf certificate doesn't match the given DICE policy" 554 )); 555 } 556 let sequence_number = self 557 .latest_global_sequence_number 558 .fetch_and_increment(&mut *self.persistent_storage)?; 559 self.persistent_storage.create_client_context( 560 instance_seq_number, 561 client_id, 562 PersistentClientContext { 563 version: VERSION_PERSISTENT_CLIENT_CONTEXT, 564 sequence_number, 565 dice_policy: Arc::clone(given_policy), 566 }, 567 )?; 568 Ok(sequence_number) 569 } 570 } 571 } 572 enforce_rollback_protection_for_client( &mut self, instance_seq_number: i32, client_id: &Arc<ClientId>, given_dice_cert: &DiceChainEntry, given_policy: &Arc<Policy>, stored_policy: &Policy, is_persistent: bool, ) -> Result<(), Error>573 fn enforce_rollback_protection_for_client( 574 &mut self, 575 instance_seq_number: i32, 576 client_id: &Arc<ClientId>, 577 given_dice_cert: &DiceChainEntry, 578 given_policy: &Arc<Policy>, 579 stored_policy: &Policy, 580 is_persistent: bool, 581 ) -> Result<(), Error> { 582 // First, match the given policy and the DICE certificate 583 if !match_dice_cert_with_policy(given_dice_cert, given_policy)? { 584 return Err(am_err!( 585 DicePolicyMatchingFailed, 586 "the client's DICE leaf certificate doesn't match the given DICE policy" 587 )); 588 } 589 if **given_policy != *stored_policy { 590 if !match_dice_cert_with_policy(given_dice_cert, stored_policy)? { 591 return Err(am_err!( 592 DicePolicyMatchingFailed, 593 "the client's DICE leaf certificate doesn't match the stored DICE policy" 594 )); 595 } 596 // Update the policy in the storage 597 if is_persistent { 598 self.persistent_storage.update_client_policy_in_storage( 599 instance_seq_number, 600 client_id, 601 given_policy, 602 )?; 603 } else { 604 // TODO: b/399707150 605 return Err(am_err!( 606 Unimplemented, 607 "Non persistent instances are not yet supported." 608 )); 609 } 610 } 611 Ok(()) 612 } 613 614 // We need to update the cache containing the global list of authorized clients with 615 // their full DICE artifacts to be used in the service exposed by the AuthMgr BE to the 616 // trusted services for matching DICE chain and DICE policies of the clients. update_global_list_of_authorized_clients( &mut self, state: &AuthenticatedConnectionState, client_seq_number: i32, client_id: &Arc<ClientId>, dice_leaf: &DiceChainEntry, given_policy: &Arc<Policy>, policy_need_update: bool, ) -> Result<(), Error>617 fn update_global_list_of_authorized_clients( 618 &mut self, 619 state: &AuthenticatedConnectionState, 620 client_seq_number: i32, 621 client_id: &Arc<ClientId>, 622 dice_leaf: &DiceChainEntry, 623 given_policy: &Arc<Policy>, 624 policy_need_update: bool, 625 ) -> Result<(), Error> { 626 match self.authorized_clients.get_mut(client_seq_number) { 627 Some(ref mut authorized_client) => { 628 if !authorized_client.full_dice_artifacts.cert_chain.is_current_leaf(dice_leaf) { 629 // This state is possible only if the client's DICE cert can change in runtime 630 // e.g. (loadable TAs) 631 let updated_full_dice_chain = (*state.dice_artifacts.cert_chain) 632 .extend_with(dice_leaf, &*self.crypto.ecdsa)?; 633 authorized_client.full_dice_artifacts.cert_chain = 634 Arc::new(updated_full_dice_chain); 635 } 636 637 if policy_need_update { 638 authorized_client.full_dice_artifacts.policy = Arc::new( 639 extend_dice_policy_with(&state.dice_artifacts.policy, given_policy)?, 640 ); 641 } 642 } 643 None => { 644 let client_full_dice_artifacts = DiceArtifacts { 645 cert_chain: Arc::new( 646 (*state.dice_artifacts.cert_chain) 647 .extend_with(dice_leaf, &*self.crypto.ecdsa)?, 648 ), 649 policy: Arc::new(extend_dice_policy_with( 650 &state.dice_artifacts.policy, 651 given_policy, 652 )?), 653 }; 654 655 self.authorized_clients.insert(AuthorizedClientFullDiceArtifacts { 656 sequence_number: client_seq_number, 657 transport_id: state.transport_id, 658 client_id: Arc::clone(client_id), 659 full_dice_artifacts: client_full_dice_artifacts, 660 })?; 661 } 662 } 663 Ok(()) 664 } 665 } 666