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