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