1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! Implementation of the AIDL interface `IVmPayloadService`.
16
17 use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::{
18 BnVmPayloadService, IVmPayloadService, VM_PAYLOAD_SERVICE_SOCKET_NAME, AttestationResult::AttestationResult,
19 STATUS_FAILED_TO_PREPARE_CSR_AND_KEY
20 };
21 use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::IVirtualMachineService;
22 use anyhow::{anyhow, Context, Result};
23 use avflog::LogResult;
24 use binder::{Interface, BinderFeatures, ExceptionCode, Strong, IntoBinderResult, Status};
25 use client_vm_csr::{generate_attestation_key_and_csr, ClientVmAttestationData};
26 use log::info;
27 use rpcbinder::RpcServer;
28 use crate::vm_secret::VmSecret;
29 use std::os::unix::io::OwnedFd;
30
31 /// Implementation of `IVmPayloadService`.
32 struct VmPayloadService {
33 allow_restricted_apis: bool,
34 virtual_machine_service: Strong<dyn IVirtualMachineService>,
35 secret: VmSecret,
36 }
37
38 impl IVmPayloadService for VmPayloadService {
notifyPayloadReady(&self) -> binder::Result<()>39 fn notifyPayloadReady(&self) -> binder::Result<()> {
40 self.virtual_machine_service.notifyPayloadReady()
41 }
42
getVmInstanceSecret(&self, identifier: &[u8], size: i32) -> binder::Result<Vec<u8>>43 fn getVmInstanceSecret(&self, identifier: &[u8], size: i32) -> binder::Result<Vec<u8>> {
44 if !(0..=32).contains(&size) {
45 return Err(anyhow!("size {size} not in range (0..=32)"))
46 .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT);
47 }
48 let mut instance_secret = vec![0; size.try_into().unwrap()];
49 self.secret
50 .derive_payload_sealing_key(identifier, &mut instance_secret)
51 .context("Failed to derive VM instance secret")
52 .with_log()
53 .or_service_specific_exception(-1)?;
54 Ok(instance_secret)
55 }
56
getDiceAttestationChain(&self) -> binder::Result<Vec<u8>>57 fn getDiceAttestationChain(&self) -> binder::Result<Vec<u8>> {
58 self.check_restricted_apis_allowed()?;
59 if let Some(bcc) = self.secret.dice_artifacts().bcc() {
60 Ok(bcc.to_vec())
61 } else {
62 Err(anyhow!("bcc is none")).or_binder_exception(ExceptionCode::ILLEGAL_STATE)
63 }
64 }
65
getDiceAttestationCdi(&self) -> binder::Result<Vec<u8>>66 fn getDiceAttestationCdi(&self) -> binder::Result<Vec<u8>> {
67 self.check_restricted_apis_allowed()?;
68 Ok(self.secret.dice_artifacts().cdi_attest().to_vec())
69 }
70
requestAttestation( &self, challenge: &[u8], test_mode: bool, ) -> binder::Result<AttestationResult>71 fn requestAttestation(
72 &self,
73 challenge: &[u8],
74 test_mode: bool,
75 ) -> binder::Result<AttestationResult> {
76 let ClientVmAttestationData { private_key, csr } =
77 generate_attestation_key_and_csr(challenge, self.secret.dice_artifacts())
78 .map_err(|e| {
79 Status::new_service_specific_error_str(
80 STATUS_FAILED_TO_PREPARE_CSR_AND_KEY,
81 Some(format!("Failed to prepare the CSR and key pair: {e:?}")),
82 )
83 })
84 .with_log()?;
85 let csr = csr
86 .into_cbor_vec()
87 .map_err(|e| {
88 Status::new_service_specific_error_str(
89 STATUS_FAILED_TO_PREPARE_CSR_AND_KEY,
90 Some(format!("Failed to serialize CSR into CBOR: {e:?}")),
91 )
92 })
93 .with_log()?;
94 let cert_chain = self.virtual_machine_service.requestAttestation(&csr, test_mode)?;
95 Ok(AttestationResult {
96 privateKey: private_key.as_slice().to_vec(),
97 certificateChain: cert_chain,
98 })
99 }
100 }
101
102 impl Interface for VmPayloadService {}
103
104 impl VmPayloadService {
105 /// Creates a new `VmPayloadService` instance from the `IVirtualMachineService` reference.
new( allow_restricted_apis: bool, vm_service: Strong<dyn IVirtualMachineService>, secret: VmSecret, ) -> VmPayloadService106 fn new(
107 allow_restricted_apis: bool,
108 vm_service: Strong<dyn IVirtualMachineService>,
109 secret: VmSecret,
110 ) -> VmPayloadService {
111 Self { allow_restricted_apis, virtual_machine_service: vm_service, secret }
112 }
113
check_restricted_apis_allowed(&self) -> binder::Result<()>114 fn check_restricted_apis_allowed(&self) -> binder::Result<()> {
115 if self.allow_restricted_apis {
116 Ok(())
117 } else {
118 Err(anyhow!("Use of restricted APIs is not allowed"))
119 .with_log()
120 .or_binder_exception(ExceptionCode::SECURITY)
121 }
122 }
123 }
124
125 /// Registers the `IVmPayloadService` service.
register_vm_payload_service( allow_restricted_apis: bool, vm_service: Strong<dyn IVirtualMachineService>, secret: VmSecret, vm_payload_service_fd: OwnedFd, ) -> Result<()>126 pub(crate) fn register_vm_payload_service(
127 allow_restricted_apis: bool,
128 vm_service: Strong<dyn IVirtualMachineService>,
129 secret: VmSecret,
130 vm_payload_service_fd: OwnedFd,
131 ) -> Result<()> {
132 let vm_payload_binder = BnVmPayloadService::new_binder(
133 VmPayloadService::new(allow_restricted_apis, vm_service, secret),
134 BinderFeatures::default(),
135 );
136
137 let server = RpcServer::new_bound_socket(vm_payload_binder.as_binder(), vm_payload_service_fd)?;
138 info!("The RPC server '{}' is running.", VM_PAYLOAD_SERVICE_SOCKET_NAME);
139
140 // Move server reference into a background thread and run it forever.
141 std::thread::spawn(move || {
142 server.join();
143 });
144 Ok(())
145 }
146