Add (nonsecure) default AuthGraph impl
Add an implementation for the AuthGraph key exchange HAL, to allow
testing and policy compliance.
In real use, IAuthGraphKeyExchange instances are expected to be
retrieved from some other HAL, allowing the AuthGraph instance to be
specifically correlated with the component that uses it.
Bug: 284470121
Bug: 291228560
Test: hal_implementation_test
Test: VtsAidlAuthGraphSessionTest
Change-Id: Ib064292d60bead663af7721fd1406f2a9b5d8ecd
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index b348d35..6ed8e8f 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -513,7 +513,7 @@
<version>1</version>
<interface>
<name>IAuthGraphKeyExchange</name>
- <instance>default</instance>
+ <instance>nonsecure</instance>
</interface>
</hal>
<hal format="aidl" optional="true" updatable-via-apex="true">
diff --git a/security/authgraph/default/Android.bp b/security/authgraph/default/Android.bp
new file mode 100644
index 0000000..9de3bc1
--- /dev/null
+++ b/security/authgraph/default/Android.bp
@@ -0,0 +1,46 @@
+//
+// 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.
+//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+rust_binary {
+ name: "android.hardware.security.authgraph-service.nonsecure",
+ relative_install_path: "hw",
+ vendor: true,
+ init_rc: ["authgraph.rc"],
+ vintf_fragments: ["authgraph.xml"],
+ defaults: [
+ "authgraph_use_latest_hal_aidl_rust",
+ ],
+ rustlibs: [
+ "libandroid_logger",
+ "libauthgraph_core",
+ "libauthgraph_boringssl",
+ "libauthgraph_hal",
+ "libbinder_rs",
+ "liblibc",
+ "liblog_rust",
+ ],
+ srcs: [
+ "src/main.rs",
+ ],
+}
diff --git a/security/authgraph/default/authgraph.rc b/security/authgraph/default/authgraph.rc
new file mode 100644
index 0000000..0222994
--- /dev/null
+++ b/security/authgraph/default/authgraph.rc
@@ -0,0 +1,5 @@
+service vendor.authgraph /vendor/bin/hw/android.hardware.security.authgraph-service.nonsecure
+ interface aidl android.hardware.security.authgraph.IAuthGraph/nonsecure
+ class hal
+ user nobody
+ group nobody
diff --git a/security/authgraph/default/authgraph.xml b/security/authgraph/default/authgraph.xml
new file mode 100644
index 0000000..9529a0a
--- /dev/null
+++ b/security/authgraph/default/authgraph.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.security.authgraph</name>
+ <version>1</version>
+ <interface>
+ <name>IAuthGraphKeyExchange</name>
+ <instance>nonsecure</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/security/authgraph/default/src/main.rs b/security/authgraph/default/src/main.rs
new file mode 100644
index 0000000..2112e58
--- /dev/null
+++ b/security/authgraph/default/src/main.rs
@@ -0,0 +1,227 @@
+/*
+ * 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.
+ */
+
+//! Default implementation of the AuthGraph key exchange HAL.
+//!
+//! This implementation of the HAL is only intended to allow testing and policy compliance. A real
+//! implementation of the AuthGraph HAL would be implemented in a secure environment, and would not
+//! be independently registered with service manager (a secure component that uses AuthGraph would
+//! expose an entrypoint that allowed retrieval of the specific IAuthGraphKeyExchange instance that
+//! is correlated with the component).
+
+use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
+ Arc::Arc, IAuthGraphKeyExchange::BnAuthGraphKeyExchange,
+ IAuthGraphKeyExchange::IAuthGraphKeyExchange, Identity::Identity, KeInitResult::KeInitResult,
+ Key::Key, PubKey::PubKey, SessionIdSignature::SessionIdSignature, SessionInfo::SessionInfo,
+ SessionInitiationInfo::SessionInitiationInfo,
+};
+use authgraph_boringssl as boring;
+use authgraph_core::{key::MillisecondsSinceEpoch, keyexchange as ke, traits};
+use authgraph_hal::{err_to_binder, Innto, TryInnto};
+use log::{error, info};
+use std::ffi::CString;
+use std::sync::Mutex;
+
+static SERVICE_NAME: &str = "android.hardware.security.authgraph.IAuthGraphKeyExchange";
+static SERVICE_INSTANCE: &str = "nonsecure";
+
+/// Local error type for failures in the HAL service.
+#[derive(Debug, Clone)]
+struct HalServiceError(String);
+
+impl From<String> for HalServiceError {
+ fn from(s: String) -> Self {
+ Self(s)
+ }
+}
+
+fn main() {
+ if let Err(e) = inner_main() {
+ panic!("HAL service failed: {:?}", e);
+ }
+}
+
+fn inner_main() -> Result<(), HalServiceError> {
+ // Initialize Android logging.
+ android_logger::init_once(
+ android_logger::Config::default()
+ .with_tag("authgraph-hal-nonsecure")
+ .with_min_level(log::Level::Info)
+ .with_log_id(android_logger::LogId::System),
+ );
+ // Redirect panic messages to logcat.
+ std::panic::set_hook(Box::new(|panic_info| {
+ error!("{}", panic_info);
+ }));
+
+ info!("Insecure AuthGraph key exchange HAL service is starting.");
+
+ info!("Starting thread pool now.");
+ binder::ProcessState::start_thread_pool();
+
+ // Register the service
+ let service = AuthGraphService::new_as_binder();
+ let service_name = format!("{}/{}", SERVICE_NAME, SERVICE_INSTANCE);
+ binder::add_service(&service_name, service.as_binder()).map_err(|e| {
+ format!(
+ "Failed to register service {} because of {:?}.",
+ service_name, e
+ )
+ })?;
+
+ info!("Successfully registered AuthGraph HAL services.");
+ binder::ProcessState::join_thread_pool();
+ info!("AuthGraph HAL service is terminating."); // should not reach here
+ Ok(())
+}
+
+/// Non-secure implementation of the AuthGraph key exchange service.
+struct AuthGraphService {
+ imp: Mutex<traits::TraitImpl>,
+}
+
+impl AuthGraphService {
+ /// Create a new instance.
+ fn new() -> Self {
+ Self {
+ imp: Mutex::new(traits::TraitImpl {
+ aes_gcm: Box::new(boring::BoringAes),
+ ecdh: Box::new(boring::BoringEcDh),
+ ecdsa: Box::new(boring::BoringEcDsa),
+ hmac: Box::new(boring::BoringHmac),
+ hkdf: Box::new(boring::BoringHkdf),
+ sha256: Box::new(boring::BoringSha256),
+ rng: Box::new(boring::BoringRng),
+ device: Box::<boring::test_device::AgDevice>::default(),
+ clock: Some(Box::new(StdClock)),
+ }),
+ }
+ }
+
+ /// Create a new instance wrapped in a proxy object.
+ pub fn new_as_binder() -> binder::Strong<dyn IAuthGraphKeyExchange> {
+ BnAuthGraphKeyExchange::new_binder(Self::new(), binder::BinderFeatures::default())
+ }
+}
+
+impl binder::Interface for AuthGraphService {}
+
+/// Extract (and require) an unsigned public key as bytes from a [`PubKey`].
+fn unsigned_pub_key(pub_key: &PubKey) -> binder::Result<&[u8]> {
+ match pub_key {
+ PubKey::PlainKey(key) => Ok(&key.plainPubKey),
+ PubKey::SignedKey(_) => Err(binder::Status::new_exception(
+ binder::ExceptionCode::ILLEGAL_ARGUMENT,
+ Some(&CString::new("expected unsigned public key").unwrap()),
+ )),
+ }
+}
+
+/// This nonsecure implementation of the AuthGraph HAL interface directly calls the AuthGraph
+/// reference implementation library code; a real implementation requires the AuthGraph
+/// code to run in a secure environment, not within Android.
+impl IAuthGraphKeyExchange for AuthGraphService {
+ fn create(&self) -> binder::Result<SessionInitiationInfo> {
+ info!("create()");
+ let mut imp = self.imp.lock().unwrap();
+ let info = ke::create(&mut *imp).map_err(err_to_binder)?;
+ Ok(info.innto())
+ }
+ fn init(
+ &self,
+ peer_pub_key: &PubKey,
+ peer_id: &Identity,
+ peer_nonce: &[u8],
+ peer_version: i32,
+ ) -> binder::Result<KeInitResult> {
+ info!("init(v={peer_version})");
+ let mut imp = self.imp.lock().unwrap();
+ let peer_pub_key = unsigned_pub_key(peer_pub_key)?;
+ let result = ke::init(
+ &mut *imp,
+ peer_pub_key,
+ &peer_id.identity,
+ &peer_nonce,
+ peer_version,
+ )
+ .map_err(err_to_binder)?;
+ Ok(result.innto())
+ }
+
+ fn finish(
+ &self,
+ peer_pub_key: &PubKey,
+ peer_id: &Identity,
+ peer_signature: &SessionIdSignature,
+ peer_nonce: &[u8],
+ peer_version: i32,
+ own_key: &Key,
+ ) -> binder::Result<SessionInfo> {
+ info!("finish(v={peer_version})");
+ let mut imp = self.imp.lock().unwrap();
+ let peer_pub_key = unsigned_pub_key(peer_pub_key)?;
+ let own_key: Key = own_key.clone();
+ let own_key: authgraph_core::key::Key = own_key.try_innto()?;
+ let session_info = ke::finish(
+ &mut *imp,
+ peer_pub_key,
+ &peer_id.identity,
+ &peer_signature.signature,
+ &peer_nonce,
+ peer_version,
+ own_key,
+ )
+ .map_err(err_to_binder)?;
+ Ok(session_info.innto())
+ }
+
+ fn authenticationComplete(
+ &self,
+ peer_signature: &SessionIdSignature,
+ shared_keys: &[Arc; 2],
+ ) -> binder::Result<[Arc; 2]> {
+ info!("authComplete()");
+ let mut imp = self.imp.lock().unwrap();
+ let shared_keys = [shared_keys[0].arc.clone(), shared_keys[1].arc.clone()];
+ let arcs = ke::authentication_complete(&mut *imp, &peer_signature.signature, shared_keys)
+ .map_err(err_to_binder)?;
+ Ok(arcs.map(|arc| Arc { arc }))
+ }
+}
+
+/// Monotonic clock.
+#[derive(Default)]
+pub struct StdClock;
+
+impl traits::MonotonicClock for StdClock {
+ fn now(&self) -> authgraph_core::key::MillisecondsSinceEpoch {
+ let mut time = libc::timespec {
+ tv_sec: 0, // libc::time_t
+ tv_nsec: 0, // libc::c_long
+ };
+ let rc =
+ // Safety: `time` is a valid structure.
+ unsafe { libc::clock_gettime(libc::CLOCK_BOOTTIME, &mut time as *mut libc::timespec) };
+ if rc < 0 {
+ log::warn!("failed to get time!");
+ return MillisecondsSinceEpoch(0);
+ }
+ // The types in `libc::timespec` may be different on different architectures,
+ // so allow conversion to `i64`.
+ #[allow(clippy::unnecessary_cast)]
+ MillisecondsSinceEpoch((time.tv_sec as i64 * 1000) + (time.tv_nsec as i64 / 1000 / 1000))
+ }
+}