blob: 0260773b0607b3307ff005facb8b5a40dc6492b8 [file] [log] [blame]
David Brazdil66fc1202022-07-04 21:48:45 +01001// 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
17use android_system_virtualizationservice::{
18 aidl::android::system::virtualizationservice::{
Alice Wanga6357692023-09-07 14:59:37 +000019 VirtualMachineConfig::VirtualMachineConfig,
David Brazdil66fc1202022-07-04 21:48:45 +010020 VirtualMachineRawConfig::VirtualMachineRawConfig,
21 },
22 binder::{ParcelFileDescriptor, ProcessState},
23};
Alice Wang9646fb32023-09-08 10:01:31 +000024use anyhow::{bail, Context, Result};
Alice Wang20b8ebc2023-11-17 09:54:47 +000025use bssl_avf::{sha256, EcKey, EvpPKey};
Alice Wangf7c0f942023-09-14 09:33:04 +000026use ciborium::value::Value;
Alice Wangde6bee52023-11-10 09:58:40 +000027use client_vm_csr::generate_attestation_key_and_csr;
Alice Wang20b8ebc2023-11-17 09:54:47 +000028use coset::{CborSerializable, CoseMac0, CoseSign};
Alice Wangd3a96402023-11-24 15:37:39 +000029use cstr::cstr;
30use diced_open_dice::{
31 retry_bcc_format_config_descriptor, retry_bcc_main_flow, Config, DiceArtifacts,
32 DiceConfigValues, DiceMode, InputValues, OwnedDiceArtifacts, HASH_SIZE, HIDDEN_SIZE,
33};
David Brazdil66fc1202022-07-04 21:48:45 +010034use log::info;
Alice Wang9646fb32023-09-08 10:01:31 +000035use service_vm_comm::{
Alice Wang20b8ebc2023-11-17 09:54:47 +000036 ClientVmAttestationParams, Csr, CsrPayload, EcdsaP256KeyPair, GenerateCertificateRequestParams,
Alice Wangd3a96402023-11-24 15:37:39 +000037 Request, RequestProcessingError, Response, VmType,
Alice Wang9646fb32023-09-08 10:01:31 +000038};
Alice Wang17dc76e2023-09-06 09:43:52 +000039use service_vm_manager::ServiceVm;
Alice Wang20b8ebc2023-11-17 09:54:47 +000040use std::fs;
David Brazdil66fc1202022-07-04 21:48:45 +010041use std::fs::File;
Alice Wangf7c0f942023-09-14 09:33:04 +000042use std::io;
David Brazdil66fc1202022-07-04 21:48:45 +010043use std::panic;
Alice Wang17dc76e2023-09-06 09:43:52 +000044use std::path::PathBuf;
Alice Wang17dc76e2023-09-06 09:43:52 +000045use vmclient::VmInstance;
Alice Wang20b8ebc2023-11-17 09:54:47 +000046use x509_parser::{
47 certificate::X509Certificate,
48 der_parser::{der::parse_der, oid, oid::Oid},
49 prelude::FromDer,
50 x509::{AlgorithmIdentifier, SubjectPublicKeyInfo, X509Version},
51};
Alice Wang4e082c32023-07-11 07:41:50 +000052
Alice Wang9a8b39f2023-04-12 15:31:48 +000053const UNSIGNED_RIALTO_PATH: &str = "/data/local/tmp/rialto_test/arm64/rialto_unsigned.bin";
54const INSTANCE_IMG_PATH: &str = "/data/local/tmp/rialto_test/arm64/instance.img";
Alice Wang20b8ebc2023-11-17 09:54:47 +000055const TEST_CERT_CHAIN_PATH: &str = "testdata/rkp_cert_chain.der";
Alice Wangd3a96402023-11-24 15:37:39 +000056/// The following data are generated randomly with urandom.
57const CODE_HASH_MICRODROID: [u8; HASH_SIZE] = [
58 0x08, 0x78, 0xc2, 0x5b, 0xe7, 0xea, 0x3d, 0x62, 0x70, 0x22, 0xd9, 0x1c, 0x4f, 0x3c, 0x2e, 0x2f,
59 0x0f, 0x97, 0xa4, 0x6f, 0x6d, 0xd5, 0xe6, 0x4a, 0x6d, 0xbe, 0x34, 0x2e, 0x56, 0x04, 0xaf, 0xef,
60 0x74, 0x3f, 0xec, 0xb8, 0x44, 0x11, 0xf4, 0x2f, 0x05, 0xb2, 0x06, 0xa3, 0x0e, 0x75, 0xb7, 0x40,
61 0x9a, 0x4c, 0x58, 0xab, 0x96, 0xe7, 0x07, 0x97, 0x07, 0x86, 0x5c, 0xa1, 0x42, 0x12, 0xf0, 0x34,
62];
63const AUTHORITY_HASH_MICRODROID: [u8; HASH_SIZE] = [
64 0xc7, 0x97, 0x5b, 0xa9, 0x9e, 0xbf, 0x0b, 0xeb, 0xe7, 0x7f, 0x69, 0x8f, 0x8e, 0xcf, 0x04, 0x7d,
65 0x2c, 0x0f, 0x4d, 0xbe, 0xcb, 0xf5, 0xf1, 0x4c, 0x1d, 0x1c, 0xb7, 0x44, 0xdf, 0xf8, 0x40, 0x90,
66 0x09, 0x65, 0xab, 0x01, 0x34, 0x3e, 0xc2, 0xc4, 0xf7, 0xa2, 0x3a, 0x5c, 0x4e, 0x76, 0x4f, 0x42,
67 0xa8, 0x6c, 0xc9, 0xf1, 0x7b, 0x12, 0x80, 0xa4, 0xef, 0xa2, 0x4d, 0x72, 0xa1, 0x21, 0xe2, 0x47,
68];
David Brazdil66fc1202022-07-04 21:48:45 +010069
Alice Wang9a8b39f2023-04-12 15:31:48 +000070#[test]
Alice Wange910b902023-09-07 10:35:12 +000071fn process_requests_in_protected_vm() -> Result<()> {
Alice Wang9646fb32023-09-08 10:01:31 +000072 check_processing_requests(VmType::ProtectedVm)
Alice Wang9a8b39f2023-04-12 15:31:48 +000073}
74
Alice Wange910b902023-09-07 10:35:12 +000075#[test]
76fn process_requests_in_non_protected_vm() -> Result<()> {
Alice Wang9646fb32023-09-08 10:01:31 +000077 check_processing_requests(VmType::NonProtectedVm)
78}
79
80fn check_processing_requests(vm_type: VmType) -> Result<()> {
81 let mut vm = start_service_vm(vm_type)?;
Alice Wange910b902023-09-07 10:35:12 +000082
83 check_processing_reverse_request(&mut vm)?;
Alice Wang74eb78b2023-11-09 16:13:10 +000084 let key_pair = check_processing_generating_key_pair_request(&mut vm)?;
85 check_processing_generating_certificate_request(&mut vm, &key_pair.maced_public_key)?;
Alice Wangd3a96402023-11-24 15:37:39 +000086 check_attestation_request(&mut vm, &key_pair, vm_type)?;
Alice Wange910b902023-09-07 10:35:12 +000087 Ok(())
88}
89
90fn check_processing_reverse_request(vm: &mut ServiceVm) -> Result<()> {
Alice Wang0486e252023-10-06 14:30:49 +000091 let message = "abc".repeat(500);
Alice Wange910b902023-09-07 10:35:12 +000092 let request = Request::Reverse(message.as_bytes().to_vec());
93
Alice Wangfbdc85b2023-09-07 12:56:46 +000094 let response = vm.process_request(request)?;
95 info!("Received response: {response:?}.");
Alice Wange910b902023-09-07 10:35:12 +000096
97 let expected_response: Vec<u8> = message.as_bytes().iter().rev().cloned().collect();
98 assert_eq!(Response::Reverse(expected_response), response);
99 Ok(())
100}
101
Alice Wang74eb78b2023-11-09 16:13:10 +0000102fn check_processing_generating_key_pair_request(vm: &mut ServiceVm) -> Result<EcdsaP256KeyPair> {
Alice Wang9646fb32023-09-08 10:01:31 +0000103 let request = Request::GenerateEcdsaP256KeyPair;
104
105 let response = vm.process_request(request)?;
106 info!("Received response: {response:?}.");
107
108 match response {
Alice Wang74eb78b2023-11-09 16:13:10 +0000109 Response::GenerateEcdsaP256KeyPair(key_pair) => {
110 assert_array_has_nonzero(&key_pair.maced_public_key);
111 assert_array_has_nonzero(&key_pair.key_blob);
112 Ok(key_pair)
Alice Wanga78d3f02023-09-13 12:39:16 +0000113 }
Alice Wangff5592d2023-09-13 15:27:39 +0000114 _ => bail!("Incorrect response type: {response:?}"),
Alice Wang9646fb32023-09-08 10:01:31 +0000115 }
116}
117
Alice Wanga78d3f02023-09-13 12:39:16 +0000118fn assert_array_has_nonzero(v: &[u8]) {
119 assert!(v.iter().any(|&x| x != 0))
120}
121
Alice Wangff5592d2023-09-13 15:27:39 +0000122fn check_processing_generating_certificate_request(
123 vm: &mut ServiceVm,
Alice Wang74eb78b2023-11-09 16:13:10 +0000124 maced_public_key: &[u8],
Alice Wangff5592d2023-09-13 15:27:39 +0000125) -> Result<()> {
126 let params = GenerateCertificateRequestParams {
Alice Wang74eb78b2023-11-09 16:13:10 +0000127 keys_to_sign: vec![maced_public_key.to_vec()],
Alice Wangff5592d2023-09-13 15:27:39 +0000128 challenge: vec![],
129 };
Alice Wang9646fb32023-09-08 10:01:31 +0000130 let request = Request::GenerateCertificateRequest(params);
131
132 let response = vm.process_request(request)?;
133 info!("Received response: {response:?}.");
134
135 match response {
Alice Wangf7c0f942023-09-14 09:33:04 +0000136 Response::GenerateCertificateRequest(csr) => check_csr(csr),
Alice Wangff5592d2023-09-13 15:27:39 +0000137 _ => bail!("Incorrect response type: {response:?}"),
Alice Wang9646fb32023-09-08 10:01:31 +0000138 }
139}
140
Alice Wang20b8ebc2023-11-17 09:54:47 +0000141fn check_attestation_request(
142 vm: &mut ServiceVm,
143 remotely_provisioned_key_pair: &EcdsaP256KeyPair,
Alice Wangd3a96402023-11-24 15:37:39 +0000144 vm_type: VmType,
Alice Wang20b8ebc2023-11-17 09:54:47 +0000145) -> Result<()> {
Alice Wangde6bee52023-11-10 09:58:40 +0000146 /// The following data was generated randomly with urandom.
147 const CHALLENGE: [u8; 16] = [
148 0x7d, 0x86, 0x58, 0x79, 0x3a, 0x09, 0xdf, 0x1c, 0xa5, 0x80, 0x80, 0x15, 0x2b, 0x13, 0x17,
149 0x5c,
150 ];
151 let dice_artifacts = diced_sample_inputs::make_sample_bcc_and_cdis()?;
Alice Wangd3a96402023-11-24 15:37:39 +0000152 let dice_artifacts = extend_dice_artifacts_with_microdroid_payload(&dice_artifacts)?;
Alice Wangde6bee52023-11-10 09:58:40 +0000153 let attestation_data = generate_attestation_key_and_csr(&CHALLENGE, &dice_artifacts)?;
Alice Wang20b8ebc2023-11-17 09:54:47 +0000154 let cert_chain = fs::read(TEST_CERT_CHAIN_PATH)?;
155 let (remaining, cert) = X509Certificate::from_der(&cert_chain)?;
Alice Wangde6bee52023-11-10 09:58:40 +0000156
Alice Wang20b8ebc2023-11-17 09:54:47 +0000157 // Builds the mock parameters for the client VM attestation.
158 // The `csr` and `remotely_provisioned_key_blob` parameters are extracted from the same
159 // libraries as in production.
160 // The `remotely_provisioned_cert` parameter is an RKP certificate extracted from a test
161 // certificate chain retrieved from RKPD.
Alice Wangde6bee52023-11-10 09:58:40 +0000162 let params = ClientVmAttestationParams {
Alice Wang20b8ebc2023-11-17 09:54:47 +0000163 csr: attestation_data.csr.clone().into_cbor_vec()?,
164 remotely_provisioned_key_blob: remotely_provisioned_key_pair.key_blob.to_vec(),
165 remotely_provisioned_cert: cert_chain[..(cert_chain.len() - remaining.len())].to_vec(),
Alice Wangde6bee52023-11-10 09:58:40 +0000166 };
Alice Wang74eb78b2023-11-09 16:13:10 +0000167 let request = Request::RequestClientVmAttestation(params);
168
169 let response = vm.process_request(request)?;
170 info!("Received response: {response:?}.");
171
172 match response {
Alice Wang20b8ebc2023-11-17 09:54:47 +0000173 Response::RequestClientVmAttestation(certificate) => {
Alice Wangd3a96402023-11-24 15:37:39 +0000174 // The end-to-end test for non-protected VM attestation works because both the service
175 // VM and the client VM use the same fake DICE chain.
176 assert_eq!(vm_type, VmType::NonProtectedVm);
Alice Wang20b8ebc2023-11-17 09:54:47 +0000177 check_certificate_for_client_vm(
178 &certificate,
179 &remotely_provisioned_key_pair.maced_public_key,
180 &attestation_data.csr,
181 &cert,
182 )?;
183 Ok(())
184 }
Alice Wangd3a96402023-11-24 15:37:39 +0000185 Response::Err(RequestProcessingError::InvalidDiceChain) => {
186 // The end-to-end test for protected VM attestation doesn't work because the service VM
187 // compares the fake DICE chain in the CSR with the real DICE chain.
188 // We cannot generate a valid DICE chain with the same payloads up to pvmfw.
189 assert_eq!(vm_type, VmType::ProtectedVm);
190 Ok(())
191 }
Alice Wang74eb78b2023-11-09 16:13:10 +0000192 _ => bail!("Incorrect response type: {response:?}"),
193 }
194}
195
Alice Wangd3a96402023-11-24 15:37:39 +0000196fn extend_dice_artifacts_with_microdroid_payload(
197 dice_artifacts: &dyn DiceArtifacts,
198) -> Result<OwnedDiceArtifacts> {
199 let config_values = DiceConfigValues {
200 component_name: Some(cstr!("Microdroid payload")),
201 component_version: Some(1),
202 resettable: true,
203 ..Default::default()
204 };
205 let config_descriptor = retry_bcc_format_config_descriptor(&config_values)?;
206 let input_values = InputValues::new(
207 CODE_HASH_MICRODROID,
208 Config::Descriptor(config_descriptor.as_slice()),
209 AUTHORITY_HASH_MICRODROID,
210 DiceMode::kDiceModeDebug,
211 [0u8; HIDDEN_SIZE], // hidden
212 );
213 retry_bcc_main_flow(
214 dice_artifacts.cdi_attest(),
215 dice_artifacts.cdi_seal(),
216 dice_artifacts.bcc().unwrap(),
217 &input_values,
218 )
219 .context("Failed to run BCC main flow for Microdroid")
220}
221
Alice Wang20b8ebc2023-11-17 09:54:47 +0000222fn check_certificate_for_client_vm(
223 certificate: &[u8],
224 maced_public_key: &[u8],
225 csr: &Csr,
226 parent_certificate: &X509Certificate,
227) -> Result<()> {
228 let cose_mac = CoseMac0::from_slice(maced_public_key)?;
229 let authority_public_key = EcKey::from_cose_public_key(&cose_mac.payload.unwrap()).unwrap();
230 let (remaining, cert) = X509Certificate::from_der(certificate)?;
231 assert!(remaining.is_empty());
232
233 // Checks the certificate signature against the authority public key.
234 const ECDSA_WITH_SHA_256: Oid<'static> = oid!(1.2.840 .10045 .4 .3 .2);
235 let expected_algorithm =
236 AlgorithmIdentifier { algorithm: ECDSA_WITH_SHA_256, parameters: None };
237 assert_eq!(expected_algorithm, cert.signature_algorithm);
238 let digest = sha256(cert.tbs_certificate.as_ref()).unwrap();
239 authority_public_key
240 .ecdsa_verify(cert.signature_value.as_ref(), &digest)
241 .expect("Failed to verify the certificate signature with the authority public key");
242
243 // Checks that the certificate's subject public key is equal to the key in the CSR.
244 let cose_sign = CoseSign::from_slice(&csr.signed_csr_payload)?;
245 let csr_payload =
246 cose_sign.payload.as_ref().and_then(|v| CsrPayload::from_cbor_slice(v).ok()).unwrap();
247 let subject_public_key = EcKey::from_cose_public_key(&csr_payload.public_key).unwrap();
248 let expected_spki_data =
249 EvpPKey::try_from(subject_public_key).unwrap().subject_public_key_info().unwrap();
250 let (remaining, expected_spki) = SubjectPublicKeyInfo::from_der(&expected_spki_data)?;
251 assert!(remaining.is_empty());
252 assert_eq!(&expected_spki, cert.public_key());
253
254 // Checks the certificate extension.
255 const ATTESTATION_EXTENSION_OID: Oid<'static> = oid!(1.3.6 .1 .4 .1 .11129 .2 .1 .29 .1);
256 let extensions = cert.extensions();
257 assert_eq!(1, extensions.len());
258 let extension = &extensions[0];
259 assert_eq!(ATTESTATION_EXTENSION_OID, extension.oid);
260 assert!(!extension.critical);
261 let (remaining, extension) = parse_der(extension.value)?;
262 assert!(remaining.is_empty());
263 let attestation_ext = extension.as_sequence()?;
Alice Wangd3a96402023-11-24 15:37:39 +0000264 assert_eq!(2, attestation_ext.len());
Alice Wang20b8ebc2023-11-17 09:54:47 +0000265 assert_eq!(csr_payload.challenge, attestation_ext[0].as_slice()?);
Alice Wangd3a96402023-11-24 15:37:39 +0000266 let is_vm_secure = attestation_ext[1].as_bool()?;
267 assert!(
268 !is_vm_secure,
269 "The VM shouldn't be secure as the last payload added in the test is in Debug mode"
270 );
Alice Wang20b8ebc2023-11-17 09:54:47 +0000271
272 // Checks other fields on the certificate
273 assert_eq!(X509Version::V3, cert.version());
274 assert_eq!(parent_certificate.validity(), cert.validity());
275 assert_eq!(
276 String::from("CN=Android Protected Virtual Machine Key"),
277 cert.subject().to_string()
278 );
279 assert_eq!(parent_certificate.subject(), cert.issuer());
280
281 Ok(())
282}
283
Alice Wangf7c0f942023-09-14 09:33:04 +0000284/// TODO(b/300625792): Check the CSR with libhwtrust once the CSR is complete.
285fn check_csr(csr: Vec<u8>) -> Result<()> {
286 let mut reader = io::Cursor::new(csr);
287 let csr: Value = ciborium::from_reader(&mut reader)?;
288 match csr {
289 Value::Array(arr) => {
290 assert_eq!(4, arr.len());
291 }
292 _ => bail!("Incorrect CSR format: {csr:?}"),
293 }
294 Ok(())
295}
296
Alice Wange910b902023-09-07 10:35:12 +0000297fn start_service_vm(vm_type: VmType) -> Result<ServiceVm> {
David Brazdil66fc1202022-07-04 21:48:45 +0100298 android_logger::init_once(
299 android_logger::Config::default().with_tag("rialto").with_min_level(log::Level::Debug),
300 );
David Brazdil66fc1202022-07-04 21:48:45 +0100301 // Redirect panic messages to logcat.
302 panic::set_hook(Box::new(|panic_info| {
303 log::error!("{}", panic_info);
304 }));
David Brazdil66fc1202022-07-04 21:48:45 +0100305 // We need to start the thread pool for Binder to work properly, especially link_to_death.
306 ProcessState::start_thread_pool();
Alice Wange910b902023-09-07 10:35:12 +0000307 ServiceVm::start_vm(vm_instance(vm_type)?, vm_type)
Alice Wang17dc76e2023-09-06 09:43:52 +0000308}
309
Alice Wange910b902023-09-07 10:35:12 +0000310fn vm_instance(vm_type: VmType) -> Result<VmInstance> {
Alice Wanga6357692023-09-07 14:59:37 +0000311 match vm_type {
Alice Wang1d9a5872023-09-06 14:32:36 +0000312 VmType::ProtectedVm => {
Alice Wanga6357692023-09-07 14:59:37 +0000313 service_vm_manager::protected_vm_instance(PathBuf::from(INSTANCE_IMG_PATH))
Alice Wang1d9a5872023-09-06 14:32:36 +0000314 }
Alice Wanga6357692023-09-07 14:59:37 +0000315 VmType::NonProtectedVm => nonprotected_vm_instance(),
316 }
317}
318
319fn nonprotected_vm_instance() -> Result<VmInstance> {
320 let rialto = File::open(UNSIGNED_RIALTO_PATH).context("Failed to open Rialto kernel binary")?;
David Brazdil66fc1202022-07-04 21:48:45 +0100321 let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
Alice Wanga6357692023-09-07 14:59:37 +0000322 name: String::from("Non protected rialto"),
David Brazdil66fc1202022-07-04 21:48:45 +0100323 bootloader: Some(ParcelFileDescriptor::new(rialto)),
Alice Wanga6357692023-09-07 14:59:37 +0000324 protectedVm: false,
David Brazdil66fc1202022-07-04 21:48:45 +0100325 memoryMib: 300,
David Brazdil66fc1202022-07-04 21:48:45 +0100326 platformVersion: "~1.0".to_string(),
Inseob Kim6ef80972023-07-20 17:23:36 +0900327 ..Default::default()
David Brazdil66fc1202022-07-04 21:48:45 +0100328 });
Alice Wanga6357692023-09-07 14:59:37 +0000329 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(service.as_ref(), &config, console, /* consoleIn */ None, log, None)
335 .context("Failed to create VM")
David Brazdil66fc1202022-07-04 21:48:45 +0100336}