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