xref: /aosp_15_r20/external/crosvm/devices/src/vtpm_proxy.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! vTPM Proxy backend using the vtpmd on ChromeOS to virtualize TPM commands.
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
8*bb4ee6a4SAndroid Build Coastguard Worker 
9*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
10*bb4ee6a4SAndroid Build Coastguard Worker use protobuf::Message;
11*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
12*bb4ee6a4SAndroid Build Coastguard Worker use system_api::client::OrgChromiumVtpm;
13*bb4ee6a4SAndroid Build Coastguard Worker use system_api::vtpm_interface::SendCommandRequest;
14*bb4ee6a4SAndroid Build Coastguard Worker use system_api::vtpm_interface::SendCommandResponse;
15*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error;
16*bb4ee6a4SAndroid Build Coastguard Worker 
17*bb4ee6a4SAndroid Build Coastguard Worker use super::virtio::TpmBackend;
18*bb4ee6a4SAndroid Build Coastguard Worker 
19*bb4ee6a4SAndroid Build Coastguard Worker // 5 minutes is the default timeout for tpm commands.
20*bb4ee6a4SAndroid Build Coastguard Worker const VTPM_DBUS_TIMEOUT: Duration = Duration::from_secs(300);
21*bb4ee6a4SAndroid Build Coastguard Worker 
22*bb4ee6a4SAndroid Build Coastguard Worker // The response of TPM_RC_INSUFFICIENT
23*bb4ee6a4SAndroid Build Coastguard Worker const TPM_RC_INSUFFICIENT_RESPONSE: &[u8] = &[
24*bb4ee6a4SAndroid Build Coastguard Worker     0x80, 0x01, // TPM_ST_NO_SESSIONS
25*bb4ee6a4SAndroid Build Coastguard Worker     0x00, 0x00, 0x00, 0x0A, // Header Size = 10
26*bb4ee6a4SAndroid Build Coastguard Worker     0x00, 0x00, 0x00, 0x9A, // TPM_RC_INSUFFICIENT
27*bb4ee6a4SAndroid Build Coastguard Worker ];
28*bb4ee6a4SAndroid Build Coastguard Worker 
29*bb4ee6a4SAndroid Build Coastguard Worker // The response of TPM_RC_FAILURE
30*bb4ee6a4SAndroid Build Coastguard Worker const TPM_RC_FAILURE_RESPONSE: &[u8] = &[
31*bb4ee6a4SAndroid Build Coastguard Worker     0x80, 0x01, // TPM_ST_NO_SESSIONS
32*bb4ee6a4SAndroid Build Coastguard Worker     0x00, 0x00, 0x00, 0x0A, // Header Size = 10
33*bb4ee6a4SAndroid Build Coastguard Worker     0x00, 0x00, 0x01, 0x01, // TPM_RC_FAILURE
34*bb4ee6a4SAndroid Build Coastguard Worker ];
35*bb4ee6a4SAndroid Build Coastguard Worker 
36*bb4ee6a4SAndroid Build Coastguard Worker /// A proxy object that connects to the vtpmd on ChromeOS.
37*bb4ee6a4SAndroid Build Coastguard Worker pub struct VtpmProxy {
38*bb4ee6a4SAndroid Build Coastguard Worker     dbus_connection: Option<dbus::blocking::Connection>,
39*bb4ee6a4SAndroid Build Coastguard Worker     buf: Vec<u8>,
40*bb4ee6a4SAndroid Build Coastguard Worker }
41*bb4ee6a4SAndroid Build Coastguard Worker 
42*bb4ee6a4SAndroid Build Coastguard Worker impl VtpmProxy {
43*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns a proxy that can be connected to the vtpmd.
new() -> Self44*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new() -> Self {
45*bb4ee6a4SAndroid Build Coastguard Worker         VtpmProxy {
46*bb4ee6a4SAndroid Build Coastguard Worker             dbus_connection: None,
47*bb4ee6a4SAndroid Build Coastguard Worker             buf: Vec::new(),
48*bb4ee6a4SAndroid Build Coastguard Worker         }
49*bb4ee6a4SAndroid Build Coastguard Worker     }
50*bb4ee6a4SAndroid Build Coastguard Worker 
get_or_create_dbus_connection( &mut self, ) -> anyhow::Result<&dbus::blocking::Connection, dbus::Error>51*bb4ee6a4SAndroid Build Coastguard Worker     fn get_or_create_dbus_connection(
52*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
53*bb4ee6a4SAndroid Build Coastguard Worker     ) -> anyhow::Result<&dbus::blocking::Connection, dbus::Error> {
54*bb4ee6a4SAndroid Build Coastguard Worker         return match self.dbus_connection {
55*bb4ee6a4SAndroid Build Coastguard Worker             Some(ref dbus_connection) => Ok(dbus_connection),
56*bb4ee6a4SAndroid Build Coastguard Worker             None => {
57*bb4ee6a4SAndroid Build Coastguard Worker                 let dbus_connection = dbus::blocking::Connection::new_system()?;
58*bb4ee6a4SAndroid Build Coastguard Worker                 self.dbus_connection = Some(dbus_connection);
59*bb4ee6a4SAndroid Build Coastguard Worker                 return self.get_or_create_dbus_connection();
60*bb4ee6a4SAndroid Build Coastguard Worker             }
61*bb4ee6a4SAndroid Build Coastguard Worker         };
62*bb4ee6a4SAndroid Build Coastguard Worker     }
63*bb4ee6a4SAndroid Build Coastguard Worker 
try_execute_command(&mut self, command: &[u8]) -> anyhow::Result<(), Error>64*bb4ee6a4SAndroid Build Coastguard Worker     fn try_execute_command(&mut self, command: &[u8]) -> anyhow::Result<(), Error> {
65*bb4ee6a4SAndroid Build Coastguard Worker         let dbus_connection = self
66*bb4ee6a4SAndroid Build Coastguard Worker             .get_or_create_dbus_connection()
67*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::DBusError)?;
68*bb4ee6a4SAndroid Build Coastguard Worker 
69*bb4ee6a4SAndroid Build Coastguard Worker         let proxy = dbus_connection.with_proxy(
70*bb4ee6a4SAndroid Build Coastguard Worker             "org.chromium.Vtpm",
71*bb4ee6a4SAndroid Build Coastguard Worker             "/org/chromium/Vtpm",
72*bb4ee6a4SAndroid Build Coastguard Worker             VTPM_DBUS_TIMEOUT,
73*bb4ee6a4SAndroid Build Coastguard Worker         );
74*bb4ee6a4SAndroid Build Coastguard Worker 
75*bb4ee6a4SAndroid Build Coastguard Worker         let mut proto = SendCommandRequest::new();
76*bb4ee6a4SAndroid Build Coastguard Worker         proto.set_command(command.to_vec());
77*bb4ee6a4SAndroid Build Coastguard Worker 
78*bb4ee6a4SAndroid Build Coastguard Worker         let bytes = proto.write_to_bytes().map_err(Error::ProtobufError)?;
79*bb4ee6a4SAndroid Build Coastguard Worker 
80*bb4ee6a4SAndroid Build Coastguard Worker         let resp_bytes = proxy.send_command(bytes).map_err(Error::DBusError)?;
81*bb4ee6a4SAndroid Build Coastguard Worker 
82*bb4ee6a4SAndroid Build Coastguard Worker         let response =
83*bb4ee6a4SAndroid Build Coastguard Worker             SendCommandResponse::parse_from_bytes(&resp_bytes).map_err(Error::ProtobufError)?;
84*bb4ee6a4SAndroid Build Coastguard Worker 
85*bb4ee6a4SAndroid Build Coastguard Worker         self.buf = response.response().to_vec();
86*bb4ee6a4SAndroid Build Coastguard Worker 
87*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
88*bb4ee6a4SAndroid Build Coastguard Worker     }
89*bb4ee6a4SAndroid Build Coastguard Worker }
90*bb4ee6a4SAndroid Build Coastguard Worker 
91*bb4ee6a4SAndroid Build Coastguard Worker impl Default for VtpmProxy {
default() -> Self92*bb4ee6a4SAndroid Build Coastguard Worker     fn default() -> Self {
93*bb4ee6a4SAndroid Build Coastguard Worker         Self::new()
94*bb4ee6a4SAndroid Build Coastguard Worker     }
95*bb4ee6a4SAndroid Build Coastguard Worker }
96*bb4ee6a4SAndroid Build Coastguard Worker 
97*bb4ee6a4SAndroid Build Coastguard Worker impl TpmBackend for VtpmProxy {
execute_command<'a>(&'a mut self, command: &[u8]) -> &'a [u8]98*bb4ee6a4SAndroid Build Coastguard Worker     fn execute_command<'a>(&'a mut self, command: &[u8]) -> &'a [u8] {
99*bb4ee6a4SAndroid Build Coastguard Worker         match self.try_execute_command(command) {
100*bb4ee6a4SAndroid Build Coastguard Worker             Ok(()) => &self.buf,
101*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
102*bb4ee6a4SAndroid Build Coastguard Worker                 error!("{:#}", e);
103*bb4ee6a4SAndroid Build Coastguard Worker                 match e {
104*bb4ee6a4SAndroid Build Coastguard Worker                     Error::ProtobufError(_) => TPM_RC_INSUFFICIENT_RESPONSE,
105*bb4ee6a4SAndroid Build Coastguard Worker                     Error::DBusError(_) => TPM_RC_FAILURE_RESPONSE,
106*bb4ee6a4SAndroid Build Coastguard Worker                 }
107*bb4ee6a4SAndroid Build Coastguard Worker             }
108*bb4ee6a4SAndroid Build Coastguard Worker         }
109*bb4ee6a4SAndroid Build Coastguard Worker     }
110*bb4ee6a4SAndroid Build Coastguard Worker }
111*bb4ee6a4SAndroid Build Coastguard Worker 
112*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
113*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)]
114*bb4ee6a4SAndroid Build Coastguard Worker enum Error {
115*bb4ee6a4SAndroid Build Coastguard Worker     #[error("D-Bus failure: {0:#}")]
116*bb4ee6a4SAndroid Build Coastguard Worker     DBusError(dbus::Error),
117*bb4ee6a4SAndroid Build Coastguard Worker     #[error("protocol buffers failure: {0:#}")]
118*bb4ee6a4SAndroid Build Coastguard Worker     ProtobufError(protobuf::Error),
119*bb4ee6a4SAndroid Build Coastguard Worker }
120