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::{anyhow, ensure, 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, unstable_api::AsNative, BinderFeatures, Interface, IntoBinderResult, Strong},
25 };
26 use log::{error, info};
27 use std::{
28     ffi::{c_void, CStr},
29     panic,
30     ptr::{self, NonNull},
31     result,
32     sync::{Arc, Mutex},
33 };
34 use vm_payload_bindgen::{
35     AIBinder, AVmAttestationResult, AVmAttestationResult_free,
36     AVmAttestationResult_getCertificateAt, AVmAttestationResult_getCertificateCount,
37     AVmAttestationResult_getPrivateKey, AVmAttestationResult_sign, AVmAttestationStatus,
38     AVmAttestationStatus_toString, AVmPayload_notifyPayloadReady, AVmPayload_requestAttestation,
39     AVmPayload_requestAttestationForTesting, AVmPayload_runVsockRpcServer,
40 };
41 
42 /// Entry point of the Service VM client.
43 #[allow(non_snake_case)]
44 #[no_mangle]
AVmPayload_main()45 pub extern "C" fn AVmPayload_main() {
46     android_logger::init_once(
47         android_logger::Config::default()
48             .with_tag("service_vm_client")
49             .with_max_level(log::LevelFilter::Debug),
50     );
51     // Redirect panic messages to logcat.
52     panic::set_hook(Box::new(|panic_info| {
53         error!("{}", panic_info);
54     }));
55     if let Err(e) = try_main() {
56         error!("failed with {:?}", e);
57         std::process::exit(1);
58     }
59 }
60 
try_main() -> Result<()>61 fn try_main() -> Result<()> {
62     info!("Welcome to Service VM Client!");
63 
64     let mut service = AttestationService::new_binder().as_binder();
65     let service = service.as_native_mut() as *mut AIBinder;
66     let param = ptr::null_mut();
67     // SAFETY: We hold a strong pointer, so the raw pointer remains valid. The bindgen AIBinder
68     // is the same type as `sys::AIBinder`. It is safe for `on_ready` to be invoked at any time,
69     // with any parameter.
70     unsafe { AVmPayload_runVsockRpcServer(service, PORT.try_into()?, Some(on_ready), param) };
71 }
72 
on_ready(_param: *mut c_void)73 extern "C" fn on_ready(_param: *mut c_void) {
74     // SAFETY: It is safe to call `AVmPayload_notifyPayloadReady` at any time.
75     unsafe { AVmPayload_notifyPayloadReady() };
76 }
77 
78 struct AttestationService {
79     res: Arc<Mutex<Option<AttestationResult>>>,
80 }
81 
82 impl Interface for AttestationService {}
83 
84 impl AttestationService {
new_binder() -> Strong<dyn IAttestationService>85     fn new_binder() -> Strong<dyn IAttestationService> {
86         let res = Arc::new(Mutex::new(None));
87         BnAttestationService::new_binder(AttestationService { res }, BinderFeatures::default())
88     }
89 }
90 
91 impl IAttestationService for AttestationService {
requestAttestationForTesting(&self) -> binder::Result<()>92     fn requestAttestationForTesting(&self) -> binder::Result<()> {
93         const CHALLENGE: &[u8] = &[0xaa; 32];
94         let res = AttestationResult::request_attestation_for_testing(CHALLENGE)
95             .map_err(|e| anyhow!("Unexpected status: {:?}", status_to_cstr(e)))
96             .with_log()
97             .or_service_specific_exception(-1)?;
98         *self.res.lock().unwrap() = Some(res);
99         Ok(())
100     }
101 
signWithAttestationKey( &self, challenge: &[u8], message: &[u8], ) -> binder::Result<SigningResult>102     fn signWithAttestationKey(
103         &self,
104         challenge: &[u8],
105         message: &[u8],
106     ) -> binder::Result<SigningResult> {
107         let res = match AttestationResult::request_attestation(challenge) {
108             Ok(res) => res,
109             Err(status) => {
110                 let status = to_attestation_status(status);
111                 return Ok(SigningResult { certificateChain: vec![], signature: vec![], status });
112             }
113         };
114         let certificate_chain =
115             res.certificate_chain().with_log().or_service_specific_exception(-1)?;
116         let status = AttestationStatus::OK;
117         let signature = res.sign(message).with_log().or_service_specific_exception(-1)?;
118         Ok(SigningResult { certificateChain: certificate_chain, signature, status })
119     }
120 
validateAttestationResult(&self) -> binder::Result<()>121     fn validateAttestationResult(&self) -> binder::Result<()> {
122         // TODO(b/191073073): Returns the attestation result to the host for validation.
123         self.res.lock().unwrap().as_ref().unwrap().log().or_service_specific_exception(-1)
124     }
125 }
126 
to_attestation_status(status: AVmAttestationStatus) -> AttestationStatus127 fn to_attestation_status(status: AVmAttestationStatus) -> AttestationStatus {
128     match status {
129         AVmAttestationStatus::ATTESTATION_OK => AttestationStatus::OK,
130         AVmAttestationStatus::ATTESTATION_ERROR_INVALID_CHALLENGE => {
131             AttestationStatus::ERROR_INVALID_CHALLENGE
132         }
133         AVmAttestationStatus::ATTESTATION_ERROR_ATTESTATION_FAILED => {
134             AttestationStatus::ERROR_ATTESTATION_FAILED
135         }
136         AVmAttestationStatus::ATTESTATION_ERROR_UNSUPPORTED => AttestationStatus::ERROR_UNSUPPORTED,
137     }
138 }
139 
140 #[derive(Debug)]
141 struct AttestationResult(NonNull<AVmAttestationResult>);
142 
143 // Safety: `AttestationResult` is not `Send` because it contains a raw pointer to a C struct.
144 unsafe impl Send for AttestationResult {}
145 
146 impl AttestationResult {
request_attestation_for_testing( challenge: &[u8], ) -> result::Result<Self, AVmAttestationStatus>147     fn request_attestation_for_testing(
148         challenge: &[u8],
149     ) -> result::Result<Self, AVmAttestationStatus> {
150         let mut res: *mut AVmAttestationResult = ptr::null_mut();
151         // SAFETY: It is safe as we only read the challenge within its bounds and the
152         // function does not retain any reference to it.
153         let status = unsafe {
154             AVmPayload_requestAttestationForTesting(
155                 challenge.as_ptr() as *const c_void,
156                 challenge.len(),
157                 &mut res,
158             )
159         };
160         if status == AVmAttestationStatus::ATTESTATION_OK {
161             info!("Attestation succeeds. Status: {:?}", status_to_cstr(status));
162             let res = NonNull::new(res).expect("The attestation result is null");
163             Ok(Self(res))
164         } else {
165             Err(status)
166         }
167     }
168 
request_attestation(challenge: &[u8]) -> result::Result<Self, AVmAttestationStatus>169     fn request_attestation(challenge: &[u8]) -> result::Result<Self, AVmAttestationStatus> {
170         let mut res: *mut AVmAttestationResult = ptr::null_mut();
171         // SAFETY: It is safe as we only read the challenge within its bounds and the
172         // function does not retain any reference to it.
173         let status = unsafe {
174             AVmPayload_requestAttestation(
175                 challenge.as_ptr() as *const c_void,
176                 challenge.len(),
177                 &mut res,
178             )
179         };
180         if status == AVmAttestationStatus::ATTESTATION_OK {
181             info!("Attestation succeeds. Status: {:?}", status_to_cstr(status));
182             let res = NonNull::new(res).expect("The attestation result is null");
183             Ok(Self(res))
184         } else {
185             Err(status)
186         }
187     }
188 
certificate_chain(&self) -> Result<Vec<u8>>189     fn certificate_chain(&self) -> Result<Vec<u8>> {
190         let num_certs = get_certificate_count(self.as_ref());
191         let mut certs = Vec::new();
192         for i in 0..num_certs {
193             certs.extend(get_certificate_at(self.as_ref(), i)?.iter());
194         }
195         Ok(certs)
196     }
197 
private_key(&self) -> Result<Box<[u8]>>198     fn private_key(&self) -> Result<Box<[u8]>> {
199         get_private_key(self.as_ref())
200     }
201 
sign(&self, message: &[u8]) -> Result<Vec<u8>>202     fn sign(&self, message: &[u8]) -> Result<Vec<u8>> {
203         sign_with_attested_key(self.as_ref(), message)
204     }
205 
log(&self) -> Result<()>206     fn log(&self) -> Result<()> {
207         let cert_chain = self.certificate_chain()?;
208         info!("Attestation result certificateChain = {:?}", cert_chain);
209 
210         let private_key = self.private_key()?;
211         info!("Attestation result privateKey = {:?}", private_key);
212 
213         let message = b"Hello from Service VM client";
214         info!("Signing message: {:?}", message);
215         let signature = self.sign(message)?;
216         info!("Signature: {:?}", signature);
217         Ok(())
218     }
219 }
220 
221 impl AsRef<AVmAttestationResult> for AttestationResult {
as_ref(&self) -> &AVmAttestationResult222     fn as_ref(&self) -> &AVmAttestationResult {
223         // SAFETY: This field is private, and only populated with a successful call to
224         // `AVmPayload_requestAttestation`.
225         unsafe { self.0.as_ref() }
226     }
227 }
228 
229 impl Drop for AttestationResult {
drop(&mut self)230     fn drop(&mut self) {
231         // SAFETY: This field is private, and only populated with a successful call to
232         // `AVmPayload_requestAttestation`, and not freed elsewhere.
233         unsafe { AVmAttestationResult_free(self.0.as_ptr()) };
234     }
235 }
236 
get_certificate_count(res: &AVmAttestationResult) -> usize237 fn get_certificate_count(res: &AVmAttestationResult) -> usize {
238     // SAFETY: The result is returned by `AVmPayload_requestAttestation` and should be valid
239     // before getting freed.
240     unsafe { AVmAttestationResult_getCertificateCount(res) }
241 }
242 
get_certificate_at(res: &AVmAttestationResult, index: usize) -> Result<Box<[u8]>>243 fn get_certificate_at(res: &AVmAttestationResult, index: usize) -> Result<Box<[u8]>> {
244     let size =
245         // SAFETY: The result is returned by `AVmPayload_requestAttestation` and should be valid
246         // before getting freed.
247         unsafe { AVmAttestationResult_getCertificateAt(res, index, ptr::null_mut(), 0) };
248     let mut cert = vec![0u8; size];
249     // SAFETY: The result is returned by `AVmPayload_requestAttestation` and should be valid
250     // before getting freed. This function only writes within the bounds of `cert`.
251     // And `cert` cannot overlap `res` because we just allocated it.
252     let size = unsafe {
253         AVmAttestationResult_getCertificateAt(
254             res,
255             index,
256             cert.as_mut_ptr() as *mut c_void,
257             cert.len(),
258         )
259     };
260     ensure!(size == cert.len());
261     Ok(cert.into_boxed_slice())
262 }
263 
get_private_key(res: &AVmAttestationResult) -> Result<Box<[u8]>>264 fn get_private_key(res: &AVmAttestationResult) -> Result<Box<[u8]>> {
265     let size =
266         // SAFETY: The result is returned by `AVmPayload_requestAttestation` and should be valid
267         // before getting freed.
268         unsafe { AVmAttestationResult_getPrivateKey(res, ptr::null_mut(), 0) };
269     let mut private_key = vec![0u8; size];
270     // SAFETY: The result is returned by `AVmPayload_requestAttestation` and should be valid
271     // before getting freed. This function only writes within the bounds of `private_key`.
272     // And `private_key` cannot overlap `res` because we just allocated it.
273     let size = unsafe {
274         AVmAttestationResult_getPrivateKey(
275             res,
276             private_key.as_mut_ptr() as *mut c_void,
277             private_key.len(),
278         )
279     };
280     ensure!(size == private_key.len());
281     Ok(private_key.into_boxed_slice())
282 }
283 
sign_with_attested_key(res: &AVmAttestationResult, message: &[u8]) -> Result<Vec<u8>>284 fn sign_with_attested_key(res: &AVmAttestationResult, message: &[u8]) -> Result<Vec<u8>> {
285     // SAFETY: The result is returned by `AVmPayload_requestAttestation` and should be valid
286     // before getting freed.
287     let size = unsafe {
288         AVmAttestationResult_sign(
289             res,
290             message.as_ptr() as *const c_void,
291             message.len(),
292             ptr::null_mut(),
293             0,
294         )
295     };
296     let mut signature = vec![0u8; size];
297     // SAFETY: The result is returned by `AVmPayload_requestAttestation` and should be valid
298     // before getting freed. This function only writes within the bounds of `signature`.
299     // And `signature` cannot overlap `res` because we just allocated it.
300     let size = unsafe {
301         AVmAttestationResult_sign(
302             res,
303             message.as_ptr() as *const c_void,
304             message.len(),
305             signature.as_mut_ptr() as *mut c_void,
306             signature.len(),
307         )
308     };
309     ensure!(size <= signature.len());
310     signature.truncate(size);
311     Ok(signature)
312 }
313 
status_to_cstr(status: AVmAttestationStatus) -> &'static CStr314 fn status_to_cstr(status: AVmAttestationStatus) -> &'static CStr {
315     // SAFETY: The function only reads the given enum status and returns a pointer to a
316     // static string.
317     let message = unsafe { AVmAttestationStatus_toString(status) };
318     // SAFETY: The pointer returned by `AVmAttestationStatus_toString` is guaranteed to
319     // point to a valid C String that lives forever.
320     unsafe { CStr::from_ptr(message) }
321 }
322