// Copyright 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. //! IRemotelyProvisionedComponent HAL implementation. use crate::rkpvm; use android_hardware_security_rkp::aidl::android::hardware::security::keymint::{ DeviceInfo::DeviceInfo, IRemotelyProvisionedComponent::{ BnRemotelyProvisionedComponent, IRemotelyProvisionedComponent, STATUS_FAILED, STATUS_INVALID_MAC, STATUS_REMOVED, }, MacedPublicKey::MacedPublicKey, ProtectedData::ProtectedData, RpcHardwareInfo::{RpcHardwareInfo, CURVE_NONE, MIN_SUPPORTED_NUM_KEYS_IN_CSR}, }; use anyhow::Context; use avflog::LogResult; use binder::{ BinderFeatures, ExceptionCode, Interface, IntoBinderResult, Result as BinderResult, Status, Strong, }; use hypervisor_props::is_protected_vm_supported; use rustutils::system_properties; use service_vm_comm::{RequestProcessingError, Response}; /// Constructs a binder object that implements `IRemotelyProvisionedComponent`. pub(crate) fn new_binder() -> Strong { BnRemotelyProvisionedComponent::new_binder( AvfRemotelyProvisionedComponent {}, BinderFeatures::default(), ) } struct AvfRemotelyProvisionedComponent {} impl Interface for AvfRemotelyProvisionedComponent {} #[allow(non_snake_case)] impl IRemotelyProvisionedComponent for AvfRemotelyProvisionedComponent { fn getHardwareInfo(&self) -> BinderResult { check_remote_attestation_is_supported()?; Ok(RpcHardwareInfo { versionNumber: 3, rpcAuthorName: String::from("Android Virtualization Framework"), supportedEekCurve: CURVE_NONE, uniqueId: Some(String::from("AVF Remote Provisioning 1")), supportedNumKeysInCsr: MIN_SUPPORTED_NUM_KEYS_IN_CSR, }) } fn generateEcdsaP256KeyPair( &self, testMode: bool, macedPublicKey: &mut MacedPublicKey, ) -> BinderResult> { check_remote_attestation_is_supported()?; if testMode { return Err(Status::new_service_specific_error_str( STATUS_REMOVED, Some("generateEcdsaP256KeyPair does not support test mode in IRPC v3+ HAL."), )) .with_log(); } let res = rkpvm::generate_ecdsa_p256_key_pair() .context("Failed to generate ECDSA P-256 key pair") .with_log() .or_service_specific_exception(STATUS_FAILED)?; match res { Response::GenerateEcdsaP256KeyPair(key_pair) => { macedPublicKey.macedKey = key_pair.maced_public_key; Ok(key_pair.key_blob) } _ => Err(to_service_specific_error(res)), } .with_log() } fn generateCertificateRequest( &self, _testMode: bool, _keysToSign: &[MacedPublicKey], _endpointEncryptionCertChain: &[u8], _challenge: &[u8], _deviceInfo: &mut DeviceInfo, _protectedData: &mut ProtectedData, ) -> BinderResult> { Err(Status::new_service_specific_error_str( STATUS_REMOVED, Some("This method was deprecated in v3 of the interface."), )) .with_log() } fn generateCertificateRequestV2( &self, keysToSign: &[MacedPublicKey], challenge: &[u8], ) -> BinderResult> { check_remote_attestation_is_supported()?; const MAX_CHALLENGE_SIZE: usize = 64; if challenge.len() > MAX_CHALLENGE_SIZE { let message = format!( "Challenge is too big. Actual: {:?}. Maximum: {:?}.", challenge.len(), MAX_CHALLENGE_SIZE ); return Err(Status::new_service_specific_error_str(STATUS_FAILED, Some(message))) .with_log(); } let res = rkpvm::generate_certificate_request(keysToSign, challenge) .context("Failed to generate certificate request") .with_log() .or_service_specific_exception(STATUS_FAILED)?; match res { Response::GenerateCertificateRequest(res) => Ok(res), _ => Err(to_service_specific_error(res)), } .with_log() } } pub(crate) fn check_remote_attestation_is_supported() -> BinderResult<()> { if !is_protected_vm_supported().unwrap_or(false) { return Err(Status::new_exception_str( ExceptionCode::UNSUPPORTED_OPERATION, Some("Protected VM support is missing for this operation"), )) .with_log(); } if !is_remote_attestation_supported() { return Err(Status::new_exception_str( ExceptionCode::UNSUPPORTED_OPERATION, Some("Remote attestation is disabled"), )) .with_log(); } Ok(()) } pub(crate) fn is_remote_attestation_supported() -> bool { // Remote attestation is enabled by default. system_properties::read_bool("avf.remote_attestation.enabled", true).unwrap_or(true) } pub(crate) fn to_service_specific_error(response: Response) -> Status { match response { Response::Err(e) => match e { RequestProcessingError::InvalidMac => { Status::new_service_specific_error_str(STATUS_INVALID_MAC, Some(format!("{e}"))) } _ => Status::new_service_specific_error_str( STATUS_FAILED, Some(format!("Failed to process request: {e}.")), ), }, other => Status::new_service_specific_error_str( STATUS_FAILED, Some(format!("Incorrect response type: {other:?}")), ), } }