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