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