From 5f4493d75b3e3b320fdea9a42d807aca5a048808 Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Thu, 14 Mar 2024 10:14:07 +0000 Subject: [PATCH] Secretkeeper: more VTS tests Add tests for: - large number of session creations - also use a bigger identity, to better simulate real use - attempt to retrieve a secret with an incorrect identity Test: VtsSecretkeeperTargetTest (shiba) Bug: 327526008 Change-Id: I8dddf643d03a8fb679511564cb03c2248477c116 --- security/secretkeeper/aidl/vts/Android.bp | 1 + security/secretkeeper/aidl/vts/dice_sample.rs | 226 +++++++++++++++++- .../aidl/vts/secretkeeper_test_client.rs | 128 +++++++++- 3 files changed, 333 insertions(+), 22 deletions(-) diff --git a/security/secretkeeper/aidl/vts/Android.bp b/security/secretkeeper/aidl/vts/Android.bp index b9ce5cea86..be07a7ba66 100644 --- a/security/secretkeeper/aidl/vts/Android.bp +++ b/security/secretkeeper/aidl/vts/Android.bp @@ -27,6 +27,7 @@ rust_library { "libciborium", "libcoset", "libdiced_open_dice", + "libhex", "liblog_rust", "libsecretkeeper_client", ], diff --git a/security/secretkeeper/aidl/vts/dice_sample.rs b/security/secretkeeper/aidl/vts/dice_sample.rs index 97b4789985..4ef396a0be 100644 --- a/security/secretkeeper/aidl/vts/dice_sample.rs +++ b/security/secretkeeper/aidl/vts/dice_sample.rs @@ -28,10 +28,11 @@ use core::ffi::CStr; use coset::{ iana, Algorithm, AsCborValue, CborSerializable, CoseKey, KeyOperation, KeyType, Label, }; +pub use diced_open_dice::CDI_SIZE; use diced_open_dice::{ derive_cdi_private_key_seed, keypair_from_seed, retry_bcc_format_config_descriptor, retry_bcc_main_flow, retry_dice_main_flow, Config, DiceArtifacts, DiceConfigValues, DiceError, - DiceMode, InputValues, OwnedDiceArtifacts, CDI_SIZE, HASH_SIZE, HIDDEN_SIZE, + DiceMode, InputValues, OwnedDiceArtifacts, HASH_SIZE, HIDDEN_SIZE, }; use log::error; use secretkeeper_client::dice::OwnedDiceArtifactsWithExplicitKey; @@ -110,12 +111,36 @@ fn ed25519_public_key_to_cbor_value(public_key: &[u8]) -> Value { /// The `security_version` is included in the Android certificate as well as each subcomponent /// of AVB certificate. pub fn make_explicit_owned_dice(security_version: u64) -> OwnedDiceArtifactsWithExplicitKey { - let dice = make_sample_bcc_and_cdis(security_version); + make_explicit_owned_dice_for_uds(security_version, UDS) +} + +/// Makes a DICE chain (BCC) from the sample input for the given UDS. +pub fn make_explicit_owned_dice_for_uds( + security_version: u64, + uds: &[u8; CDI_SIZE], +) -> OwnedDiceArtifactsWithExplicitKey { + let dice = make_sample_bcc_and_cdis(security_version, uds, Subcomponents::Minimal); OwnedDiceArtifactsWithExplicitKey::from_owned_artifacts(dice).unwrap() } -fn make_sample_bcc_and_cdis(security_version: u64) -> OwnedDiceArtifacts { - let private_key_seed = derive_cdi_private_key_seed(UDS).unwrap(); +/// Makes an XXL DICE chain. +pub fn make_large_explicit_owned_dice(security_version: u64) -> OwnedDiceArtifactsWithExplicitKey { + let dice = make_sample_bcc_and_cdis(security_version, UDS, Subcomponents::CompOs); + OwnedDiceArtifactsWithExplicitKey::from_owned_artifacts(dice).unwrap() +} + +/// Indicate which subcomponent DICE information to include. +enum Subcomponents { + Minimal, + CompOs, +} + +fn make_sample_bcc_and_cdis( + security_version: u64, + uds: &[u8; CDI_SIZE], + subcomponents: Subcomponents, +) -> OwnedDiceArtifacts { + let private_key_seed = derive_cdi_private_key_seed(uds).unwrap(); // Gets the root public key in DICE chain (BCC). let (public_key, _) = keypair_from_seed(private_key_seed.as_array()).unwrap(); @@ -136,18 +161,16 @@ fn make_sample_bcc_and_cdis(security_version: u64) -> OwnedDiceArtifacts { DiceMode::kDiceModeNormal, HIDDEN_ABL, ); - let (cdi_values, cert) = retry_dice_main_flow(UDS, UDS, &input_values).unwrap(); + let (cdi_values, cert) = retry_dice_main_flow(uds, uds, &input_values).unwrap(); let bcc_value = Value::Array(vec![ed25519_public_key_value, de::from_reader(&cert[..]).unwrap()]); let mut bcc: Vec = vec![]; ser::into_writer(&bcc_value, &mut bcc).unwrap(); // Appends AVB certificate to DICE chain. - let config_desc = cbor!({ - COMPONENT_NAME => "AVB", - COMPONENT_VERSION => 1, - COMPONENT_RESETTABLE => null, - SUBCOMPONENT_DESCRIPTORS => [ + let subcomponents = match subcomponents { + Subcomponents::CompOs => compos_subcomponent_descriptors(), + Subcomponents::Minimal => cbor!([ { SUBCOMPONENT_NAME => "sub_1", SUBCOMPONENT_SECURITY_VERSION => security_version, @@ -160,7 +183,14 @@ fn make_sample_bcc_and_cdis(security_version: u64) -> OwnedDiceArtifacts { SUBCOMPONENT_CODE_HASH => b"xoxo", SUBCOMPONENT_AUTHORITY_HASH => b"oxox", } - ] + ]) + .unwrap(), + }; + let config_desc = cbor!({ + COMPONENT_NAME => "AVB", + COMPONENT_VERSION => 1, + COMPONENT_RESETTABLE => null, + SUBCOMPONENT_DESCRIPTORS => subcomponents, }) .unwrap() .to_vec() @@ -206,3 +236,177 @@ fn make_sample_bcc_and_cdis(security_version: u64) -> OwnedDiceArtifacts { ) .unwrap() } + +fn compos_subcomponent_descriptors() -> Value { + // Subcomponent descriptors taken from a CompOS chain. + cbor!([ + { + SUBCOMPONENT_NAME => "apk:com.android.compos.payload", + SUBCOMPONENT_SECURITY_VERSION => 34, + SUBCOMPONENT_CODE_HASH => hex::decode("9f9a7ca6367a602ee8aeb83c783ae37d1028e4e7fe7492c53ca6b0ac3a5a4918").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("5216ccb62004c4534f35c780ad7c582f4ee528371e27d4151f0553325de9ccbe6b34ec4233f5f640703581053abfea303977272d17958704d89b7711292a4569").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apk:com.android.security.fsverity_metadata.system", + SUBCOMPONENT_SECURITY_VERSION => 34, + SUBCOMPONENT_CODE_HASH => hex::decode("c5f0a71179daa76d5897e391ea882a2f22911b5c2c81794ed6bcd2366dfc6474").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("5216ccb62004c4534f35c780ad7c582f4ee528371e27d4151f0553325de9ccbe6b34ec4233f5f640703581053abfea303977272d17958704d89b7711292a4569").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apk:com.android.security.fsverity_metadata.system_ext", + SUBCOMPONENT_SECURITY_VERSION => 34, + SUBCOMPONENT_CODE_HASH => hex::decode("d043740bc1b45ef8eecb093714321f458f1df17e4d76652a02f3b6c038da8305").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("5216ccb62004c4534f35c780ad7c582f4ee528371e27d4151f0553325de9ccbe6b34ec4233f5f640703581053abfea303977272d17958704d89b7711292a4569").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.adbd", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("fa4d9b37ff0b534c02865357cce0e2fb5e39a00da00880b438de9a8dd13e79f7").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("4df2b359bfe246a1301166dfa9d9a74ae7c11eebe2b6edc360fcc7630974533c4ac28b216af7af3c8c88de2869d0f7b043872eaf75964e311c10bc1beb1cb89c").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.adservices", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("debbb6f029c92dcb23b8589b751e945855bdff2cb903fed1e8f9f3ee4740bc00").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("2f85397ad0e9c7e7afa3add6c18d18a1a2b9501d2dc51f481ae57fa789f381228ca905459e871b5bfcb300e5a101260ffb6bf58a920e6b7dfc17941ab7a565c4").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.appsearch", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("44dd279b861339cfcf92d55b7d4aa1cc21a856a8b0a0bf1bfe66574fdd681194").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("e326a8d1cf4a3b18b45c530e153bd310b9bff04949e37a8886b526dc546e2baf403c3384fef01c18341b3e5de0566c294c8373aa8f7b92e07dd9c938a96f7e35").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.art", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("e4a8eae20cee7fd98dd202b32321a5feaae73cf125b880763d810edbf6b394dd").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("ed255ae9ea98826f3f3a966849f0aaaf356d140c766a869048016e0ba10141af039fec5c53658ddebdad9c2339587c5ef5487bde89237ca79802238d91aebba8").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.btservices", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("d7aa86dfdf92e662d2210cd2b3ad4e4522c917e9e287268363aa90e20f9ae16c").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("a0d577d4a56cfad09aaa7abcd2355cd78872df85672f2faf9ac2fdf15c06147394e704c7473f28bed737803581a3d097275cc26d8095a4a896ee76167f9ee40e").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.compos", + SUBCOMPONENT_SECURITY_VERSION => 2, + SUBCOMPONENT_CODE_HASH => hex::decode("64c4b31c7de83ecb31632aff1fb6433741b5f870b1d9f258673787715b83e785").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("3e2691174d210a6479c586ef655ee5af1ee53ff960f6291d7b695237d56f73027c5cb30a6d6df07848a0c0b65b6d697e31ed98ba0711a0cb39002c4186b4ad95").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.configinfrastructure", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("69d589bcd38decdee64f5bdd359af461e95a5f9c9cf7e6c767db25f0ab81b5e7").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("13cde315955806bb1f9ec00714166255148e6baa43f3473bcbe5082bc35d3525605470a6c7ac208337dd79d2250e4adcd4f89f09036f2cbbb553f387c622be07").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.conscrypt", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("a91183cc1c12e2d0c9f2b0cd9c97c4592246035c2b07f080d9921fa57ed42900").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("4d76d909dd77ee0f8299880b27215a327dda261fb4504125d730fc4f78b105b0947c4103b4bcf49ea9a44d6d04e3c4d385d9ca02a2ef43b8850fca0d91b11e57").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.devicelock", + SUBCOMPONENT_SECURITY_VERSION => 1, + SUBCOMPONENT_CODE_HASH => hex::decode("85f7bdd116f9c2069f5bfb0039ec1ea165ccaaa517f340440b8eb8f58d044fa8").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("2949543df13e57c5dfa49aa3ade0c450514432a7e2710bbb1fd4b768e158bbadf17be6f1446be7d321960e13f2f10f648d2ee551ec41475169e629ed71f2cc5f").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.healthfitness", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("ad38a1e8186cb62ac75e47592496582ef7ab26b3f0dd405340cee2fe8d73dc47").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("2273e8a7113a103d2b7461c9ae8149ba4cfabe5edeb48b1703c4b4f2fab1a4e9c5a66bf75a9f2063f27df6390d310f1091e9511ad2e41baae822fde1fb022f4f").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.i18n", + SUBCOMPONENT_SECURITY_VERSION => 1, + SUBCOMPONENT_CODE_HASH => hex::decode("2107e7972afeb70f6653643aebf5e0198c5bf13d71b4c792960f78344bf7e439").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("668ac67e4b8a00bf5863ee175db92aefa64138eccbc86a7f528d6fdabec3443e781f4f4c5c3db123994d45696e13e07aa207da25bc70709dcaba3a740b679f7b").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.ipsec", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("dfc3ff28eaf429535b651bdb675fbc6d6a7e2834919c02ce56bc20f736562c2c").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("8ae0b721d55d3d3f80a1bce694dd85fbbbbba990b0479864c694a47912d4f42a60ca328f76b462a6624b89d1d8b1212fe06fc7749e2c2b0cccd9d86f1058dee2").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.media", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("cb1288d098962dbe0d069e78512138e6031d4f1bb4052fea30866f0d8226c541").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("7a374d48802077d032daa41fb60123e470808d4bae5d7fd87e6f6e6039fee67cf9cb37b960edb5014247ffc57f4673a0d6a52a07e477c9c7d570594ce0a867af").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.mediaprovider", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("bf343bfbe145a81974f05244b523b47d5ecc606c534a65723bb5b7a5f40ab4e1").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("272c2cbde4cdd914978246bf6150e30db54f603ee5602a1a48e0b31aa9569a533ff9eedab10bcb852c988d1d46f09de28fc2f0596b070adc38fed9edc12270d8").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.nfcservices", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("ff0caa7f86efd179fda394b387e2ef875272d7035138ca1309229fe80dc3dd3a").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("26af902c55fa92240fa15f060849e29803775249b5d53a02f7c4a57b039c0be6570809c2d81d63d6d6a923bc58ace14b05d64dcf0f9fdce0f99e6ef18ea292b4").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.ondevicepersonalization", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("9a339ac3a29bf2852dde9318575799c23c144515cca129eed5055a589d8da33d").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("96c20dbd0a57864a6aa055ebc5611da744c969d37838e7c75712c3f6f37bdbf9eda0dfc240d8f545f9b6fb500edd6d8ca5f48a70acde9a7121e545187df8705d").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.os.statsd", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("523e068e66be46eb3789d82aecfba7f58287a9cbc4bcf3c45fd32291db3da048").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("431db3773485c432e706fc8040373a373f0dac5a96ba0150ac813d80c00f351496dfe789c6c88dd673aaf642a64c0e09754fb0bb2c12bb12b62968427f9d3f87").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.permission", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("2f3de015ab80900579db7935d425ee228ea597ac07ef47b8e7e6366a91d93be9").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("0bcf05c42dcff0d2f5dc151369681179b0489749b27c5d2dff9ce69c990e7f299fd9782be1d46698101758f39bf18804e1043e3bd8e3da6c3554a6cccc34a891").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.rkpd", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("acb4c10a0f01065b787cf8349e7f371d91dda352d51a25e08fca229375de2ef1").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("56854df8c24c9670413396120c89bf18d5f6e2d5ade48b14a102be3bb29751fad1da3b754588da27f33ec5187258a8ec806a323ecf3e99cf8f051499e8cc8b5b").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.scheduling", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("b802e45078bbff1648ef97c38743005983d25ba47261b9e9fb7c758defec920e").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("d8e3c0f8501b639074c003fd1a45424756a91a79f326e2b50a66f39c9ced5bc0cd0811f6055b5f2c8330a845f95bd26d6f6d3962e3436f65fdfda3343f26cb69").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.sdkext", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("fb2a3d5437766135838d7ce078870a403ae6929937d58ec8b40182057587af21").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("6bdc69078b58bc524648ce606c8050ffd6a88a8e169c23cbce7a6cfc444cde58a2a9a77968e3f1454a0eaeb0ad00bb846e5447473b0730bbd28e0b71189af808").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.tethering", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("d352cfd92179ec854ae30c9ce54562b1a31f01738524ba11ceae10db6207c995").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("1af6fe33f7035ea7a4353a02ed40fd7b72f2668b58794d2bbccce8b61aa9878eb817cdcc813e1eab1a2f287c2f15e8b2bb620cf024e55210a659f27c3064bd7f").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.uwb", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("bfc970bc51670ade054b5fcafa6ed9fb90f0aa14168ea5a97d20d5b236ffac00").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("993f35bbdbad1db72f17382058b10020bb1c932cef8f540c240cb26e867ea03bab4ade22f41823a8be3ea5e82306f47368e294e153328ba38ad35b3aafabdf84").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.virt", + SUBCOMPONENT_SECURITY_VERSION => 2, + SUBCOMPONENT_CODE_HASH => hex::decode("efff05a5354236dc3efca323bf25d0488f7c8212a393349f9a7d329f7db88e73").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("a279d6d530ae0cea2b2f2c1d3dee1e5b59dbdac861e137995eaf44b1a57c5cfb02b7892f00e7fe647756fd2cfef66e74350b517c4d79463c6e6a6f96eb01693b").unwrap(), + }, + { + SUBCOMPONENT_NAME => "apex:com.android.wifi", + SUBCOMPONENT_SECURITY_VERSION => 990090000, + SUBCOMPONENT_CODE_HASH => hex::decode("2d6db7bcfb436ff9a8f22788e4666071d18e03063422d5b58e378530d304e0af").unwrap(), + SUBCOMPONENT_AUTHORITY_HASH => hex::decode("29b3ef73b51aff982b3136c944add0ee40a12eba762ca69ae9646c4f08fd8145e593c8b1fe4208e52f87e0735134c573612ec0566ebbf5ab08b2054a5954b599").unwrap(), + }, + ]).unwrap() +} diff --git a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs index 7c00aa93bb..595dc7a878 100644 --- a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs +++ b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs @@ -36,7 +36,7 @@ use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType}; use secretkeeper_test::{ AUTHORITY_HASH, MODE, CONFIG_DESC, SECURITY_VERSION, SUBCOMPONENT_AUTHORITY_HASH, SUBCOMPONENT_DESCRIPTORS, SUBCOMPONENT_SECURITY_VERSION, - dice_sample::make_explicit_owned_dice + dice_sample::{make_explicit_owned_dice_for_uds, make_explicit_owned_dice, make_large_explicit_owned_dice, CDI_SIZE} }; use std::fs; use std::path::Path; @@ -289,9 +289,22 @@ impl From for Error { } } -// Assert that the error is EntryNotFound +// Assert that the error is `EntryNotFound`. fn assert_entry_not_found(res: Result) { - assert!(matches!(res.unwrap_err(), Error::SecretkeeperError(SecretkeeperError::EntryNotFound))) + assert_result_matches(res, SecretkeeperError::EntryNotFound) +} + +// Assert that the error is `DicePolicyError`. +fn assert_dice_policy_error(res: Result) { + assert_result_matches(res, SecretkeeperError::DicePolicyError) +} + +fn assert_result_matches(res: Result, want: SecretkeeperError) { + match res { + Err(Error::SecretkeeperError(e)) if e == want => {} + Err(got) => panic!("unexpected error {got:?}, expected {want:?}"), + Ok(_) => panic!("unexpected success instead of {want:?}"), + } } /// Construct a sealing policy on the dice chain. This method uses the following set of @@ -445,6 +458,42 @@ fn secret_management_store_get_secret_not_found(instance: String) { assert_entry_not_found(sk_client.get(&ID_NOT_STORED)); } +/// A secret stored in one session should be accessible from a different session +/// as long as the client has the same identity. +#[rdroidtest(get_instances())] +fn secretkeeper_get_secret_across_sessions_with_same_identity(instance: String) { + // Store a secret with one session. Note that we need to hang on to the + // test client because it auto-deletes entries on drop. + let mut sk_client1 = SkClient::new(&instance).unwrap(); + sk_client1.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap(); + assert_eq!(sk_client1.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE); + + // Retrieve the secret using a different session (that has the same identity). + let mut sk_client2 = SkClient::new(&instance).unwrap(); + assert_eq!(sk_client2.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE); +} + +/// A secret stored in one session should not be accessible from a different session +/// if the client has a different identity. +#[rdroidtest(get_instances())] +fn secretkeeper_no_secret_across_sessions_with_different_identity(instance: String) { + // Store a secret with one session. Note that we need to hang on to the + // test client because it auto-deletes entries on drop. + let mut sk_client1 = SkClient::new(&instance).unwrap(); + sk_client1.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap(); + assert_eq!(sk_client1.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE); + + // Fail to retrieve the secret using a different session that has a different identity. + pub const ALT_UDS: &[u8; CDI_SIZE] = &[ + 0x66, 0x4f, 0xab, 0xa9, 0xa5, 0xad, 0x0f, 0x5e, 0x15, 0xc3, 0x12, 0xf7, 0x77, 0x45, 0xfa, + 0x56, 0x18, 0x6a, 0xa6, 0x34, 0xb6, 0x7c, 0x82, 0x7b, 0x89, 0x4c, 0xc5, 0x52, 0xd3, 0x27, + 0x36, 0x8e, + ]; + let alt_identity = make_explicit_owned_dice_for_uds(5, ALT_UDS); + let mut sk_client2 = SkClient::with_identity(&instance, alt_identity).unwrap(); + assert_dice_policy_error(sk_client2.get(&ID_EXAMPLE)); +} + #[rdroidtest(get_instances())] fn secretkeeper_store_delete_ids(instance: String) { let mut sk_client = SkClient::new(&instance).unwrap(); @@ -522,6 +571,69 @@ fn secretkeeper_store_delete_all(instance: String) { assert_entry_not_found(sk_client.get(&ID_NOT_STORED)); } +// This tests creates lots of sessions one after another, to confirm that the Secretkeeper +// instance doesn't have unbounded internal state. (Instead, it should drop older sessions +// and the clients using those sessions would need to re-establish a new session.) +#[rdroidtest(get_instances())] +fn secretkeeper_many_sessions_serial(instance: String) { + const SESSION_COUNT: usize = 32; + let mut sk_clients = Vec::new(); + for idx in 0..SESSION_COUNT { + let identity = make_large_explicit_owned_dice(5); + let mut sk_client = SkClient::with_identity(&instance, identity) + .expect(&format!("failed to establish session {idx}")); + sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap(); + sk_clients.push(sk_client); + } +} + +// This tests creates lots of sessions in parallel. Some of these session are expected +// to fail, but the Secretkeeper TA should survive the experience. +#[rdroidtest(get_instances())] +fn secretkeeper_many_sessions_parallel(instance: String) { + const SESSION_COUNT: usize = 32; + + let mut handles = Vec::>::new(); + for idx in 0..SESSION_COUNT { + let instance = instance.clone(); + handles.push(std::thread::spawn(move || { + // In each thread, create a session and use it. This may (legitimately) fail at any + // moment. + let _result = use_sk_may_fail(instance, idx); + })); + } + + // Wait for all activity to quiesce. + for handle in handles { + let _result = handle.join(); + } + + // Now that all the parallel activity is done, should still be able to interact with + // Secretkeeper. + let mut sk_client = SkClient::new(&instance).unwrap(); + sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap(); + assert_eq!(sk_client.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE); + + // Remove any IDs that might have been stored in the test. + for idx in 0..SESSION_COUNT { + let mut id = ID_EXAMPLE.clone(); + id.0[0] = idx as u8; + sk_client.delete(&[&id]); + } +} + +fn use_sk_may_fail(instance: String, idx: usize) -> Result<(), Error> { + let identity = make_large_explicit_owned_dice(5); + let mut sk_client = SkClient::with_identity(&instance, identity)?; + let mut id = ID_EXAMPLE.clone(); + id.0[0] = idx as u8; + + sk_client.store(&id, &SECRET_EXAMPLE)?; + let result = sk_client.get(&id)?; + assert_eq!(result, SECRET_EXAMPLE); + Ok(()) +} + // This test checks that Secretkeeper uses the expected [`RequestSeqNum`] as aad while // decrypting requests and the responses are encrypted with correct [`ResponseSeqNum`] for the // first few messages. @@ -634,10 +746,7 @@ fn secret_management_policy_gate(instance: String) { let dice_chain_downgraded = make_explicit_owned_dice(/*Security version in a node */ 99); let mut sk_client_downgraded = SkClient::with_identity(&instance, dice_chain_downgraded).unwrap(); - assert!(matches!( - sk_client_downgraded.get(&ID_EXAMPLE).unwrap_err(), - Error::SecretkeeperError(SecretkeeperError::DicePolicyError) - )); + assert_dice_policy_error(sk_client_downgraded.get(&ID_EXAMPLE)); // Now get the secret with the later version, and upgrade the sealing policy along the way. let sealing_policy = @@ -648,10 +757,7 @@ fn secret_management_policy_gate(instance: String) { ); // The original version of the client should no longer be able to retrieve the secret. - assert!(matches!( - sk_client_original.get(&ID_EXAMPLE).unwrap_err(), - Error::SecretkeeperError(SecretkeeperError::DicePolicyError) - )); + assert_dice_policy_error(sk_client_original.get(&ID_EXAMPLE)); } // This test checks that the identity of Secretkeeper (in context of AuthGraph key exchange) is