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 //! Integration test for Rialto.
16 
17 use android_system_virtualizationservice::{
18     aidl::android::system::virtualizationservice::{
19         VirtualMachineConfig::VirtualMachineConfig,
20         VirtualMachineRawConfig::VirtualMachineRawConfig,
21     },
22     binder::{ParcelFileDescriptor, ProcessState},
23 };
24 use anyhow::{bail, Context, Result};
25 use bssl_avf::{rand_bytes, sha256, EcKey, PKey};
26 use client_vm_csr::generate_attestation_key_and_csr;
27 use coset::{CborSerializable, CoseMac0, CoseSign};
28 use hwtrust::{
29     rkp,
30     session::{RkpInstance, Session},
31 };
32 use log::{info, warn};
33 use service_vm_comm::{
34     ClientVmAttestationParams, Csr, CsrPayload, EcdsaP256KeyPair, GenerateCertificateRequestParams,
35     Request, RequestProcessingError, Response, VmType,
36 };
37 use service_vm_fake_chain::client_vm::{
38     fake_client_vm_dice_artifacts, fake_sub_components, SubComponent,
39 };
40 use service_vm_manager::{ServiceVm, VM_MEMORY_MB};
41 use std::fs;
42 use std::fs::File;
43 use std::panic;
44 use std::path::PathBuf;
45 use std::str::FromStr;
46 use vmclient::VmInstance;
47 use x509_cert::{
48     certificate::{Certificate, Version},
49     der::{self, asn1, Decode, Encode},
50     name::Name,
51     spki::{AlgorithmIdentifier, ObjectIdentifier, SubjectPublicKeyInfo},
52 };
53 
54 const UNSIGNED_RIALTO_PATH: &str = "/data/local/tmp/rialto_test/arm64/rialto_unsigned.bin";
55 const INSTANCE_IMG_PATH: &str = "/data/local/tmp/rialto_test/arm64/instance.img";
56 const TEST_CERT_CHAIN_PATH: &str = "testdata/rkp_cert_chain.der";
57 
58 #[cfg(dice_changes)]
59 #[test]
process_requests_in_protected_vm() -> Result<()>60 fn process_requests_in_protected_vm() -> Result<()> {
61     if hypervisor_props::is_protected_vm_supported()? {
62         // The test is skipped if the feature flag |dice_changes| is not enabled, because when
63         // the flag is off, the DICE chain is truncated in the pvmfw, and the service VM cannot
64         // verify the chain due to the missing entries in the chain.
65         check_processing_requests(VmType::ProtectedVm, None)
66     } else {
67         warn!("pVMs are not supported on device, skipping test");
68         Ok(())
69     }
70 }
71 
72 #[test]
process_requests_in_non_protected_vm() -> Result<()>73 fn process_requests_in_non_protected_vm() -> Result<()> {
74     const MEMORY_MB: i32 = 300;
75     check_processing_requests(VmType::NonProtectedVm, Some(MEMORY_MB))?;
76     check_processing_requests(VmType::NonProtectedVm, None)
77 }
78 
check_processing_requests(vm_type: VmType, vm_memory_mb: Option<i32>) -> Result<()>79 fn check_processing_requests(vm_type: VmType, vm_memory_mb: Option<i32>) -> Result<()> {
80     let mut vm = start_service_vm(vm_type, vm_memory_mb)?;
81 
82     check_processing_reverse_request(&mut vm)?;
83     let key_pair = check_processing_generating_key_pair_request(&mut vm)?;
84     check_processing_generating_certificate_request(&mut vm, &key_pair.maced_public_key)?;
85     check_attestation_request(&mut vm, &key_pair, vm_type)?;
86     Ok(())
87 }
88 
check_processing_reverse_request(vm: &mut ServiceVm) -> Result<()>89 fn check_processing_reverse_request(vm: &mut ServiceVm) -> Result<()> {
90     let message = "abc".repeat(500);
91     let request = Request::Reverse(message.as_bytes().to_vec());
92 
93     let response = vm.process_request(request)?;
94     info!("Received response: {response:?}.");
95 
96     let expected_response: Vec<u8> = message.as_bytes().iter().rev().cloned().collect();
97     assert_eq!(Response::Reverse(expected_response), response);
98     Ok(())
99 }
100 
check_processing_generating_key_pair_request(vm: &mut ServiceVm) -> Result<EcdsaP256KeyPair>101 fn check_processing_generating_key_pair_request(vm: &mut ServiceVm) -> Result<EcdsaP256KeyPair> {
102     let request = Request::GenerateEcdsaP256KeyPair;
103 
104     let response = vm.process_request(request)?;
105     info!("Received response: {response:?}.");
106 
107     match response {
108         Response::GenerateEcdsaP256KeyPair(key_pair) => {
109             assert_array_has_nonzero(&key_pair.maced_public_key);
110             assert_array_has_nonzero(&key_pair.key_blob);
111             Ok(key_pair)
112         }
113         _ => bail!("Incorrect response type: {response:?}"),
114     }
115 }
116 
assert_array_has_nonzero(v: &[u8])117 fn assert_array_has_nonzero(v: &[u8]) {
118     assert!(v.iter().any(|&x| x != 0))
119 }
120 
check_processing_generating_certificate_request( vm: &mut ServiceVm, maced_public_key: &[u8], ) -> Result<()>121 fn check_processing_generating_certificate_request(
122     vm: &mut ServiceVm,
123     maced_public_key: &[u8],
124 ) -> Result<()> {
125     let params = GenerateCertificateRequestParams {
126         keys_to_sign: vec![maced_public_key.to_vec()],
127         challenge: vec![],
128     };
129     let request = Request::GenerateCertificateRequest(params);
130 
131     let response = vm.process_request(request)?;
132     info!("Received response: {response:?}.");
133 
134     match response {
135         Response::GenerateCertificateRequest(csr) => check_csr(csr),
136         _ => bail!("Incorrect response type: {response:?}"),
137     }
138 }
139 
check_attestation_request( vm: &mut ServiceVm, remotely_provisioned_key_pair: &EcdsaP256KeyPair, vm_type: VmType, ) -> Result<()>140 fn check_attestation_request(
141     vm: &mut ServiceVm,
142     remotely_provisioned_key_pair: &EcdsaP256KeyPair,
143     vm_type: VmType,
144 ) -> Result<()> {
145     /// The following data was generated randomly with urandom.
146     const CHALLENGE: [u8; 16] = [
147         0x7d, 0x86, 0x58, 0x79, 0x3a, 0x09, 0xdf, 0x1c, 0xa5, 0x80, 0x80, 0x15, 0x2b, 0x13, 0x17,
148         0x5c,
149     ];
150     let dice_artifacts = fake_client_vm_dice_artifacts()?;
151     let attestation_data = generate_attestation_key_and_csr(&CHALLENGE, &dice_artifacts)?;
152     let cert_chain = fs::read(TEST_CERT_CHAIN_PATH)?;
153     // The certificate chain contains several certificates, but we only need the first one.
154     // Parsing the data with trailing data always fails with a `TrailingData` error.
155     let cert_len: usize = match Certificate::from_der(&cert_chain).unwrap_err().kind() {
156         der::ErrorKind::TrailingData { decoded, .. } => decoded.try_into().unwrap(),
157         e => bail!("Unexpected error: {e}"),
158     };
159 
160     // Builds the mock parameters for the client VM attestation.
161     // The `csr` and `remotely_provisioned_key_blob` parameters are extracted from the same
162     // libraries as in production.
163     // The `remotely_provisioned_cert` parameter is an RKP certificate extracted from a test
164     // certificate chain retrieved from RKPD.
165     let params = ClientVmAttestationParams {
166         csr: attestation_data.csr.clone().into_cbor_vec()?,
167         remotely_provisioned_key_blob: remotely_provisioned_key_pair.key_blob.to_vec(),
168         remotely_provisioned_cert: cert_chain[..cert_len].to_vec(),
169     };
170     let request = Request::RequestClientVmAttestation(params);
171 
172     let response = vm.process_request(request)?;
173     info!("Received response: {response:?}.");
174 
175     match response {
176         Response::RequestClientVmAttestation(certificate) => {
177             // The end-to-end test for non-protected VM attestation works because both the service
178             // VM and the client VM use the same fake DICE chain.
179             assert_eq!(vm_type, VmType::NonProtectedVm);
180             check_certificate_for_client_vm(
181                 &certificate,
182                 &remotely_provisioned_key_pair.maced_public_key,
183                 &attestation_data.csr,
184                 &Certificate::from_der(&cert_chain[..cert_len]).unwrap(),
185             )?;
186             Ok(())
187         }
188         Response::Err(RequestProcessingError::InvalidDiceChain) => {
189             // The end-to-end test for protected VM attestation doesn't work because the service VM
190             // compares the fake DICE chain in the CSR with the real DICE chain.
191             // We cannot generate a valid DICE chain with the same payloads up to pvmfw.
192             assert_eq!(vm_type, VmType::ProtectedVm);
193             Ok(())
194         }
195         _ => bail!("Incorrect response type: {response:?}"),
196     }
197 }
198 
check_vm_components(vm_components: &asn1::SequenceOf<asn1::Any, 4>) -> Result<()>199 fn check_vm_components(vm_components: &asn1::SequenceOf<asn1::Any, 4>) -> Result<()> {
200     let expected_components = fake_sub_components();
201     assert_eq!(expected_components.len(), vm_components.len());
202     for (i, expected_component) in expected_components.iter().enumerate() {
203         check_vm_component(vm_components.get(i).unwrap(), expected_component)?;
204     }
205     Ok(())
206 }
207 
check_vm_component(vm_component: &asn1::Any, expected_component: &SubComponent) -> Result<()>208 fn check_vm_component(vm_component: &asn1::Any, expected_component: &SubComponent) -> Result<()> {
209     let vm_component = vm_component.decode_as::<asn1::SequenceOf<asn1::Any, 4>>().unwrap();
210     assert_eq!(4, vm_component.len());
211     let name = vm_component.get(0).unwrap().decode_as::<asn1::Utf8StringRef>().unwrap();
212     let name_str: &str = name.as_ref();
213     assert_eq!(expected_component.name, name_str);
214     let version = vm_component.get(1).unwrap().decode_as::<u64>().unwrap();
215     assert_eq!(expected_component.version, version);
216     let code_hash = vm_component.get(2).unwrap().decode_as::<asn1::OctetString>().unwrap();
217     assert_eq!(expected_component.code_hash, code_hash.as_bytes());
218     let authority_hash = vm_component.get(3).unwrap().decode_as::<asn1::OctetString>().unwrap();
219     assert_eq!(expected_component.authority_hash, authority_hash.as_bytes());
220     Ok(())
221 }
222 
check_certificate_for_client_vm( certificate: &[u8], maced_public_key: &[u8], csr: &Csr, parent_certificate: &Certificate, ) -> Result<()>223 fn check_certificate_for_client_vm(
224     certificate: &[u8],
225     maced_public_key: &[u8],
226     csr: &Csr,
227     parent_certificate: &Certificate,
228 ) -> Result<()> {
229     let cose_mac = CoseMac0::from_slice(maced_public_key)?;
230     let authority_public_key =
231         EcKey::from_cose_public_key_slice(&cose_mac.payload.unwrap()).unwrap();
232     let cert = Certificate::from_der(certificate).unwrap();
233 
234     // Checks the certificate signature against the authority public key.
235     const ECDSA_WITH_SHA_256: ObjectIdentifier =
236         ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.2");
237     let expected_algorithm = AlgorithmIdentifier { oid: ECDSA_WITH_SHA_256, parameters: None };
238     assert_eq!(expected_algorithm, cert.signature_algorithm);
239     let tbs_cert = cert.tbs_certificate;
240     let digest = sha256(&tbs_cert.to_der().unwrap()).unwrap();
241     authority_public_key
242         .ecdsa_verify_der(cert.signature.raw_bytes(), &digest)
243         .expect("Failed to verify the certificate signature with the authority public key");
244 
245     // Checks that the certificate's subject public key is equal to the key in the CSR.
246     let cose_sign = CoseSign::from_slice(&csr.signed_csr_payload)?;
247     let csr_payload =
248         cose_sign.payload.as_ref().and_then(|v| CsrPayload::from_cbor_slice(v).ok()).unwrap();
249     let subject_public_key = EcKey::from_cose_public_key_slice(&csr_payload.public_key).unwrap();
250     let expected_spki_data =
251         PKey::try_from(subject_public_key).unwrap().subject_public_key_info().unwrap();
252     let expected_spki = SubjectPublicKeyInfo::from_der(&expected_spki_data).unwrap();
253     assert_eq!(expected_spki, tbs_cert.subject_public_key_info);
254 
255     // Checks the certificate extension.
256     const ATTESTATION_EXTENSION_OID: ObjectIdentifier =
257         ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11129.2.1.29.1");
258     let extensions = tbs_cert.extensions.unwrap();
259     assert_eq!(1, extensions.len());
260     let extension = &extensions[0];
261     assert_eq!(ATTESTATION_EXTENSION_OID, extension.extn_id);
262     assert!(!extension.critical);
263     let attestation_ext =
264         asn1::SequenceOf::<asn1::Any, 3>::from_der(extension.extn_value.as_bytes()).unwrap();
265     assert_eq!(3, attestation_ext.len());
266     let challenge = attestation_ext.get(0).unwrap().decode_as::<asn1::OctetString>().unwrap();
267     assert_eq!(csr_payload.challenge, challenge.as_bytes());
268     let is_vm_secure = attestation_ext.get(1).unwrap().decode_as::<bool>().unwrap();
269     assert!(
270         !is_vm_secure,
271         "The VM shouldn't be secure as the last payload added in the test is in Debug mode"
272     );
273     let vm_components =
274         attestation_ext.get(2).unwrap().decode_as::<asn1::SequenceOf<asn1::Any, 4>>().unwrap();
275     check_vm_components(&vm_components)?;
276 
277     // Checks other fields on the certificate
278     assert_eq!(Version::V3, tbs_cert.version);
279     assert_eq!(parent_certificate.tbs_certificate.validity, tbs_cert.validity);
280     assert_eq!(
281         Name::from_str("CN=Android Protected Virtual Machine Key").unwrap(),
282         tbs_cert.subject
283     );
284     assert_eq!(parent_certificate.tbs_certificate.subject, tbs_cert.issuer);
285 
286     Ok(())
287 }
288 
check_csr(csr: Vec<u8>) -> Result<()>289 fn check_csr(csr: Vec<u8>) -> Result<()> {
290     let mut session = Session::default();
291     session.set_allow_any_mode(true);
292     session.set_rkp_instance(RkpInstance::Avf);
293     let _csr = rkp::Csr::from_cbor(&session, &csr[..]).context("Failed to parse CSR")?;
294     Ok(())
295 }
296 
start_service_vm(vm_type: VmType, vm_memory_mb: Option<i32>) -> Result<ServiceVm>297 fn start_service_vm(vm_type: VmType, vm_memory_mb: Option<i32>) -> Result<ServiceVm> {
298     android_logger::init_once(
299         android_logger::Config::default()
300             .with_tag("rialto")
301             .with_max_level(log::LevelFilter::Debug),
302     );
303     // Redirect panic messages to logcat.
304     panic::set_hook(Box::new(|panic_info| {
305         log::error!("{}", panic_info);
306     }));
307     // We need to start the thread pool for Binder to work properly, especially link_to_death.
308     ProcessState::start_thread_pool();
309     ServiceVm::start_vm(vm_instance(vm_type, vm_memory_mb)?, vm_type)
310 }
311 
vm_instance(vm_type: VmType, vm_memory_mb: Option<i32>) -> Result<VmInstance>312 fn vm_instance(vm_type: VmType, vm_memory_mb: Option<i32>) -> Result<VmInstance> {
313     match vm_type {
314         VmType::ProtectedVm => {
315             assert!(vm_memory_mb.is_none());
316             service_vm_manager::protected_vm_instance(PathBuf::from(INSTANCE_IMG_PATH))
317         }
318         VmType::NonProtectedVm => nonprotected_vm_instance(vm_memory_mb.unwrap_or(VM_MEMORY_MB)),
319     }
320 }
321 
nonprotected_vm_instance(memory_mib: i32) -> Result<VmInstance>322 fn nonprotected_vm_instance(memory_mib: i32) -> Result<VmInstance> {
323     let rialto = File::open(UNSIGNED_RIALTO_PATH).context("Failed to open Rialto kernel binary")?;
324     // Do not use `#allocateInstanceId` to generate the instance ID because the method
325     // also adds an instance ID to the database it manages.
326     // This is not necessary for this test.
327     let mut instance_id = [0u8; 64];
328     rand_bytes(&mut instance_id).unwrap();
329     let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
330         name: format!("Non protected rialto ({memory_mib}MiB)"),
331         kernel: Some(ParcelFileDescriptor::new(rialto)),
332         protectedVm: false,
333         memoryMib: memory_mib,
334         platformVersion: "~1.0".to_string(),
335         instanceId: instance_id,
336         ..Default::default()
337     });
338     let console = Some(service_vm_manager::android_log_fd()?);
339     let log = Some(service_vm_manager::android_log_fd()?);
340     let virtmgr = vmclient::VirtualizationService::new().context("Failed to spawn VirtMgr")?;
341     let service = virtmgr.connect().context("Failed to connect to VirtMgr")?;
342     info!("Connected to VirtMgr for service VM");
343     VmInstance::create(
344         service.as_ref(),
345         &config,
346         console,
347         /* consoleIn */ None,
348         log,
349         /* dump_dt */ None,
350         None,
351     )
352     .context("Failed to create VM")
353 }
354