AuthGraph: move code into library

Use the core library's new service implementation, which wraps a
channel to the TA.

In this nonsecure case, the TA is local in-process, so use the core
library's AuthGraphTa, and implement the SerializedChannel as just
a direct invocation of the TA.

Move this code into a _nonsecure library, so the main.rs just has
the code needed to start the executable and register the service.

Test: VtsAidlAuthGraphSessionTest
Bug: 284470121
Change-Id: I738d3876872a8cd248f0ebec708676d1173b6e37
This commit is contained in:
David Drysdale
2023-11-06 09:57:10 +00:00
parent f2117ff77c
commit 6c09af215d
3 changed files with 107 additions and 160 deletions

View File

@@ -22,6 +22,26 @@ package {
default_applicable_licenses: ["hardware_interfaces_license"],
}
rust_library {
name: "libauthgraph_nonsecure",
crate_name: "authgraph_nonsecure",
defaults: [
"authgraph_use_latest_hal_aidl_rust",
],
vendor_available: true,
rustlibs: [
"libandroid_logger",
"libauthgraph_boringssl",
"libauthgraph_core",
"libauthgraph_hal",
"libbinder_rs",
"liblibc",
"liblog_rust",
],
srcs: ["src/lib.rs"],
}
rust_binary {
name: "android.hardware.security.authgraph-service.nonsecure",
relative_install_path: "hw",
@@ -33,10 +53,8 @@ rust_binary {
],
rustlibs: [
"libandroid_logger",
"libauthgraph_core",
"libauthgraph_boringssl",
"libauthgraph_hal",
"libauthgraph_wire",
"libauthgraph_nonsecure",
"libbinder_rs",
"liblibc",
"liblog_rust",

View File

@@ -0,0 +1,81 @@
/*
* 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.
*/
//! Common functionality for non-secure/testing instance of AuthGraph.
use authgraph_boringssl as boring;
use authgraph_core::{
key::MillisecondsSinceEpoch,
ta::{AuthGraphTa, Role},
traits,
};
use authgraph_hal::channel::SerializedChannel;
use std::sync::{Arc, Mutex};
use std::time::Instant;
/// Monotonic clock with an epoch that starts at the point of construction.
/// (This makes it unsuitable for use outside of testing, because the epoch
/// will not match that of any other component.)
pub struct StdClock(Instant);
impl Default for StdClock {
fn default() -> Self {
Self(Instant::now())
}
}
impl traits::MonotonicClock for StdClock {
fn now(&self) -> MillisecondsSinceEpoch {
let millis: i64 = self
.0
.elapsed()
.as_millis()
.try_into()
.expect("failed to fit timestamp in i64");
MillisecondsSinceEpoch(millis)
}
}
/// Implementation of the AuthGraph TA that runs locally in-process (and which is therefore
/// insecure).
pub struct LocalTa {
ta: Arc<Mutex<AuthGraphTa>>,
}
impl LocalTa {
/// Create a new instance.
pub fn new() -> Self {
Self {
ta: Arc::new(Mutex::new(AuthGraphTa::new(
boring::trait_impls(
Box::<boring::test_device::AgDevice>::default(),
Some(Box::new(StdClock::default())),
),
Role::Both,
))),
}
}
}
/// Pretend to be a serialized channel to the TA, but actually just directly invoke the TA with
/// incoming requests.
impl SerializedChannel for LocalTa {
const MAX_SIZE: usize = usize::MAX;
fn execute(&mut self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
Ok(self.ta.lock().unwrap().process(req_data))
}
}

View File

@@ -22,18 +22,10 @@
//! 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::{errcode_to_binder, Innto, TryInnto};
use authgraph_hal::service;
use authgraph_nonsecure::LocalTa;
use log::{error, info};
use std::ffi::CString;
use std::sync::Mutex;
use std::sync::{Arc, Mutex};
static SERVICE_NAME: &str = "android.hardware.security.authgraph.IAuthGraphKeyExchange";
static SERVICE_INSTANCE: &str = "nonsecure";
@@ -73,7 +65,8 @@ fn inner_main() -> Result<(), HalServiceError> {
binder::ProcessState::start_thread_pool();
// Register the service
let service = AuthGraphService::new_as_binder();
let local_ta = LocalTa::new();
let service = service::AuthGraphService::new_as_binder(Arc::new(Mutex::new(local_ta)));
let service_name = format!("{}/{}", SERVICE_NAME, SERVICE_INSTANCE);
binder::add_service(&service_name, service.as_binder()).map_err(|e| {
format!(
@@ -87,148 +80,3 @@ fn inner_main() -> Result<(), HalServiceError> {
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()),
)),
}
}
fn err_to_binder(err: authgraph_core::error::Error) -> binder::Status {
if err.0 != authgraph_wire::ErrorCode::Ok && !err.1.is_empty() {
error!("failure {:?} message: '{}'", err.0, err.1);
}
errcode_to_binder(err.0)
}
/// 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))
}
}