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