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

Commit 695f0260 authored by David Drysdale's avatar David Drysdale Committed by Gerrit Code Review
Browse files

Merge "KeyMint: default to Rust reference implementation" into main

parents 337c6afb 30196cf7
Loading
Loading
Loading
Loading
+48 −22
Original line number Diff line number Diff line
@@ -7,39 +7,29 @@ package {
    default_applicable_licenses: ["hardware_interfaces_license"],
}

cc_binary {
rust_binary {
    name: "android.hardware.security.keymint-service",
    relative_install_path: "hw",
    vendor: true,
    init_rc: ["android.hardware.security.keymint-service.rc"],
    vintf_fragments: [
        "android.hardware.security.keymint-service.xml",
        "android.hardware.security.sharedsecret-service.xml",
        "android.hardware.security.secureclock-service.xml",
    ],
    vendor: true,
    cflags: [
        "-Wall",
        "-Wextra",
    ],
    defaults: [
        "keymint_use_latest_hal_aidl_ndk_shared",
    ],
    shared_libs: [
        "android.hardware.security.rkp-V3-ndk",
        "android.hardware.security.sharedsecret-V1-ndk",
        "android.hardware.security.secureclock-V1-ndk",
        "libbase",
        "libbinder_ndk",
        "libcppbor_external",
        "libcrypto",
        "libkeymaster_portable",
        "libkeymint",
        "liblog",
        "libpuresoftkeymasterdevice",
        "libutils",
        "keymint_use_latest_hal_aidl_rust",
    ],
    srcs: [
        "service.cpp",
        "main.rs",
    ],
    rustlibs: [
        "libandroid_logger",
        "libbinder_rs",
        "liblog_rust",
        "libkmr_hal",
        "libkmr_hal_nonsecure",
        "libkmr_ta_nonsecure",
    ],
    required: [
        "android.hardware.hardware_keystore.xml",
@@ -52,3 +42,39 @@ prebuilt_etc {
    vendor: true,
    src: "android.hardware.hardware_keystore.xml",
}

rust_library {
    name: "libkmr_hal_nonsecure",
    crate_name: "kmr_hal_nonsecure",
    vendor_available: true,
    lints: "android",
    rustlibs: [
        "libbinder_rs",
        "libhex",
        "liblibc",
        "liblog_rust",
        "libkmr_hal",
        "libkmr_wire",
    ],
    srcs: ["hal/lib.rs"],

}

rust_library {
    name: "libkmr_ta_nonsecure",
    crate_name: "kmr_ta_nonsecure",
    vendor_available: true,
    host_supported: true,
    lints: "android",
    rustlibs: [
        "libhex",
        "liblibc",
        "liblog_rust",
        "libkmr_common",
        "libkmr_crypto_boring",
        "libkmr_ta",
        "libkmr_wire",
    ],
    srcs: ["ta/lib.rs"],

}
+99 −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.
 */

//! KeyMint helper functions that are only suitable for non-secure environments
//! such as Cuttlefish.

use kmr_hal::env::get_property;
use log::error;

/// Populate attestation ID information based on properties (where available).
/// Retrieving the serial number requires SELinux permission.
pub fn attestation_id_info() -> kmr_wire::AttestationIdInfo {
    let prop = |name| {
        get_property(name)
            .unwrap_or_else(|_| format!("{} unavailable", name))
            .as_bytes()
            .to_vec()
    };
    kmr_wire::AttestationIdInfo {
        brand: prop("ro.product.brand"),
        device: prop("ro.product.device"),
        product: prop("ro.product.name"),
        serial: prop("ro.serialno"),
        manufacturer: prop("ro.product.manufacturer"),
        model: prop("ro.product.model"),
        // Currently modem_simulator always returns one fixed value. See `handleGetIMEI` in
        // device/google/cuttlefish/host/commands/modem_simulator/misc_service.cpp for more details.
        // TODO(b/263188546): Use device-specific IMEI values when available.
        imei: b"867400022047199".to_vec(),
        imei2: b"867400022047199".to_vec(),
        meid: vec![],
    }
}

/// Get boot information based on system properties.
pub fn get_boot_info() -> kmr_wire::SetBootInfoRequest {
    // No access to a verified boot key.
    let verified_boot_key = vec![0; 32];
    let vbmeta_digest = get_property("ro.boot.vbmeta.digest").unwrap_or_else(|_| "00".repeat(32));
    let verified_boot_hash = hex::decode(&vbmeta_digest).unwrap_or_else(|_e| {
        error!("failed to parse hex data in '{}'", vbmeta_digest);
        vec![0; 32]
    });
    let device_boot_locked = match get_property("ro.boot.vbmeta.device_state")
        .unwrap_or_else(|_| "no-prop".to_string())
        .as_str()
    {
        "locked" => true,
        "unlocked" => false,
        v => {
            error!("Unknown device_state '{}', treating as unlocked", v);
            false
        }
    };
    let verified_boot_state = match get_property("ro.boot.verifiedbootstate")
        .unwrap_or_else(|_| "no-prop".to_string())
        .as_str()
    {
        "green" => 0,  // Verified
        "yellow" => 1, // SelfSigned
        "orange" => 2, // Unverified,
        "red" => 3,    // Failed,
        v => {
            error!("Unknown boot state '{}', treating as Unverified", v);
            2
        }
    };

    // Attempt to get the boot patchlevel from a system property.  This requires an SELinux
    // permission, so fall back to re-using the OS patchlevel if this can't be done.
    let boot_patchlevel_prop = get_property("ro.vendor.boot_security_patch").unwrap_or_else(|e| {
        error!("Failed to retrieve boot patchlevel: {:?}", e);
        get_property(kmr_hal::env::OS_PATCHLEVEL_PROPERTY)
            .unwrap_or_else(|_| "1970-09-19".to_string())
    });
    let boot_patchlevel =
        kmr_hal::env::extract_patchlevel(&boot_patchlevel_prop).unwrap_or(19700919);

    kmr_wire::SetBootInfoRequest {
        verified_boot_key,
        device_boot_locked,
        verified_boot_state,
        verified_boot_hash,
        boot_patchlevel,
    }
}
+174 −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.
 */

//! Default implementation of the KeyMint HAL and related HALs.
//!
//! This implementation of the HAL is only intended to allow testing and policy compliance.  A real
//! implementation **must be implemented in a secure environment**.

use kmr_hal::SerializedChannel;
use kmr_hal_nonsecure::{attestation_id_info, get_boot_info};
use log::{debug, error, info};
use std::ops::DerefMut;
use std::sync::{mpsc, Arc, Mutex};

/// Name of KeyMint binder device instance.
static SERVICE_INSTANCE: &str = "default";

static KM_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
static RPC_SERVICE_NAME: &str = "android.hardware.security.keymint.IRemotelyProvisionedComponent";
static CLOCK_SERVICE_NAME: &str = "android.hardware.security.secureclock.ISecureClock";
static SECRET_SERVICE_NAME: &str = "android.hardware.security.sharedsecret.ISharedSecret";

/// 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("keymint-hal-nonsecure")
            .with_max_level(log::LevelFilter::Info)
            .with_log_buffer(android_logger::LogId::System),
    );
    // Redirect panic messages to logcat.
    std::panic::set_hook(Box::new(|panic_info| {
        error!("{}", panic_info);
    }));

    info!("Insecure KeyMint HAL service is starting.");

    info!("Starting thread pool now.");
    binder::ProcessState::start_thread_pool();

    // Create a TA in-process, which acts as a local channel for communication.
    let channel = Arc::new(Mutex::new(LocalTa::new()));

    let km_service = kmr_hal::keymint::Device::new_as_binder(channel.clone());
    let service_name = format!("{}/{}", KM_SERVICE_NAME, SERVICE_INSTANCE);
    binder::add_service(&service_name, km_service.as_binder()).map_err(|e| {
        HalServiceError(format!(
            "Failed to register service {} because of {:?}.",
            service_name, e
        ))
    })?;

    let rpc_service = kmr_hal::rpc::Device::new_as_binder(channel.clone());
    let service_name = format!("{}/{}", RPC_SERVICE_NAME, SERVICE_INSTANCE);
    binder::add_service(&service_name, rpc_service.as_binder()).map_err(|e| {
        HalServiceError(format!(
            "Failed to register service {} because of {:?}.",
            service_name, e
        ))
    })?;

    let clock_service = kmr_hal::secureclock::Device::new_as_binder(channel.clone());
    let service_name = format!("{}/{}", CLOCK_SERVICE_NAME, SERVICE_INSTANCE);
    binder::add_service(&service_name, clock_service.as_binder()).map_err(|e| {
        HalServiceError(format!(
            "Failed to register service {} because of {:?}.",
            service_name, e
        ))
    })?;

    let secret_service = kmr_hal::sharedsecret::Device::new_as_binder(channel.clone());
    let service_name = format!("{}/{}", SECRET_SERVICE_NAME, SERVICE_INSTANCE);
    binder::add_service(&service_name, secret_service.as_binder()).map_err(|e| {
        HalServiceError(format!(
            "Failed to register service {} because of {:?}.",
            service_name, e
        ))
    })?;

    info!("Successfully registered KeyMint HAL services.");

    // Let the TA know information about the boot environment. In a real device this
    // is communicated directly from the bootloader to the TA, but here we retrieve
    // the information from system properties and send from the HAL service.
    let boot_req = get_boot_info();
    debug!("boot/HAL->TA: boot info is {:?}", boot_req);
    kmr_hal::send_boot_info(channel.lock().unwrap().deref_mut(), boot_req)
        .map_err(|e| HalServiceError(format!("Failed to send boot info: {:?}", e)))?;

    // Let the TA know information about the userspace environment.
    if let Err(e) = kmr_hal::send_hal_info(channel.lock().unwrap().deref_mut()) {
        error!("Failed to send HAL info: {:?}", e);
    }

    // Let the TA know about attestation IDs. (In a real device these would be pre-provisioned into
    // the TA.)
    let attest_ids = attestation_id_info();
    if let Err(e) = kmr_hal::send_attest_ids(channel.lock().unwrap().deref_mut(), attest_ids) {
        error!("Failed to send attestation ID info: {:?}", e);
    }

    info!("Successfully registered KeyMint HAL services.");
    binder::ProcessState::join_thread_pool();
    info!("KeyMint HAL service is terminating."); // should not reach here
    Ok(())
}

/// Implementation of the KeyMint TA that runs locally in-process (and which is therefore
/// insecure).
#[derive(Debug)]
pub struct LocalTa {
    in_tx: mpsc::Sender<Vec<u8>>,
    out_rx: mpsc::Receiver<Vec<u8>>,
}

impl LocalTa {
    /// Create a new instance.
    pub fn new() -> Self {
        // Create a pair of channels to communicate with the TA thread.
        let (in_tx, in_rx) = mpsc::channel();
        let (out_tx, out_rx) = mpsc::channel();

        // The TA code expects to run single threaded, so spawn a thread to run it in.
        std::thread::spawn(move || {
            let mut ta = kmr_ta_nonsecure::build_ta();
            loop {
                let req_data: Vec<u8> = in_rx.recv().expect("failed to receive next req");
                let rsp_data = ta.process(&req_data);
                out_tx.send(rsp_data).expect("failed to send out rsp");
            }
        });
        Self { in_tx, out_rx }
    }
}

impl SerializedChannel for LocalTa {
    const MAX_SIZE: usize = usize::MAX;

    fn execute(&mut self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
        self.in_tx
            .send(req_data.to_vec())
            .expect("failed to send in request");
        Ok(self.out_rx.recv().expect("failed to receive response"))
    }
}
+0 −63
Original line number Diff line number Diff line
/*
 * Copyright 2020, 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.
 */

#define LOG_TAG "android.hardware.security.keymint-service"

#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>

#include <AndroidKeyMintDevice.h>
#include <AndroidRemotelyProvisionedComponentDevice.h>
#include <AndroidSecureClock.h>
#include <AndroidSharedSecret.h>
#include <keymaster/soft_keymaster_logger.h>

using aidl::android::hardware::security::keymint::AndroidKeyMintDevice;
using aidl::android::hardware::security::keymint::AndroidRemotelyProvisionedComponentDevice;
using aidl::android::hardware::security::keymint::SecurityLevel;
using aidl::android::hardware::security::secureclock::AndroidSecureClock;
using aidl::android::hardware::security::sharedsecret::AndroidSharedSecret;

template <typename T, class... Args>
std::shared_ptr<T> addService(Args&&... args) {
    std::shared_ptr<T> ser = ndk::SharedRefBase::make<T>(std::forward<Args>(args)...);
    auto instanceName = std::string(T::descriptor) + "/default";
    LOG(INFO) << "adding keymint service instance: " << instanceName;
    binder_status_t status =
            AServiceManager_addService(ser->asBinder().get(), instanceName.c_str());
    CHECK_EQ(status, STATUS_OK);
    return ser;
}

int main() {
    // The global logger object required by keymaster's logging macros in keymaster/logger.h.
    keymaster::SoftKeymasterLogger km_logger;
    // Zero threads seems like a useless pool, but below we'll join this thread to it, increasing
    // the pool size to 1.
    ABinderProcess_setThreadPoolMaxThreadCount(0);
    // Add Keymint Service
    std::shared_ptr<AndroidKeyMintDevice> keyMint =
            addService<AndroidKeyMintDevice>(SecurityLevel::SOFTWARE);
    // Add Secure Clock Service
    addService<AndroidSecureClock>(keyMint);
    // Add Shared Secret Service
    addService<AndroidSharedSecret>(keyMint);
    // Add Remotely Provisioned Component Service
    addService<AndroidRemotelyProvisionedComponentDevice>(keyMint);
    ABinderProcess_joinThreadPool();
    return EXIT_FAILURE;  // should not reach
}
+425 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading