Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 74f8aadf authored by David Drysdale's avatar David Drysdale Committed by Automerger Merge Worker
Browse files

AuthGraph: move code into library am: 6c09af21 am: 8a036f62

parents d5b5f268 8a036f62
Loading
Loading
Loading
Loading
+21 −3
Original line number Diff line number Diff line
@@ -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",
+81 −0
Original line number Diff line number Diff line
/*
 * 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))
    }
}
+5 −157
Original line number Diff line number Diff line
@@ -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))
    }
}