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