Merge "Secretkeeper: improve VTS tests" into main

This commit is contained in:
Shikha Panwar 2023-12-15 12:10:42 +00:00 committed by Gerrit Code Review
commit 6ba95073eb
3 changed files with 219 additions and 288 deletions

View file

@ -25,6 +25,7 @@ rust_test {
"general-tests", "general-tests",
"vts", "vts",
], ],
test_config: "AndroidTest.xml",
rustlibs: [ rustlibs: [
"libsecretkeeper_comm_nostd", "libsecretkeeper_comm_nostd",
"libsecretkeeper_core_nostd", "libsecretkeeper_core_nostd",
@ -36,6 +37,7 @@ rust_test {
"libbinder_rs", "libbinder_rs",
"libcoset", "libcoset",
"liblog_rust", "liblog_rust",
"liblogger",
], ],
require_root: true, require_root: true,
} }

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration description="Config for Secretkeeper VTS tests.">
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="push-file" key="VtsSecretkeeperTargetTest" value="/data/local/tmp/VtsSecretkeeperTargetTest" />
</target_preparer>
<test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
<option name="test-device-path" value="/data/local/tmp" />
<option name="module-name" value="VtsSecretkeeperTargetTest" />
<!-- Rust tests are run in parallel by default. Run these ones
single-threaded, so that one test's secrets don't affect
the behaviour of a different test. -->
<option name="native-test-flag" value="--test-threads=1" />
</test>
</configuration>

View file

