AuthGraph: add per-role VTS tests
Add VTS tests that just exercise a single role, sink or source.
Use the AuthGraph core library to provide the implementation of the
other role. This means that the tests are best written in Rust.
Put the test code into a library, so that other HALs which include
AuthGraph as a component can exercise the AuthGraph parts in their own
VTS tests.
Test: VtsAidlAuthGraphRoleTest
Bug: 284470121
Change-Id: I73f6aa277b41cc728587d707d7a6f82f0d18e08f
diff --git a/security/authgraph/aidl/vts/functional/lib.rs b/security/authgraph/aidl/vts/functional/lib.rs
new file mode 100644
index 0000000..7b9b2b9
--- /dev/null
+++ b/security/authgraph/aidl/vts/functional/lib.rs
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+//! VTS test library for AuthGraph functionality.
+//!
+//! This test code is bundled as a library, not as `[cfg(test)]`, to allow it to be
+//! re-used inside the (Rust) VTS tests of components that use AuthGraph.
+
+use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
+ Error::Error, IAuthGraphKeyExchange::IAuthGraphKeyExchange, Identity::Identity,
+ PlainPubKey::PlainPubKey, PubKey::PubKey, SessionIdSignature::SessionIdSignature,
+};
+use authgraph_boringssl as boring;
+use authgraph_core::keyexchange as ke;
+use authgraph_core::{arc, key, traits};
+use authgraph_nonsecure::StdClock;
+use coset::CborSerializable;
+
+pub mod sink;
+pub mod source;
+
+/// Return a collection of AuthGraph trait implementations suitable for testing.
+pub fn test_impls() -> traits::TraitImpl {
+ // Note that the local implementation is using a clock with a potentially different epoch than
+ // the implementation under test.
+ boring::trait_impls(
+ Box::<boring::test_device::AgDevice>::default(),
+ Some(Box::new(StdClock::default())),
+ )
+}
+
+fn build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> PubKey {
+ PubKey::PlainKey(PlainPubKey {
+ plainPubKey: pub_key.clone().unwrap(),
+ })
+}
+
+fn extract_plain_pub_key(pub_key: &Option<PubKey>) -> &PlainPubKey {
+ match pub_key {
+ Some(PubKey::PlainKey(pub_key)) => pub_key,
+ Some(PubKey::SignedKey(_)) => panic!("expect unsigned public key"),
+ None => panic!("expect pubKey to be populated"),
+ }
+}
+
+fn verification_key_from_identity(impls: &traits::TraitImpl, identity: &[u8]) -> key::EcVerifyKey {
+ let identity = key::Identity::from_slice(identity).expect("invalid identity CBOR");
+ impls
+ .device
+ .process_peer_cert_chain(&identity.cert_chain, &*impls.ecdsa)
+ .expect("failed to extract signing key")
+}
+
+fn vec_to_identity(data: &[u8]) -> Identity {
+ Identity {
+ identity: data.to_vec(),
+ }
+}
+
+fn vec_to_signature(data: &[u8]) -> SessionIdSignature {
+ SessionIdSignature {
+ signature: data.to_vec(),
+ }
+}
+
+/// Decrypt a pair of AES-256 keys encrypted with the AuthGraph PBK.
+pub fn decipher_aes_keys(imp: &traits::TraitImpl, arc: &[Vec<u8>; 2]) -> [key::AesKey; 2] {
+ [
+ decipher_aes_key(imp, &arc[0]),
+ decipher_aes_key(imp, &arc[1]),
+ ]
+}
+
+/// Decrypt an AES-256 key encrypted with the AuthGraph PBK.
+pub fn decipher_aes_key(imp: &traits::TraitImpl, arc: &[u8]) -> key::AesKey {
+ let pbk = imp.device.get_per_boot_key().expect("no PBK available");
+ let arc::ArcContent {
+ payload,
+ protected_headers: _,
+ unprotected_headers: _,
+ } = arc::decipher_arc(&pbk, arc, &*imp.aes_gcm).expect("failed to decrypt arc");
+ assert_eq!(payload.0.len(), 32);
+ let mut key = key::AesKey([0; 32]);
+ key.0.copy_from_slice(&payload.0);
+ assert_ne!(key.0, [0; 32], "agreed AES-256 key should be non-zero");
+ key
+}