1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
18 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::SecretId::SecretId;
19 use authgraph_vts_test as ag_vts;
20 use authgraph_boringssl as boring;
21 use authgraph_core::key;
22 use coset::{CborOrdering, CborSerializable, CoseEncrypt0, CoseKey};
23 use dice_policy_builder::{TargetEntry, ConstraintSpec, ConstraintType, MissingAction, WILDCARD_FULL_ARRAY, policy_for_dice_chain};
24 use rdroidtest::{ignore_if, rdroidtest};
25 use secretkeeper_client::dice::OwnedDiceArtifactsWithExplicitKey;
26 use secretkeeper_client::{SkSession, Error as SkClientError};
27 use secretkeeper_core::cipher;
28 use secretkeeper_comm::data_types::error::SecretkeeperError;
29 use secretkeeper_comm::data_types::request::Request;
30 use secretkeeper_comm::data_types::request_response_impl::{
31 GetVersionRequest, GetVersionResponse, GetSecretRequest, GetSecretResponse, StoreSecretRequest,
32 StoreSecretResponse };
33 use secretkeeper_comm::data_types::{Id, Secret, SeqNum};
34 use secretkeeper_comm::data_types::response::Response;
35 use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType};
36 use secretkeeper_test::{
37 AUTHORITY_HASH, MODE, CONFIG_DESC, SECURITY_VERSION, SUBCOMPONENT_AUTHORITY_HASH,
38 SUBCOMPONENT_DESCRIPTORS, SUBCOMPONENT_SECURITY_VERSION,
39 dice_sample::{make_explicit_owned_dice_for_uds, make_explicit_owned_dice, make_large_explicit_owned_dice, CDI_SIZE}
40 };
41 use std::fs;
42 use std::path::Path;
43
44 const SECRETKEEPER_SERVICE: &str = "android.hardware.security.secretkeeper.ISecretkeeper";
45 const CURRENT_VERSION: u64 = 1;
46 const SECRETKEEPER_KEY_HOST_DT: &str =
47 "/proc/device-tree/avf/reference/avf/secretkeeper_public_key";
48
49 // Random bytes (of ID_SIZE/SECRET_SIZE) generated for tests.
50 const ID_EXAMPLE: Id = Id([
51 0xF1, 0xB2, 0xED, 0x3B, 0xD1, 0xBD, 0xF0, 0x7D, 0xE1, 0xF0, 0x01, 0xFC, 0x61, 0x71, 0xD3, 0x42,
52 0xE5, 0x8A, 0xAF, 0x33, 0x6C, 0x11, 0xDC, 0xC8, 0x6F, 0xAE, 0x12, 0x5C, 0x26, 0x44, 0x6B, 0x86,
53 0xCC, 0x24, 0xFD, 0xBF, 0x91, 0x4A, 0x54, 0x84, 0xF9, 0x01, 0x59, 0x25, 0x70, 0x89, 0x38, 0x8D,
54 0x5E, 0xE6, 0x91, 0xDF, 0x68, 0x60, 0x69, 0x26, 0xBE, 0xFE, 0x79, 0x58, 0xF7, 0xEA, 0x81, 0x7D,
55 ]);
56 const ID_EXAMPLE_2: Id = Id([
57 0x6A, 0xCC, 0xB1, 0xEB, 0xBB, 0xAB, 0xE3, 0xEA, 0x44, 0xBD, 0xDC, 0x75, 0x75, 0x7D, 0xC0, 0xE5,
58 0xC7, 0x86, 0x41, 0x56, 0x39, 0x66, 0x96, 0x10, 0xCB, 0x43, 0x10, 0x79, 0x03, 0xDC, 0xE6, 0x9F,
59 0x12, 0x2B, 0xEF, 0x28, 0x9C, 0x1E, 0x32, 0x46, 0x5F, 0xA3, 0xE7, 0x8D, 0x53, 0x63, 0xE8, 0x30,
60 0x5A, 0x17, 0x6F, 0xEF, 0x42, 0xD6, 0x58, 0x7A, 0xF0, 0xCB, 0xD4, 0x40, 0x58, 0x96, 0x32, 0xF4,
61 ]);
62 const ID_NOT_STORED: Id = Id([
63 0x56, 0xD0, 0x4E, 0xAA, 0xC1, 0x7B, 0x55, 0x6B, 0xA0, 0x2C, 0x65, 0x43, 0x39, 0x0A, 0x6C, 0xE9,
64 0x1F, 0xD0, 0x0E, 0x20, 0x3E, 0xFB, 0xF5, 0xF9, 0x3F, 0x5B, 0x11, 0x1B, 0x18, 0x73, 0xF6, 0xBB,
65 0xAB, 0x9F, 0xF2, 0xD6, 0xBD, 0xBA, 0x25, 0x68, 0x22, 0x30, 0xF2, 0x1F, 0x90, 0x05, 0xF3, 0x64,
66 0xE7, 0xEF, 0xC6, 0xB6, 0xA0, 0x85, 0xC9, 0x40, 0x40, 0xF0, 0xB4, 0xB9, 0xD8, 0x28, 0xEE, 0x9C,
67 ]);
68 const SECRET_EXAMPLE: Secret = Secret([
69 0xA9, 0x89, 0x97, 0xFE, 0xAE, 0x97, 0x55, 0x4B, 0x32, 0x35, 0xF0, 0xE8, 0x93, 0xDA, 0xEA, 0x24,
70 0x06, 0xAC, 0x36, 0x8B, 0x3C, 0x95, 0x50, 0x16, 0x67, 0x71, 0x65, 0x26, 0xEB, 0xD0, 0xC3, 0x98,
71 ]);
72
73 // Android expects the public key of Secretkeeper instance to be present in the Linux device tree.
74 // This allows clients to (cryptographically) verify that they are indeed talking to the real
75 // secretkeeper.
76 // Note that this is the identity of the `default` instance (and not `nonsecure`)!
get_secretkeeper_identity() -> Option<CoseKey>77 fn get_secretkeeper_identity() -> Option<CoseKey> {
78 let path = Path::new(SECRETKEEPER_KEY_HOST_DT);
79 if path.exists() {
80 let key = fs::read(path).unwrap();
81 let mut key = CoseKey::from_slice(&key).unwrap();
82 key.canonicalize(CborOrdering::Lexicographic);
83 Some(key)
84 } else {
85 None
86 }
87 }
88
get_instances() -> Vec<(String, String)>89 fn get_instances() -> Vec<(String, String)> {
90 // Determine which instances are available.
91 binder::get_declared_instances(SECRETKEEPER_SERVICE)
92 .unwrap_or_default()
93 .into_iter()
94 .map(|v| (v.clone(), v))
95 .collect()
96 }
97
get_connection(instance: &str) -> binder::Strong<dyn ISecretkeeper>98 fn get_connection(instance: &str) -> binder::Strong<dyn ISecretkeeper> {
99 let name = format!("{SECRETKEEPER_SERVICE}/{instance}");
100 binder::get_interface(&name).unwrap()
101 }
102
103 /// Secretkeeper client information.
104 #[derive(Debug)]
105 struct SkClient {
106 sk: binder::Strong<dyn ISecretkeeper>,
107 session: SkSession,
108 dice_artifacts: OwnedDiceArtifactsWithExplicitKey,
109 }
110
111 impl Drop for SkClient {
drop(&mut self)112 fn drop(&mut self) {
113 // Delete any IDs that may be left over.
114 self.delete(&[&ID_EXAMPLE, &ID_EXAMPLE_2]);
115 }
116 }
117
118 impl SkClient {
119 /// Create an `SkClient` using the default `OwnedDiceArtifactsWithExplicitKey` for identity.
new(instance: &str) -> Result<Self, SkClientError>120 fn new(instance: &str) -> Result<Self, SkClientError> {
121 let default_dice = make_explicit_owned_dice(/*Security version in a node */ 5);
122 Self::create(instance, default_dice, None)
123 }
124
125 /// Create an `SkClient` using given `OwnedDiceArtifactsWithExplicitKey` as client identity.
with_identity( instance: &str, dice_artifacts: OwnedDiceArtifactsWithExplicitKey, ) -> Result<Self, SkClientError>126 fn with_identity(
127 instance: &str,
128 dice_artifacts: OwnedDiceArtifactsWithExplicitKey,
129 ) -> Result<Self, SkClientError> {
130 Self::create(instance, dice_artifacts, None)
131 }
132
133 /// Create an `SkClient` with default client identity, requiring Secretkeeper's identity to be
134 /// matched against given `expected_sk_key`.
with_expected_sk_identity( instance: &str, expected_sk_key: coset::CoseKey, ) -> Result<Self, SkClientError>135 fn with_expected_sk_identity(
136 instance: &str,
137 expected_sk_key: coset::CoseKey,
138 ) -> Result<Self, SkClientError> {
139 let default_dice = make_explicit_owned_dice(/*Security version in a node */ 5);
140 Self::create(instance, default_dice, Some(expected_sk_key))
141 }
142
create( instance: &str, dice_artifacts: OwnedDiceArtifactsWithExplicitKey, expected_sk_key: Option<coset::CoseKey>, ) -> Result<Self, SkClientError>143 fn create(
144 instance: &str,
145 dice_artifacts: OwnedDiceArtifactsWithExplicitKey,
146 expected_sk_key: Option<coset::CoseKey>,
147 ) -> Result<Self, SkClientError> {
148 let sk = get_connection(instance);
149 Ok(Self {
150 sk: sk.clone(),
151 session: SkSession::new(sk, &dice_artifacts, expected_sk_key)?,
152 dice_artifacts,
153 })
154 }
155
156 /// This method is wrapper that use `SkSession::secret_management_request` which handles
157 /// encryption and decryption.
secret_management_request(&mut self, req_data: &[u8]) -> Result<Vec<u8>, Error>158 fn secret_management_request(&mut self, req_data: &[u8]) -> Result<Vec<u8>, Error> {
159 Ok(self.session.secret_management_request(req_data)?)
160 }
161
162 /// Unlike the method [`secret_management_request`], this method directly uses
163 /// `cipher::encrypt_message` & `cipher::decrypt_message`, allowing finer control of request
164 /// & response aad.
secret_management_request_custom_aad( &self, req_data: &[u8], req_aad: &[u8], expected_res_aad: &[u8], ) -> Result<Vec<u8>, Error>165 fn secret_management_request_custom_aad(
166 &self,
167 req_data: &[u8],
168 req_aad: &[u8],
169 expected_res_aad: &[u8],
170 ) -> Result<Vec<u8>, Error> {
171 let aes_gcm = boring::BoringAes;
172 let rng = boring::BoringRng;
173 let request_bytes = cipher::encrypt_message(
174 &aes_gcm,
175 &rng,
176 self.session.encryption_key(),
177 self.session.session_id(),
178 &req_data,
179 req_aad,
180 )
181 .map_err(|e| secretkeeper_client::Error::CipherError(e))?;
182
183 // Binder call!
184 let response_bytes = self.sk.processSecretManagementRequest(&request_bytes)?;
185
186 let response_encrypt0 = CoseEncrypt0::from_slice(&response_bytes)?;
187 Ok(cipher::decrypt_message(
188 &aes_gcm,
189 self.session.decryption_key(),
190 &response_encrypt0,
191 expected_res_aad,
192 )
193 .map_err(|e| secretkeeper_client::Error::CipherError(e))?)
194 }
195
196 /// Helper method to store a secret. This uses the default compatible sealing_policy on
197 /// dice_chain.
store(&mut self, id: &Id, secret: &Secret) -> Result<(), Error>198 fn store(&mut self, id: &Id, secret: &Secret) -> Result<(), Error> {
199 let sealing_policy = sealing_policy(
200 self.dice_artifacts.explicit_key_dice_chain().ok_or(Error::UnexpectedError)?,
201 );
202 let store_request =
203 StoreSecretRequest { id: id.clone(), secret: secret.clone(), sealing_policy };
204 let store_request = store_request.serialize_to_packet().to_vec()?;
205
206 let store_response = self.secret_management_request(&store_request)?;
207 let store_response = ResponsePacket::from_slice(&store_response)?;
208
209 assert_eq!(store_response.response_type()?, ResponseType::Success);
210 // Really just checking that the response is indeed StoreSecretResponse
211 let _ = StoreSecretResponse::deserialize_from_packet(store_response)?;
212 Ok(())
213 }
214
215 /// Helper method to get a secret.
get(&mut self, id: &Id) -> Result<Secret, Error>216 fn get(&mut self, id: &Id) -> Result<Secret, Error> {
217 self.get_update_policy(id, None)
218 }
219
220 /// Helper method to get a secret, updating the sealing policy along the way.
get_update_policy( &mut self, id: &Id, updated_sealing_policy: Option<Vec<u8>>, ) -> Result<Secret, Error>221 fn get_update_policy(
222 &mut self,
223 id: &Id,
224 updated_sealing_policy: Option<Vec<u8>>,
225 ) -> Result<Secret, Error> {
226 let get_request = GetSecretRequest { id: id.clone(), updated_sealing_policy };
227 let get_request = get_request.serialize_to_packet().to_vec()?;
228
229 let get_response = self.secret_management_request(&get_request)?;
230 let get_response = ResponsePacket::from_slice(&get_response)?;
231
232 if get_response.response_type()? == ResponseType::Success {
233 let get_response = *GetSecretResponse::deserialize_from_packet(get_response)?;
234 Ok(Secret(get_response.secret.0))
235 } else {
236 let err = *SecretkeeperError::deserialize_from_packet(get_response)?;
237 Err(Error::SecretkeeperError(err))
238 }
239 }
240
241 /// Helper method to delete secrets.
delete(&self, ids: &[&Id])242 fn delete(&self, ids: &[&Id]) {
243 let ids: Vec<SecretId> = ids.iter().map(|id| SecretId { id: id.0 }).collect();
244 self.sk.deleteIds(&ids).unwrap();
245 }
246
247 /// Helper method to delete everything.
delete_all(&self)248 fn delete_all(&self) {
249 self.sk.deleteAll().unwrap();
250 }
251 }
252
253 #[derive(Debug)]
254 enum Error {
255 // Errors from Secretkeeper API errors. These are thrown by core SecretManagement and
256 // not visible without decryption.
257 SecretkeeperError(SecretkeeperError),
258 InfraError(secretkeeper_client::Error),
259 UnexpectedError,
260 }
261
262 impl From<secretkeeper_client::Error> for Error {
from(e: secretkeeper_client::Error) -> Self263 fn from(e: secretkeeper_client::Error) -> Self {
264 Self::InfraError(e)
265 }
266 }
267
268 impl From<SecretkeeperError> for Error {
from(e: SecretkeeperError) -> Self269 fn from(e: SecretkeeperError) -> Self {
270 Self::SecretkeeperError(e)
271 }
272 }
273
274 impl From<coset::CoseError> for Error {
from(e: coset::CoseError) -> Self275 fn from(e: coset::CoseError) -> Self {
276 Self::InfraError(secretkeeper_client::Error::from(e))
277 }
278 }
279
280 impl From<binder::Status> for Error {
from(s: binder::Status) -> Self281 fn from(s: binder::Status) -> Self {
282 Self::InfraError(secretkeeper_client::Error::from(s))
283 }
284 }
285
286 impl From<secretkeeper_comm::data_types::error::Error> for Error {
from(e: secretkeeper_comm::data_types::error::Error) -> Self287 fn from(e: secretkeeper_comm::data_types::error::Error) -> Self {
288 Self::InfraError(secretkeeper_client::Error::from(e))
289 }
290 }
291
292 // Assert that the error is `EntryNotFound`.
assert_entry_not_found(res: Result<Secret, Error>)293 fn assert_entry_not_found(res: Result<Secret, Error>) {
294 assert_result_matches(res, SecretkeeperError::EntryNotFound)
295 }
296
297 // Assert that the error is `DicePolicyError`.
assert_dice_policy_error(res: Result<Secret, Error>)298 fn assert_dice_policy_error(res: Result<Secret, Error>) {
299 assert_result_matches(res, SecretkeeperError::DicePolicyError)
300 }
301
assert_result_matches(res: Result<Secret, Error>, want: SecretkeeperError)302 fn assert_result_matches(res: Result<Secret, Error>, want: SecretkeeperError) {
303 match res {
304 Err(Error::SecretkeeperError(e)) if e == want => {}
305 Err(got) => panic!("unexpected error {got:?}, expected {want:?}"),
306 Ok(_) => panic!("unexpected success instead of {want:?}"),
307 }
308 }
309
310 /// Construct a sealing policy on the dice chain. This method uses the following set of
311 /// constraints which are compatible with sample DICE chains used in VTS.
312 /// 1. ExactMatch on AUTHORITY_HASH (non-optional).
313 /// 2. ExactMatch on MODE (non-optional).
314 /// 3. GreaterOrEqual on SECURITY_VERSION (optional).
315 /// 4. The DiceChainEntry corresponding to "AVB" contains SubcomponentDescriptor, for each of those:
316 /// a) GreaterOrEqual on SECURITY_VERSION (Required)
317 // b) ExactMatch on AUTHORITY_HASH (Required).
sealing_policy(dice: &[u8]) -> Vec<u8>318 fn sealing_policy(dice: &[u8]) -> Vec<u8> {
319 let constraint_spec = vec![
320 ConstraintSpec::new(
321 ConstraintType::ExactMatch,
322 vec![AUTHORITY_HASH],
323 MissingAction::Fail,
324 TargetEntry::All,
325 ),
326 ConstraintSpec::new(
327 ConstraintType::ExactMatch,
328 vec![MODE],
329 MissingAction::Fail,
330 TargetEntry::All,
331 ),
332 ConstraintSpec::new(
333 ConstraintType::GreaterOrEqual,
334 vec![CONFIG_DESC, SECURITY_VERSION],
335 MissingAction::Ignore,
336 TargetEntry::All,
337 ),
338 ConstraintSpec::new(
339 ConstraintType::GreaterOrEqual,
340 vec![
341 CONFIG_DESC,
342 SUBCOMPONENT_DESCRIPTORS,
343 WILDCARD_FULL_ARRAY,
344 SUBCOMPONENT_SECURITY_VERSION,
345 ],
346 MissingAction::Fail,
347 TargetEntry::ByName("AVB".to_string()),
348 ),
349 ConstraintSpec::new(
350 ConstraintType::ExactMatch,
351 vec![
352 CONFIG_DESC,
353 SUBCOMPONENT_DESCRIPTORS,
354 WILDCARD_FULL_ARRAY,
355 SUBCOMPONENT_AUTHORITY_HASH,
356 ],
357 MissingAction::Fail,
358 TargetEntry::ByName("AVB".to_string()),
359 ),
360 ];
361
362 policy_for_dice_chain(dice, constraint_spec).unwrap().to_vec().unwrap()
363 }
364
365 /// Perform AuthGraph key exchange, returning the session keys and session ID.
authgraph_key_exchange(sk: binder::Strong<dyn ISecretkeeper>) -> ([key::AesKey; 2], Vec<u8>)366 fn authgraph_key_exchange(sk: binder::Strong<dyn ISecretkeeper>) -> ([key::AesKey; 2], Vec<u8>) {
367 let sink = sk.getAuthGraphKe().expect("failed to get AuthGraph");
368 let mut source = ag_vts::test_ag_participant().expect("failed to create a local source");
369 ag_vts::sink::test_mainline(&mut source, sink)
370 }
371
372 // Test that the AuthGraph instance returned by SecretKeeper correctly performs
373 // mainline key exchange against a local source implementation.
374 #[rdroidtest(get_instances())]
authgraph_mainline(instance: String)375 fn authgraph_mainline(instance: String) {
376 let sk = get_connection(&instance);
377 let (_aes_keys, _session_id) = authgraph_key_exchange(sk);
378 }
379
380 // Test that the AuthGraph instance returned by SecretKeeper correctly rejects
381 // a corrupted session ID signature.
382 #[rdroidtest(get_instances())]
authgraph_corrupt_sig(instance: String)383 fn authgraph_corrupt_sig(instance: String) {
384 let sk = get_connection(&instance);
385 let sink = sk.getAuthGraphKe().expect("failed to get AuthGraph");
386 let mut source = ag_vts::test_ag_participant().expect("failed to create a local source");
387 ag_vts::sink::test_corrupt_sig(&mut source, sink);
388 }
389
390 // Test that the AuthGraph instance returned by SecretKeeper correctly detects
391 // when corrupted keys are returned to it.
392 #[rdroidtest(get_instances())]
authgraph_corrupt_keys(instance: String)393 fn authgraph_corrupt_keys(instance: String) {
394 let sk = get_connection(&instance);
395 let sink = sk.getAuthGraphKe().expect("failed to get AuthGraph");
396 let mut source = ag_vts::test_ag_participant().expect("failed to create a local source");
397 ag_vts::sink::test_corrupt_keys(&mut source, sink);
398 }
399
400 // TODO(b/2797757): Add tests that match different HAL defined objects (like request/response)
401 // with expected bytes.
402
403 #[rdroidtest(get_instances())]
secret_management_get_version(instance: String)404 fn secret_management_get_version(instance: String) {
405 let mut sk_client = SkClient::new(&instance).unwrap();
406
407 let request = GetVersionRequest {};
408 let request_packet = request.serialize_to_packet();
409 let request_bytes = request_packet.to_vec().unwrap();
410
411 let response_bytes = sk_client.secret_management_request(&request_bytes).unwrap();
412
413 let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
414 assert_eq!(response_packet.response_type().unwrap(), ResponseType::Success);
415 let get_version_response =
416 *GetVersionResponse::deserialize_from_packet(response_packet).unwrap();
417 assert_eq!(get_version_response.version, CURRENT_VERSION);
418 }
419
420 #[rdroidtest(get_instances())]
secret_management_malformed_request(instance: String)421 fn secret_management_malformed_request(instance: String) {
422 let mut sk_client = SkClient::new(&instance).unwrap();
423
424 let request = GetVersionRequest {};
425 let request_packet = request.serialize_to_packet();
426 let mut request_bytes = request_packet.to_vec().unwrap();
427
428 // Deform the request
429 request_bytes[0] = !request_bytes[0];
430
431 let response_bytes = sk_client.secret_management_request(&request_bytes).unwrap();
432
433 let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
434 assert_eq!(response_packet.response_type().unwrap(), ResponseType::Error);
435 let err = *SecretkeeperError::deserialize_from_packet(response_packet).unwrap();
436 assert_eq!(err, SecretkeeperError::RequestMalformed);
437 }
438
439 #[rdroidtest(get_instances())]
secret_management_store_get_secret_found(instance: String)440 fn secret_management_store_get_secret_found(instance: String) {
441 let mut sk_client = SkClient::new(&instance).unwrap();
442
443 sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
444
445 // Get the secret that was just stored
446 assert_eq!(sk_client.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
447 }
448
449 #[rdroidtest(get_instances())]
secret_management_store_get_secret_not_found(instance: String)450 fn secret_management_store_get_secret_not_found(instance: String) {
451 let mut sk_client = SkClient::new(&instance).unwrap();
452
453 // Store a secret (corresponding to an id).
454 sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
455
456 // Get the secret that was never stored
457 assert_entry_not_found(sk_client.get(&ID_NOT_STORED));
458 }
459
460 /// A secret stored in one session should be accessible from a different session
461 /// as long as the client has the same identity.
462 #[rdroidtest(get_instances())]
secretkeeper_get_secret_across_sessions_with_same_identity(instance: String)463 fn secretkeeper_get_secret_across_sessions_with_same_identity(instance: String) {
464 // Store a secret with one session. Note that we need to hang on to the
465 // test client because it auto-deletes entries on drop.
466 let mut sk_client1 = SkClient::new(&instance).unwrap();
467 sk_client1.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
468 assert_eq!(sk_client1.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
469
470 // Retrieve the secret using a different session (that has the same identity).
471 let mut sk_client2 = SkClient::new(&instance).unwrap();
472 assert_eq!(sk_client2.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
473 }
474
475 /// A secret stored in one session should not be accessible from a different session
476 /// if the client has a different identity.
477 #[rdroidtest(get_instances())]
secretkeeper_no_secret_across_sessions_with_different_identity(instance: String)478 fn secretkeeper_no_secret_across_sessions_with_different_identity(instance: String) {
479 // Store a secret with one session. Note that we need to hang on to the
480 // test client because it auto-deletes entries on drop.
481 let mut sk_client1 = SkClient::new(&instance).unwrap();
482 sk_client1.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
483 assert_eq!(sk_client1.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
484
485 // Fail to retrieve the secret using a different session that has a different identity.
486 pub const ALT_UDS: &[u8; CDI_SIZE] = &[
487 0x66, 0x4f, 0xab, 0xa9, 0xa5, 0xad, 0x0f, 0x5e, 0x15, 0xc3, 0x12, 0xf7, 0x77, 0x45, 0xfa,
488 0x56, 0x18, 0x6a, 0xa6, 0x34, 0xb6, 0x7c, 0x82, 0x7b, 0x89, 0x4c, 0xc5, 0x52, 0xd3, 0x27,
489 0x36, 0x8e,
490 ];
491 let alt_identity = make_explicit_owned_dice_for_uds(5, ALT_UDS);
492 let mut sk_client2 = SkClient::with_identity(&instance, alt_identity).unwrap();
493 assert_dice_policy_error(sk_client2.get(&ID_EXAMPLE));
494 }
495
496 #[rdroidtest(get_instances())]
secretkeeper_store_delete_ids(instance: String)497 fn secretkeeper_store_delete_ids(instance: String) {
498 let mut sk_client = SkClient::new(&instance).unwrap();
499
500 sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
501 sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
502 sk_client.delete(&[&ID_EXAMPLE]);
503 assert_entry_not_found(sk_client.get(&ID_EXAMPLE));
504 assert_eq!(sk_client.get(&ID_EXAMPLE_2).unwrap(), SECRET_EXAMPLE);
505
506 sk_client.delete(&[&ID_EXAMPLE_2]);
507
508 assert_entry_not_found(sk_client.get(&ID_EXAMPLE));
509 assert_entry_not_found(sk_client.get(&ID_EXAMPLE_2));
510 }
511
512 #[rdroidtest(get_instances())]
secretkeeper_store_delete_multiple_ids(instance: String)513 fn secretkeeper_store_delete_multiple_ids(instance: String) {
514 let mut sk_client = SkClient::new(&instance).unwrap();
515
516 sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
517 sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
518 sk_client.delete(&[&ID_EXAMPLE, &ID_EXAMPLE_2]);
519
520 assert_entry_not_found(sk_client.get(&ID_EXAMPLE));
521 assert_entry_not_found(sk_client.get(&ID_EXAMPLE_2));
522 }
523 #[rdroidtest(get_instances())]
secretkeeper_store_delete_duplicate_ids(instance: String)524 fn secretkeeper_store_delete_duplicate_ids(instance: String) {
525 let mut sk_client = SkClient::new(&instance).unwrap();
526
527 sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
528 sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
529 // Delete the same secret twice.
530 sk_client.delete(&[&ID_EXAMPLE, &ID_EXAMPLE]);
531
532 assert_entry_not_found(sk_client.get(&ID_EXAMPLE));
533 assert_eq!(sk_client.get(&ID_EXAMPLE_2).unwrap(), SECRET_EXAMPLE);
534 }
535
536 #[rdroidtest(get_instances())]
secretkeeper_store_delete_nonexistent(instance: String)537 fn secretkeeper_store_delete_nonexistent(instance: String) {
538 let mut sk_client = SkClient::new(&instance).unwrap();
539
540 sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
541 sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
542 sk_client.delete(&[&ID_NOT_STORED]);
543
544 assert_eq!(sk_client.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
545 assert_eq!(sk_client.get(&ID_EXAMPLE_2).unwrap(), SECRET_EXAMPLE);
546 assert_entry_not_found(sk_client.get(&ID_NOT_STORED));
547 }
548
549 // Don't run deleteAll() on a secure device, as it might affect real secrets.
550 #[rdroidtest(get_instances())]
551 #[ignore_if(|p| p != "nonsecure")]
secretkeeper_store_delete_all(instance: String)552 fn secretkeeper_store_delete_all(instance: String) {
553 let mut sk_client = SkClient::new(&instance).unwrap();
554
555 sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
556 sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
557
558 sk_client.delete_all();
559
560 assert_entry_not_found(sk_client.get(&ID_EXAMPLE));
561 assert_entry_not_found(sk_client.get(&ID_EXAMPLE_2));
562
563 // Store a new secret (corresponding to an id).
564 sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
565
566 // Get the restored secret.
567 assert_eq!(sk_client.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
568
569 // (Try to) Get the secret that was never stored
570 assert_entry_not_found(sk_client.get(&ID_NOT_STORED));
571 }
572
573 // This tests creates lots of sessions one after another, to confirm that the Secretkeeper
574 // instance doesn't have unbounded internal state. (Instead, it should drop older sessions
575 // and the clients using those sessions would need to re-establish a new session.)
576 #[rdroidtest(get_instances())]
secretkeeper_many_sessions_serial(instance: String)577 fn secretkeeper_many_sessions_serial(instance: String) {
578 const SESSION_COUNT: usize = 32;
579 let mut sk_clients = Vec::new();
580 for idx in 0..SESSION_COUNT {
581 let identity = make_large_explicit_owned_dice(5);
582 let mut sk_client = SkClient::with_identity(&instance, identity)
583 .expect(&format!("failed to establish session {idx}"));
584 sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
585 sk_clients.push(sk_client);
586 }
587 }
588
589 // This tests creates lots of sessions in parallel. Some of these session are expected
590 // to fail, but the Secretkeeper TA should survive the experience.
591 #[rdroidtest(get_instances())]
secretkeeper_many_sessions_parallel(instance: String)592 fn secretkeeper_many_sessions_parallel(instance: String) {
593 const SESSION_COUNT: usize = 32;
594
595 let mut handles = Vec::<std::thread::JoinHandle<()>>::new();
596 for idx in 0..SESSION_COUNT {
597 let instance = instance.clone();
598 handles.push(std::thread::spawn(move || {
599 // In each thread, create a session and use it. This may (legitimately) fail at any
600 // moment.
601 let _result = use_sk_may_fail(instance, idx);
602 }));
603 }
604
605 // Wait for all activity to quiesce.
606 for handle in handles {
607 let _result = handle.join();
608 }
609
610 // Now that all the parallel activity is done, should still be able to interact with
611 // Secretkeeper.
612 let mut sk_client = SkClient::new(&instance).unwrap();
613 sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
614 assert_eq!(sk_client.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
615
616 // Remove any IDs that might have been stored in the test.
617 for idx in 0..SESSION_COUNT {
618 let mut id = ID_EXAMPLE.clone();
619 id.0[0] = idx as u8;
620 sk_client.delete(&[&id]);
621 }
622 }
623
use_sk_may_fail(instance: String, idx: usize) -> Result<(), Error>624 fn use_sk_may_fail(instance: String, idx: usize) -> Result<(), Error> {
625 let identity = make_large_explicit_owned_dice(5);
626 let mut sk_client = SkClient::with_identity(&instance, identity)?;
627 let mut id = ID_EXAMPLE.clone();
628 id.0[0] = idx as u8;
629
630 sk_client.store(&id, &SECRET_EXAMPLE)?;
631 let result = sk_client.get(&id)?;
632 assert_eq!(result, SECRET_EXAMPLE);
633 Ok(())
634 }
635
636 // This test checks that Secretkeeper uses the expected [`RequestSeqNum`] as aad while
637 // decrypting requests and the responses are encrypted with correct [`ResponseSeqNum`] for the
638 // first few messages.
639 #[rdroidtest(get_instances())]
secret_management_replay_protection_seq_num(instance: String)640 fn secret_management_replay_protection_seq_num(instance: String) {
641 let dice_chain = make_explicit_owned_dice(/*Security version in a node */ 5);
642 let sealing_policy = sealing_policy(dice_chain.explicit_key_dice_chain().unwrap());
643 let sk_client = SkClient::with_identity(&instance, dice_chain).unwrap();
644 // Construct encoded request packets for the test
645 let (req_1, req_2, req_3) = construct_secret_management_requests(sealing_policy);
646
647 // Lets now construct the seq_numbers(in request & expected in response)
648 let mut seq_a = SeqNum::new();
649 let [seq_0, seq_1, seq_2] = std::array::from_fn(|_| seq_a.get_then_increment().unwrap());
650
651 // Check first request/response is successful
652 let res = ResponsePacket::from_slice(
653 &sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0).unwrap(),
654 )
655 .unwrap();
656 assert_eq!(res.response_type().unwrap(), ResponseType::Success);
657
658 // Check 2nd request/response is successful
659 let res = ResponsePacket::from_slice(
660 &sk_client.secret_management_request_custom_aad(&req_2, &seq_1, &seq_1).unwrap(),
661 )
662 .unwrap();
663 assert_eq!(res.response_type().unwrap(), ResponseType::Success);
664
665 // Check 3rd request/response is successful
666 let res = ResponsePacket::from_slice(
667 &sk_client.secret_management_request_custom_aad(&req_3, &seq_2, &seq_2).unwrap(),
668 )
669 .unwrap();
670 assert_eq!(res.response_type().unwrap(), ResponseType::Success);
671 }
672
673 // This test checks that Secretkeeper uses fresh [`RequestSeqNum`] & [`ResponseSeqNum`]
674 // for new sessions.
675 #[rdroidtest(get_instances())]
secret_management_replay_protection_seq_num_per_session(instance: String)676 fn secret_management_replay_protection_seq_num_per_session(instance: String) {
677 let dice_chain = make_explicit_owned_dice(/*Security version in a node */ 5);
678 let sealing_policy = sealing_policy(dice_chain.explicit_key_dice_chain().unwrap());
679 let sk_client = SkClient::with_identity(&instance, dice_chain).unwrap();
680
681 // Construct encoded request packets for the test
682 let (req_1, _, _) = construct_secret_management_requests(sealing_policy);
683
684 // Lets now construct the seq_number (in request & expected in response)
685 let mut seq_a = SeqNum::new();
686 let seq_0 = seq_a.get_then_increment().unwrap();
687 // Check first request/response is successful
688 let res = ResponsePacket::from_slice(
689 &sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0).unwrap(),
690 )
691 .unwrap();
692 assert_eq!(res.response_type().unwrap(), ResponseType::Success);
693
694 // Start another session
695 let sk_client_diff = SkClient::new(&instance).unwrap();
696 // Check first request/response is with seq_0 is successful
697 let res = ResponsePacket::from_slice(
698 &sk_client_diff.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0).unwrap(),
699 )
700 .unwrap();
701 assert_eq!(res.response_type().unwrap(), ResponseType::Success);
702 }
703
704 // This test checks that Secretkeeper rejects requests with out of order [`RequestSeqNum`]
705 // TODO(b/317416663): This test fails, when HAL is not present in the device. Refactor to fix this.
706 #[rdroidtest(get_instances())]
secret_management_replay_protection_out_of_seq_req_not_accepted(instance: String)707 fn secret_management_replay_protection_out_of_seq_req_not_accepted(instance: String) {
708 let dice_chain = make_explicit_owned_dice(/*Security version in a node */ 5);
709 let sealing_policy = sealing_policy(dice_chain.explicit_key_dice_chain().unwrap());
710 let sk_client = SkClient::with_identity(&instance, dice_chain).unwrap();
711
712 // Construct encoded request packets for the test
713 let (req_1, req_2, _) = construct_secret_management_requests(sealing_policy);
714
715 // Lets now construct the seq_numbers(in request & expected in response)
716 let mut seq_a = SeqNum::new();
717 let [seq_0, seq_1, seq_2] = std::array::from_fn(|_| seq_a.get_then_increment().unwrap());
718
719 // Assume First request/response is successful
720 sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0).unwrap();
721
722 // Check 2nd request/response with skipped seq_num in request is a binder error
723 let res = sk_client
724 .secret_management_request_custom_aad(&req_2, /*Skipping seq_1*/ &seq_2, &seq_1);
725 let err = res.expect_err("Out of Seq messages accepted!");
726 // Incorrect sequence numbers lead to failed decryption. The resultant error should be
727 // thrown in clear text & wrapped in Binder errors.
728 assert!(matches!(err, Error::InfraError(secretkeeper_client::Error::BinderStatus(_e))));
729 }
730
731 // This test checks DICE policy based access control of Secretkeeper.
732 #[rdroidtest(get_instances())]
secret_management_policy_gate(instance: String)733 fn secret_management_policy_gate(instance: String) {
734 let dice_chain = make_explicit_owned_dice(/*Security version in a node */ 100);
735 let mut sk_client_original = SkClient::with_identity(&instance, dice_chain).unwrap();
736 sk_client_original.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
737 assert_eq!(sk_client_original.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
738
739 // Start a session with higher security_version & get the stored secret.
740 let dice_chain_upgraded = make_explicit_owned_dice(/*Security version in a node */ 101);
741 let mut sk_client_upgraded = SkClient::with_identity(&instance, dice_chain_upgraded).unwrap();
742 assert_eq!(sk_client_upgraded.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
743
744 // Start a session with lower security_version (This should be denied access to the secret).
745 let dice_chain_downgraded = make_explicit_owned_dice(/*Security version in a node */ 99);
746 let mut sk_client_downgraded =
747 SkClient::with_identity(&instance, dice_chain_downgraded).unwrap();
748 assert_dice_policy_error(sk_client_downgraded.get(&ID_EXAMPLE));
749
750 // Now get the secret with the later version, and upgrade the sealing policy along the way.
751 let sealing_policy =
752 sealing_policy(sk_client_upgraded.dice_artifacts.explicit_key_dice_chain().unwrap());
753 assert_eq!(
754 sk_client_upgraded.get_update_policy(&ID_EXAMPLE, Some(sealing_policy)).unwrap(),
755 SECRET_EXAMPLE
756 );
757
758 // The original version of the client should no longer be able to retrieve the secret.
759 assert_dice_policy_error(sk_client_original.get(&ID_EXAMPLE));
760 }
761
762 // This test checks that the identity of Secretkeeper (in context of AuthGraph key exchange) is
763 // same as the one advertized in Linux device tree. This is only expected from `default` instance.
764 #[rdroidtest(get_instances())]
765 #[ignore_if(|p| p != "default")]
secretkeeper_check_identity(instance: String)766 fn secretkeeper_check_identity(instance: String) {
767 let sk_key = get_secretkeeper_identity()
768 .expect("Failed to extract identity of default instance from device tree");
769 // Create a session with this expected identity. This succeeds only if the identity used by
770 // Secretkeeper is sk_key.
771 let _ = SkClient::with_expected_sk_identity(&instance, sk_key).unwrap();
772 // Create a session using any other expected sk identity, this should fail. Note that the
773 // failure arises from validation which happens at the local participant.
774 let mut any_other_key = CoseKey::default();
775 any_other_key.canonicalize(CborOrdering::Lexicographic);
776 let err = SkClient::with_expected_sk_identity(&instance, any_other_key).unwrap_err();
777 assert!(matches!(
778 err,
779 SkClientError::AuthgraphError(authgraph_core::error::Error(
780 authgraph_wire::ErrorCode::InvalidPeerKeKey,
781 _
782 ))
783 ));
784 }
785
786 // Helper method that constructs 3 SecretManagement requests. Callers would usually not care about
787 // what each of the request concretely is.
construct_secret_management_requests(sealing_policy: Vec<u8>) -> (Vec<u8>, Vec<u8>, Vec<u8>)788 fn construct_secret_management_requests(sealing_policy: Vec<u8>) -> (Vec<u8>, Vec<u8>, Vec<u8>) {
789 let version_request = GetVersionRequest {};
790 let version_request = version_request.serialize_to_packet().to_vec().unwrap();
791 let store_request =
792 StoreSecretRequest { id: ID_EXAMPLE, secret: SECRET_EXAMPLE, sealing_policy };
793 let store_request = store_request.serialize_to_packet().to_vec().unwrap();
794 let get_request = GetSecretRequest { id: ID_EXAMPLE, updated_sealing_policy: None };
795 let get_request = get_request.serialize_to_packet().to_vec().unwrap();
796 (version_request, store_request, get_request)
797 }
798
799 rdroidtest::test_main!();
800