@ -14,27 +14,28 @@
* limitations under the License. * limitations under the License.
*/ */
#[cfg(test)] #![cfg(test)]
use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::SecretId::SecretId;
use authgraph_vts_test as ag_vts;
use authgraph_boringssl as boring;
use authgraph_core::key;
use binder::StatusCode; use binder::StatusCode;
use coset::{CborSerializable, CoseEncrypt0}; use coset::{CborSerializable, CoseEncrypt0};
use log::warn; use log::{info, warn};
use secretkeeper_core::cipher; use secretkeeper_core::cipher;
use secretkeeper_comm::data_types::error::SecretkeeperError; use secretkeeper_comm::data_types::error::SecretkeeperError;
use secretkeeper_comm::data_types::request::Request; use secretkeeper_comm::data_types::request::Request;
use secretkeeper_comm::data_types::request_response_impl::{ use secretkeeper_comm::data_types::request_response_impl::{
GetVersionRequest, GetVersionResponse, GetSecretRequest, GetSecretResponse, StoreSecretRequest, GetVersionRequest, GetVersionResponse, GetSecretRequest, GetSecretResponse, StoreSecretRequest,
StoreSecretResponse }; StoreSecretResponse };
use secretkeeper_comm::data_types::{Id, ID_SIZE, Secret, SECRET_SIZE}; use secretkeeper_comm::data_types::{Id, Secret};
use secretkeeper_comm::data_types::response::Response; use secretkeeper_comm::data_types::response::Response;
use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType}; use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType};
use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::SecretId::SecretId;
use authgraph_vts_test as ag_vts;
use authgraph_boringssl as boring;
use authgraph_core::key;
const SECRETKEEPER_IDENTIFIER: &str = const SECRETKEEPER_SERVICE: &str = "android.hardware.security.secretkeeper.ISecretkeeper";
"android.hardware.security.secretkeeper.ISecretkeeper/nonsecure"; const SECRETKEEPER_INSTANCES: [&'static str; 2] = ["nonsecure", "default"];
const CURRENT_VERSION: u64 = 1; const CURRENT_VERSION: u64 = 1;
// TODO(b/291238565): This will change once libdice_policy switches to Explicit-key DiceCertChain // TODO(b/291238565): This will change once libdice_policy switches to Explicit-key DiceCertChain
@ -47,38 +48,62 @@ const HYPOTHETICAL_DICE_POLICY: [u8; 43] = [
]; ];
// Random bytes (of ID_SIZE/SECRET_SIZE) generated for tests. // Random bytes (of ID_SIZE/SECRET_SIZE) generated for tests.
const ID_EXAMPLE: [u8; ID_SIZE] = [ const ID_EXAMPLE: Id = Id([
0xF1, 0xB2, 0xED, 0x3B, 0xD1, 0xBD, 0xF0, 0x7D, 0xE1, 0xF0, 0x01, 0xFC, 0x61, 0x71, 0xD3, 0x42, 0xF1, 0xB2, 0xED, 0x3B, 0xD1, 0xBD, 0xF0, 0x7D, 0xE1, 0xF0, 0x01, 0xFC, 0x61, 0x71, 0xD3, 0x42,
0xE5, 0x8A, 0xAF, 0x33, 0x6C, 0x11, 0xDC, 0xC8, 0x6F, 0xAE, 0x12, 0x5C, 0x26, 0x44, 0x6B, 0x86, 0xE5, 0x8A, 0xAF, 0x33, 0x6C, 0x11, 0xDC, 0xC8, 0x6F, 0xAE, 0x12, 0x5C, 0x26, 0x44, 0x6B, 0x86,
0xCC, 0x24, 0xFD, 0xBF, 0x91, 0x4A, 0x54, 0x84, 0xF9, 0x01, 0x59, 0x25, 0x70, 0x89, 0x38, 0x8D, 0xCC, 0x24, 0xFD, 0xBF, 0x91, 0x4A, 0x54, 0x84, 0xF9, 0x01, 0x59, 0x25, 0x70, 0x89, 0x38, 0x8D,
0x5E, 0xE6, 0x91, 0xDF, 0x68, 0x60, 0x69, 0x26, 0xBE, 0xFE, 0x79, 0x58, 0xF7, 0xEA, 0x81, 0x7D, 0x5E, 0xE6, 0x91, 0xDF, 0x68, 0x60, 0x69, 0x26, 0xBE, 0xFE, 0x79, 0x58, 0xF7, 0xEA, 0x81, 0x7D,
]; ]);
const ID_EXAMPLE_2: [u8; ID_SIZE] = [ const ID_EXAMPLE_2: Id = Id([
0x6A, 0xCC, 0xB1, 0xEB, 0xBB, 0xAB, 0xE3, 0xEA, 0x44, 0xBD, 0xDC, 0x75, 0x75, 0x7D, 0xC0, 0xE5, 0x6A, 0xCC, 0xB1, 0xEB, 0xBB, 0xAB, 0xE3, 0xEA, 0x44, 0xBD, 0xDC, 0x75, 0x75, 0x7D, 0xC0, 0xE5,
0xC7, 0x86, 0x41, 0x56, 0x39, 0x66, 0x96, 0x10, 0xCB, 0x43, 0x10, 0x79, 0x03, 0xDC, 0xE6, 0x9F, 0xC7, 0x86, 0x41, 0x56, 0x39, 0x66, 0x96, 0x10, 0xCB, 0x43, 0x10, 0x79, 0x03, 0xDC, 0xE6, 0x9F,
0x12, 0x2B, 0xEF, 0x28, 0x9C, 0x1E, 0x32, 0x46, 0x5F, 0xA3, 0xE7, 0x8D, 0x53, 0x63, 0xE8, 0x30, 0x12, 0x2B, 0xEF, 0x28, 0x9C, 0x1E, 0x32, 0x46, 0x5F, 0xA3, 0xE7, 0x8D, 0x53, 0x63, 0xE8, 0x30,
0x5A, 0x17, 0x6F, 0xEF, 0x42, 0xD6, 0x58, 0x7A, 0xF0, 0xCB, 0xD4, 0x40, 0x58, 0x96, 0x32, 0xF4, 0x5A, 0x17, 0x6F, 0xEF, 0x42, 0xD6, 0x58, 0x7A, 0xF0, 0xCB, 0xD4, 0x40, 0x58, 0x96, 0x32, 0xF4,
]; ]);
const ID_NOT_STORED: [u8; ID_SIZE] = [ const ID_NOT_STORED: Id = Id([
0x56, 0xD0, 0x4E, 0xAA, 0xC1, 0x7B, 0x55, 0x6B, 0xA0, 0x2C, 0x65, 0x43, 0x39, 0x0A, 0x6C, 0xE9, 0x56, 0xD0, 0x4E, 0xAA, 0xC1, 0x7B, 0x55, 0x6B, 0xA0, 0x2C, 0x65, 0x43, 0x39, 0x0A, 0x6C, 0xE9,
0x1F, 0xD0, 0x0E, 0x20, 0x3E, 0xFB, 0xF5, 0xF9, 0x3F, 0x5B, 0x11, 0x1B, 0x18, 0x73, 0xF6, 0xBB, 0x1F, 0xD0, 0x0E, 0x20, 0x3E, 0xFB, 0xF5, 0xF9, 0x3F, 0x5B, 0x11, 0x1B, 0x18, 0x73, 0xF6, 0xBB,
0xAB, 0x9F, 0xF2, 0xD6, 0xBD, 0xBA, 0x25, 0x68, 0x22, 0x30, 0xF2, 0x1F, 0x90, 0x05, 0xF3, 0x64, 0xAB, 0x9F, 0xF2, 0xD6, 0xBD, 0xBA, 0x25, 0x68, 0x22, 0x30, 0xF2, 0x1F, 0x90, 0x05, 0xF3, 0x64,
0xE7, 0xEF, 0xC6, 0xB6, 0xA0, 0x85, 0xC9, 0x40, 0x40, 0xF0, 0xB4, 0xB9, 0xD8, 0x28, 0xEE, 0x9C, 0xE7, 0xEF, 0xC6, 0xB6, 0xA0, 0x85, 0xC9, 0x40, 0x40, 0xF0, 0xB4, 0xB9, 0xD8, 0x28, 0xEE, 0x9C,
]; ]);
const SECRET_EXAMPLE: [u8; SECRET_SIZE] = [ const SECRET_EXAMPLE: Secret = Secret([
0xA9, 0x89, 0x97, 0xFE, 0xAE, 0x97, 0x55, 0x4B, 0x32, 0x35, 0xF0, 0xE8, 0x93, 0xDA, 0xEA, 0x24, 0xA9, 0x89, 0x97, 0xFE, 0xAE, 0x97, 0x55, 0x4B, 0x32, 0x35, 0xF0, 0xE8, 0x93, 0xDA, 0xEA, 0x24,
0x06, 0xAC, 0x36, 0x8B, 0x3C, 0x95, 0x50, 0x16, 0x67, 0x71, 0x65, 0x26, 0xEB, 0xD0, 0xC3, 0x98, 0x06, 0xAC, 0x36, 0x8B, 0x3C, 0x95, 0x50, 0x16, 0x67, 0x71, 0x65, 0x26, 0xEB, 0xD0, 0xC3, 0x98,
]; ]);
fn get_connection() -> Option<binder::Strong<dyn ISecretkeeper>> { fn get_connection() -> Option<(binder::Strong<dyn ISecretkeeper>, String)> {
match binder::get_interface(SECRETKEEPER_IDENTIFIER) { // Initialize logging (which is OK to call multiple times).
Ok(sk) => Some(sk), logger::init(logger::Config::default().with_min_level(log::Level::Debug));
Err(StatusCode::NAME_NOT_FOUND) => None,
// TODO: replace this with a parameterized set of tests that run for each available instance of
// ISecretkeeper (rather than having a fixed set of instance names to look for).
for instance in &SECRETKEEPER_INSTANCES {
let name = format!("{SECRETKEEPER_SERVICE}/{instance}");
match binder::get_interface(&name) {
Ok(sk) => {
info!("Running test against /{instance}");
return Some((sk, name));
}
Err(StatusCode::NAME_NOT_FOUND) => {
info!("No /{instance} instance of ISecretkeeper present");
}
Err(e) => { Err(e) => {
panic!( panic!("unexpected error while fetching connection to Secretkeeper {:?}", e);
"unexpected error while fetching connection to Secretkeeper {:?}", }
e }
); }
None
}
/// Macro to perform test setup. Invokes `return` if no Secretkeeper instance available.
macro_rules! setup_client {
{} => {
match SkClient::new() {
Some(sk) => sk,
None => {
warn!("Secretkeeper HAL is unavailable, skipping test");
return;
}
} }
} }
} }
@ -86,42 +111,86 @@ fn get_connection() -> Option<binder::Strong<dyn ISecretkeeper>> {
/// Secretkeeper client information. /// Secretkeeper client information.
struct SkClient { struct SkClient {
sk: binder::Strong<dyn ISecretkeeper>, sk: binder::Strong<dyn ISecretkeeper>,
name: String,
aes_keys: [key::AesKey; 2], aes_keys: [key::AesKey; 2],
session_id: Vec<u8>, session_id: Vec<u8>,
} }
impl Drop for SkClient {
fn drop(&mut self) {
// Delete any IDs that may be left over.
self.delete(&[&ID_EXAMPLE, &ID_EXAMPLE_2]);
}
}
impl SkClient { impl SkClient {
fn new() -> Option<Self> { fn new() -> Option<Self> {
let sk = get_connection()?; let (sk, name) = get_connection()?;
let (aes_keys, session_id) = authgraph_key_exchange(sk.clone()); let (aes_keys, session_id) = authgraph_key_exchange(sk.clone());
Some(Self { Some(Self { sk, name, aes_keys, session_id })
sk,
aes_keys,
session_id,
})
} }
/// Wrapper around `ISecretkeeper::processSecretManagementRequest` that handles /// Wrapper around `ISecretkeeper::processSecretManagementRequest` that handles
/// encryption and decryption. /// encryption and decryption.
fn secret_management_request(&self, req_data: &[u8]) -> Vec<u8> { fn secret_management_request(&self, req_data: &[u8]) -> Vec<u8> {
let aes_gcm = boring::BoringAes; let aes_gcm = boring::BoringAes;
let rng = boring::BoringRng; let rng = boring::BoringRng;
let request_bytes = cipher::encrypt_message( let request_bytes =
&aes_gcm, cipher::encrypt_message(&aes_gcm, &rng, &self.aes_keys[0], &self.session_id, &req_data)
&rng,
&self.aes_keys[0],
&self.session_id,
&req_data,
)
.unwrap(); .unwrap();
let response_bytes = self let response_bytes = self.sk.processSecretManagementRequest(&request_bytes).unwrap();
.sk
.processSecretManagementRequest(&request_bytes)
.unwrap();
let response_encrypt0 = CoseEncrypt0::from_slice(&response_bytes).unwrap(); let response_encrypt0 = CoseEncrypt0::from_slice(&response_bytes).unwrap();
cipher::decrypt_message(&aes_gcm, &self.aes_keys[1], &response_encrypt0).unwrap() cipher::decrypt_message(&aes_gcm, &self.aes_keys[1], &response_encrypt0).unwrap()
} }
/// Helper method to store a secret.
fn store(&self, id: &Id, secret: &Secret) {
let store_request = StoreSecretRequest {
id: id.clone(),
secret: secret.clone(),
sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
};
let store_request = store_request.serialize_to_packet().to_vec().unwrap();
let store_response = self.secret_management_request(&store_request);
let store_response = ResponsePacket::from_slice(&store_response).unwrap();
assert_eq!(store_response.response_type().unwrap(), ResponseType::Success);
// Really just checking that the response is indeed StoreSecretResponse
let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
}
/// Helper method to get a secret.
fn get(&self, id: &Id) -> Option<Secret> {
let get_request = GetSecretRequest { id: id.clone(), updated_sealing_policy: None };
let get_request = get_request.serialize_to_packet().to_vec().unwrap();
let get_response = self.secret_management_request(&get_request);
let get_response = ResponsePacket::from_slice(&get_response).unwrap();
if get_response.response_type().unwrap() == ResponseType::Success {
let get_response = *GetSecretResponse::deserialize_from_packet(get_response).unwrap();
Some(Secret(get_response.secret.0))
} else {
// Only expect a not-found failure.
let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
assert_eq!(err, SecretkeeperError::EntryNotFound);
None
}
}
/// Helper method to delete secrets.
fn delete(&self, ids: &[&Id]) {
let ids: Vec<SecretId> = ids.iter().map(|id| SecretId { id: id.0.to_vec() }).collect();
self.sk.deleteIds(&ids).unwrap();
}
/// Helper method to delete everything.
fn delete_all(&self) {
self.sk.deleteAll().unwrap();
}
} }
/// Perform AuthGraph key exchange, returning the session keys and session ID. /// Perform AuthGraph key exchange, returning the session keys and session ID.
@ -135,7 +204,7 @@ fn authgraph_key_exchange(sk: binder::Strong<dyn ISecretkeeper>) -> ([key::AesKe
/// mainline key exchange against a local source implementation. /// mainline key exchange against a local source implementation.
#[test] #[test]
fn authgraph_mainline() { fn authgraph_mainline() {
let sk = match get_connection() { let (sk, _) = match get_connection() {
Some(sk) => sk, Some(sk) => sk,
None => { None => {
warn!("Secretkeeper HAL is unavailable, skipping test"); warn!("Secretkeeper HAL is unavailable, skipping test");
@ -149,7 +218,7 @@ fn authgraph_mainline() {
/// a corrupted session ID signature. /// a corrupted session ID signature.
#[test] #[test]
fn authgraph_corrupt_sig() { fn authgraph_corrupt_sig() {
let sk = match get_connection() { let (sk, _) = match get_connection() {
Some(sk) => sk, Some(sk) => sk,
None => { None => {
warn!("Secretkeeper HAL is unavailable, skipping test"); warn!("Secretkeeper HAL is unavailable, skipping test");
@ -165,7 +234,7 @@ fn authgraph_corrupt_sig() {
/// when corrupted keys are returned to it. /// when corrupted keys are returned to it.
#[test] #[test]
fn authgraph_corrupt_keys() { fn authgraph_corrupt_keys() {
let sk = match get_connection() { let (sk, _) = match get_connection() {
Some(sk) => sk, Some(sk) => sk,
None => { None => {
warn!("Secretkeeper HAL is unavailable, skipping test"); warn!("Secretkeeper HAL is unavailable, skipping test");
@ -182,13 +251,7 @@ fn authgraph_corrupt_keys() {
#[test] #[test]
fn secret_management_get_version() { fn secret_management_get_version() {
let sk_client = match SkClient::new() { let sk_client = setup_client!();
Some(sk) => sk,
None => {
warn!("Secretkeeper HAL is unavailable, skipping test");
return;
}
};
let request = GetVersionRequest {}; let request = GetVersionRequest {};
let request_packet = request.serialize_to_packet(); let request_packet = request.serialize_to_packet();
@ -197,10 +260,7 @@ fn secret_management_get_version() {
let response_bytes = sk_client.secret_management_request(&request_bytes); let response_bytes = sk_client.secret_management_request(&request_bytes);
let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap(); let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
assert_eq!( assert_eq!(response_packet.response_type().unwrap(), ResponseType::Success);
response_packet.response_type().unwrap(),
ResponseType::Success
);
let get_version_response = let get_version_response =
*GetVersionResponse::deserialize_from_packet(response_packet).unwrap(); *GetVersionResponse::deserialize_from_packet(response_packet).unwrap();
assert_eq!(get_version_response.version, CURRENT_VERSION); assert_eq!(get_version_response.version, CURRENT_VERSION);
@ -208,13 +268,7 @@ fn secret_management_get_version() {
#[test] #[test]
fn secret_management_malformed_request() { fn secret_management_malformed_request() {
let sk_client = match SkClient::new() { let sk_client = setup_client!();
Some(sk) => sk,
None => {
warn!("Secretkeeper HAL is unavailable, skipping test");
return;
}
};
let request = GetVersionRequest {}; let request = GetVersionRequest {};
let request_packet = request.serialize_to_packet(); let request_packet = request.serialize_to_packet();
@ -226,268 +280,112 @@ fn secret_management_malformed_request() {
let response_bytes = sk_client.secret_management_request(&request_bytes); let response_bytes = sk_client.secret_management_request(&request_bytes);
let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap(); let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
assert_eq!( assert_eq!(response_packet.response_type().unwrap(), ResponseType::Error);
response_packet.response_type().unwrap(),
ResponseType::Error
);
let err = *SecretkeeperError::deserialize_from_packet(response_packet).unwrap(); let err = *SecretkeeperError::deserialize_from_packet(response_packet).unwrap();
assert_eq!(err, SecretkeeperError::RequestMalformed); assert_eq!(err, SecretkeeperError::RequestMalformed);
} }
#[test] #[test]
fn secret_management_store_get_secret_found() { fn secret_management_store_get_secret_found() {
let sk_client = match SkClient::new() { let sk_client = setup_client!();
Some(sk) => sk,
None => {
warn!("Secretkeeper HAL is unavailable, skipping test");
return;
}
};
let store_request = StoreSecretRequest { sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
id: Id(ID_EXAMPLE),
secret: Secret(SECRET_EXAMPLE),
sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
};
let store_request = store_request.serialize_to_packet().to_vec().unwrap();
let store_response = sk_client.secret_management_request(&store_request);
let store_response = ResponsePacket::from_slice(&store_response).unwrap();
assert_eq!(
store_response.response_type().unwrap(),
ResponseType::Success
);
// Really just checking that the response is indeed StoreSecretResponse
let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
// Get the secret that was just stored // Get the secret that was just stored
let get_request = GetSecretRequest { assert_eq!(sk_client.get(&ID_EXAMPLE), Some(SECRET_EXAMPLE));
id: Id(ID_EXAMPLE),
updated_sealing_policy: None,
};
let get_request = get_request.serialize_to_packet().to_vec().unwrap();
let get_response = sk_client.secret_management_request(&get_request);
let get_response = ResponsePacket::from_slice(&get_response).unwrap();
assert_eq!(get_response.response_type().unwrap(), ResponseType::Success);
let get_response = *GetSecretResponse::deserialize_from_packet(get_response).unwrap();
assert_eq!(get_response.secret.0, SECRET_EXAMPLE);
} }
#[test] #[test]
fn secret_management_store_get_secret_not_found() { fn secret_management_store_get_secret_not_found() {
let sk_client = match SkClient::new() { let sk_client = setup_client!();
Some(sk) => sk,
None => {
warn!("Secretkeeper HAL is unavailable, skipping test");
return;
}
};
// Store a secret (corresponding to an id). // Store a secret (corresponding to an id).
let store_request = StoreSecretRequest { sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
id: Id(ID_EXAMPLE),
secret: Secret(SECRET_EXAMPLE),
sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
};
let store_request = store_request.serialize_to_packet().to_vec().unwrap();
let store_response = sk_client.secret_management_request(&store_request);
let store_response = ResponsePacket::from_slice(&store_response).unwrap();
assert_eq!(
store_response.response_type().unwrap(),
ResponseType::Success
);
// Really just checking that the response is indeed StoreSecretResponse
let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
// Get the secret that was never stored // Get the secret that was never stored
let get_request = GetSecretRequest { assert_eq!(sk_client.get(&ID_NOT_STORED), None);
id: Id(ID_NOT_STORED),
updated_sealing_policy: None,
};
let get_request = get_request.serialize_to_packet().to_vec().unwrap();
let get_response = sk_client.secret_management_request(&get_request);
// Expect the entry not to be found.
let get_response = ResponsePacket::from_slice(&get_response).unwrap();
assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
assert_eq!(err, SecretkeeperError::EntryNotFound);
} }
#[test] #[test]
fn secretkeeper_store_delete_ids() { fn secretkeeper_store_delete_ids() {
let sk_client = match SkClient::new() { let sk_client = setup_client!();
Some(sk) => sk,
None => {
warn!("Secretkeeper HAL is unavailable, skipping test");
return;
}
};
let store_request = StoreSecretRequest { sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
id: Id(ID_EXAMPLE), sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
secret: Secret(SECRET_EXAMPLE), sk_client.delete(&[&ID_EXAMPLE]);
sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
};
let store_request = store_request.serialize_to_packet().to_vec().unwrap(); assert_eq!(sk_client.get(&ID_EXAMPLE), None);
let store_response = sk_client.secret_management_request(&store_request); assert_eq!(sk_client.get(&ID_EXAMPLE_2), Some(SECRET_EXAMPLE));
let store_response = ResponsePacket::from_slice(&store_response).unwrap();
assert_eq!( sk_client.delete(&[&ID_EXAMPLE_2]);
store_response.response_type().unwrap(),
ResponseType::Success
);
// Really just checking that the response is indeed StoreSecretResponse
let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
sk_client assert_eq!(sk_client.get(&ID_EXAMPLE), None);
.sk assert_eq!(sk_client.get(&ID_EXAMPLE_2), None);
.deleteIds(&[SecretId { }
id: ID_EXAMPLE.to_vec(),
}])
.unwrap();
// Try to get the secret that was just stored & deleted #[test]
let get_request = GetSecretRequest { fn secretkeeper_store_delete_multiple_ids() {
id: Id(ID_EXAMPLE), let sk_client = setup_client!();
updated_sealing_policy: None,
};
let get_request = get_request.serialize_to_packet().to_vec().unwrap();
let get_response = sk_client.secret_management_request(&get_request); sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
sk_client.delete(&[&ID_EXAMPLE, &ID_EXAMPLE_2]);
// Expect the entry not to be found. assert_eq!(sk_client.get(&ID_EXAMPLE), None);
let get_response = ResponsePacket::from_slice(&get_response).unwrap(); assert_eq!(sk_client.get(&ID_EXAMPLE_2), None);
assert_eq!(get_response.response_type().unwrap(), ResponseType::Error); }
let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
assert_eq!(err, SecretkeeperError::EntryNotFound); #[test]
fn secretkeeper_store_delete_duplicate_ids() {
let sk_client = setup_client!();
sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
// Delete the same secret twice.
sk_client.delete(&[&ID_EXAMPLE, &ID_EXAMPLE]);
assert_eq!(sk_client.get(&ID_EXAMPLE), None);
assert_eq!(sk_client.get(&ID_EXAMPLE_2), Some(SECRET_EXAMPLE));
}
#[test]
fn secretkeeper_store_delete_nonexistent() {
let sk_client = setup_client!();
sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
sk_client.delete(&[&ID_NOT_STORED]);
assert_eq!(sk_client.get(&ID_EXAMPLE), Some(SECRET_EXAMPLE));
assert_eq!(sk_client.get(&ID_EXAMPLE_2), Some(SECRET_EXAMPLE));
assert_eq!(sk_client.get(&ID_NOT_STORED), None);
} }
#[test] #[test]
fn secretkeeper_store_delete_all() { fn secretkeeper_store_delete_all() {
let sk_client = match SkClient::new() { let sk_client = setup_client!();
Some(sk) => sk,
None => { if sk_client.name != "nonsecure" {
warn!("Secretkeeper HAL is unavailable, skipping test"); // Don't run deleteAll() on a secure device, as it might affect
// real secrets.
warn!("skipping deleteAll test due to real impl");
return; return;
} }
};
let store_request = StoreSecretRequest { sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
id: Id(ID_EXAMPLE), sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
secret: Secret(SECRET_EXAMPLE),
sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
};
let store_request = store_request.serialize_to_packet().to_vec().unwrap(); sk_client.delete_all();
let store_response = sk_client.secret_management_request(&store_request);
let store_response = ResponsePacket::from_slice(&store_response).unwrap();
assert_eq!( assert_eq!(sk_client.get(&ID_EXAMPLE), None);
store_response.response_type().unwrap(), assert_eq!(sk_client.get(&ID_EXAMPLE_2), None);
ResponseType::Success
);
// Really just checking that the response is indeed StoreSecretResponse
let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
let store_request = StoreSecretRequest {
id: Id(ID_EXAMPLE_2),
secret: Secret(SECRET_EXAMPLE),
sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
};
let store_request = store_request.serialize_to_packet().to_vec().unwrap();
let store_response = sk_client.secret_management_request(&store_request);
let store_response = ResponsePacket::from_slice(&store_response).unwrap();
assert_eq!(
store_response.response_type().unwrap(),
ResponseType::Success
);
// Really just checking that the response is indeed StoreSecretResponse
let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
sk_client.sk.deleteAll().unwrap();
// Get the first secret that was just stored before deleteAll
let get_request = GetSecretRequest {
id: Id(ID_EXAMPLE),
updated_sealing_policy: None,
};
let get_request = get_request.serialize_to_packet().to_vec().unwrap();
let get_response = sk_client.secret_management_request(&get_request);
// Expect the entry not to be found.
let get_response = ResponsePacket::from_slice(&get_response).unwrap();
assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
assert_eq!(err, SecretkeeperError::EntryNotFound);
// Get the second secret that was just stored before deleteAll
let get_request = GetSecretRequest {
id: Id(ID_EXAMPLE_2),
updated_sealing_policy: None,
};
let get_request = get_request.serialize_to_packet().to_vec().unwrap();
let get_response = sk_client.secret_management_request(&get_request);
// Expect the entry not to be found.
let get_response = ResponsePacket::from_slice(&get_response).unwrap();
assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
assert_eq!(err, SecretkeeperError::EntryNotFound);
// Store a new secret (corresponding to an id). // Store a new secret (corresponding to an id).
let store_request = StoreSecretRequest { sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
id: Id(ID_EXAMPLE),
secret: Secret(SECRET_EXAMPLE),
sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
};
let store_request = store_request.serialize_to_packet().to_vec().unwrap();
let store_response = sk_client.secret_management_request(&store_request);
let store_response = ResponsePacket::from_slice(&store_response).unwrap();
assert_eq!(
store_response.response_type().unwrap(),
ResponseType::Success
);
// Get the restored secret. // Get the restored secret.
let get_request = GetSecretRequest { assert_eq!(sk_client.get(&ID_EXAMPLE), Some(SECRET_EXAMPLE));
id: Id(ID_EXAMPLE),
updated_sealing_policy: None,
};
let get_request = get_request.serialize_to_packet().to_vec().unwrap();
let get_response = sk_client.secret_management_request(&get_request);
let get_response = ResponsePacket::from_slice(&get_response).unwrap();
// Get the secret that was just re-stored.
assert_eq!(get_response.response_type().unwrap(), ResponseType::Success);
let get_response = *GetSecretResponse::deserialize_from_packet(get_response).unwrap();
assert_eq!(get_response.secret.0, SECRET_EXAMPLE);
// (Try to) Get the secret that was never stored // (Try to) Get the secret that was never stored
let get_request = GetSecretRequest { assert_eq!(sk_client.get(&ID_NOT_STORED), None);
id: Id(ID_NOT_STORED),
updated_sealing_policy: None,
};
let get_request = get_request.serialize_to_packet().to_vec().unwrap();
let get_response = sk_client.secret_management_request(&get_request);
// Check that response is `SecretkeeperError::EntryNotFound`
let get_response = ResponsePacket::from_slice(&get_response).unwrap();
assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
assert_eq!(err, SecretkeeperError::EntryNotFound);
} }