1 // Copyright 2024, 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 //! Main executable of VM attestation for end-to-end testing.
16
17 use anyhow::Result;
18 use avflog::LogResult;
19 use com_android_virt_vm_attestation_testservice::{
20 aidl::com::android::virt::vm_attestation::testservice::IAttestationService::{
21 AttestationStatus::AttestationStatus, BnAttestationService, IAttestationService,
22 SigningResult::SigningResult, PORT,
23 },
24 binder::{self, BinderFeatures, Interface, IntoBinderResult, Strong},
25 };
26 use log::{error, info};
27 use std::{
28 panic,
29 sync::{Arc, Mutex},
30 };
31 use vm_payload::{AttestationError, AttestationResult};
32
33 vm_payload::main!(main);
34
35 // Entry point of the Service VM client.
main()36 fn main() {
37 android_logger::init_once(
38 android_logger::Config::default()
39 .with_tag("service_vm_client")
40 .with_max_level(log::LevelFilter::Debug),
41 );
42 // Redirect panic messages to logcat.
43 panic::set_hook(Box::new(|panic_info| {
44 error!("{}", panic_info);
45 }));
46 if let Err(e) = try_main() {
47 error!("failed with {:?}", e);
48 std::process::exit(1);
49 }
50 }
51
try_main() -> Result<()>52 fn try_main() -> Result<()> {
53 info!("Welcome to Service VM Client!");
54
55 vm_payload::run_single_vsock_service(AttestationService::new_binder(), PORT.try_into()?)
56 }
57
58 struct AttestationService {
59 res: Arc<Mutex<Option<AttestationResult>>>,
60 }
61
62 impl Interface for AttestationService {}
63
64 impl AttestationService {
new_binder() -> Strong<dyn IAttestationService>65 fn new_binder() -> Strong<dyn IAttestationService> {
66 let res = Arc::new(Mutex::new(None));
67 BnAttestationService::new_binder(AttestationService { res }, BinderFeatures::default())
68 }
69 }
70
71 #[allow(non_snake_case)]
72 impl IAttestationService for AttestationService {
requestAttestationForTesting(&self) -> binder::Result<()>73 fn requestAttestationForTesting(&self) -> binder::Result<()> {
74 const CHALLENGE: &[u8] = &[0xaa; 32];
75 let res = vm_payload::restricted::request_attestation_for_testing(CHALLENGE)
76 .with_log()
77 .or_service_specific_exception(-1)?;
78 *self.res.lock().unwrap() = Some(res);
79 Ok(())
80 }
81
signWithAttestationKey( &self, challenge: &[u8], message: &[u8], ) -> binder::Result<SigningResult>82 fn signWithAttestationKey(
83 &self,
84 challenge: &[u8],
85 message: &[u8],
86 ) -> binder::Result<SigningResult> {
87 let res: AttestationResult = match vm_payload::request_attestation(challenge) {
88 Ok(res) => res,
89 Err(e) => {
90 let status = to_attestation_status(e);
91 return Ok(SigningResult { certificateChain: vec![], signature: vec![], status });
92 }
93 };
94
95 let certificate_chain: Vec<u8> = res.certificate_chain().flatten().collect();
96 let status = AttestationStatus::OK;
97 let signature = res.sign_message(message);
98
99 Ok(SigningResult { certificateChain: certificate_chain, signature, status })
100 }
101
validateAttestationResult(&self) -> binder::Result<()>102 fn validateAttestationResult(&self) -> binder::Result<()> {
103 // TODO(b/191073073): Returns the attestation result to the host for validation.
104 log(self.res.lock().unwrap().as_ref().unwrap());
105 Ok(())
106 }
107 }
108
log(res: &AttestationResult)109 fn log(res: &AttestationResult) {
110 for (i, cert) in res.certificate_chain().enumerate() {
111 info!("Attestation result certificate {i} = {cert:?}");
112 }
113
114 let private_key = res.private_key();
115 info!("Attestation result privateKey = {private_key:?}");
116
117 let message = b"Hello from Service VM client";
118 info!("Signing message: {message:?}");
119 let signature = res.sign_message(message);
120 info!("Signature: {signature:?}");
121 }
122
to_attestation_status(e: AttestationError) -> AttestationStatus123 fn to_attestation_status(e: AttestationError) -> AttestationStatus {
124 match e {
125 AttestationError::InvalidChallenge => AttestationStatus::ERROR_INVALID_CHALLENGE,
126 AttestationError::AttestationFailed => AttestationStatus::ERROR_ATTESTATION_FAILED,
127 AttestationError::AttestationUnsupported => AttestationStatus::ERROR_UNSUPPORTED,
128 }
129 }
130