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