1use std::time::Duration;
8
9use base::error;
10use protobuf::Message;
11use remain::sorted;
12use system_api::client::OrgChromiumVtpm;
13use system_api::vtpm_interface::SendCommandRequest;
14use system_api::vtpm_interface::SendCommandResponse;
15use thiserror::Error;
16
17use super::virtio::TpmBackend;
18
19const VTPM_DBUS_TIMEOUT: Duration = Duration::from_secs(300);
21
22const TPM_RC_INSUFFICIENT_RESPONSE: &[u8] = &[
24 0x80, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x9A, ];
28
29const TPM_RC_FAILURE_RESPONSE: &[u8] = &[
31 0x80, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x01, ];
35
36pub struct VtpmProxy {
38 dbus_connection: Option<dbus::blocking::Connection>,
39 buf: Vec<u8>,
40}
41
42impl VtpmProxy {
43 pub fn new() -> Self {
45 VtpmProxy {
46 dbus_connection: None,
47 buf: Vec::new(),
48 }
49 }
50
51 fn get_or_create_dbus_connection(
52 &mut self,
53 ) -> anyhow::Result<&dbus::blocking::Connection, dbus::Error> {
54 match self.dbus_connection {
55 Some(ref dbus_connection) => Ok(dbus_connection),
56 None => {
57 let dbus_connection = dbus::blocking::Connection::new_system()?;
58 self.dbus_connection = Some(dbus_connection);
59 self.get_or_create_dbus_connection()
60 }
61 }
62 }
63
64 fn try_execute_command(&mut self, command: &[u8]) -> anyhow::Result<(), Error> {
65 let dbus_connection = self
66 .get_or_create_dbus_connection()
67 .map_err(Error::DBusError)?;
68
69 let proxy = dbus_connection.with_proxy(
70 "org.chromium.Vtpm",
71 "/org/chromium/Vtpm",
72 VTPM_DBUS_TIMEOUT,
73 );
74
75 let mut proto = SendCommandRequest::new();
76 proto.set_command(command.to_vec());
77
78 let bytes = proto.write_to_bytes().map_err(Error::ProtobufError)?;
79
80 let resp_bytes = proxy.send_command(bytes).map_err(Error::DBusError)?;
81
82 let response =
83 SendCommandResponse::parse_from_bytes(&resp_bytes).map_err(Error::ProtobufError)?;
84
85 self.buf = response.response().to_vec();
86
87 Ok(())
88 }
89}
90
91impl Default for VtpmProxy {
92 fn default() -> Self {
93 Self::new()
94 }
95}
96
97impl TpmBackend for VtpmProxy {
98 fn execute_command<'a>(&'a mut self, command: &[u8]) -> &'a [u8] {
99 match self.try_execute_command(command) {
100 Ok(()) => &self.buf,
101 Err(e) => {
102 error!("{:#}", e);
103 match e {
104 Error::ProtobufError(_) => TPM_RC_INSUFFICIENT_RESPONSE,
105 Error::DBusError(_) => TPM_RC_FAILURE_RESPONSE,
106 }
107 }
108 }
109 }
110}
111
112#[sorted]
113#[derive(Error, Debug)]
114enum Error {
115 #[error("D-Bus failure: {0:#}")]
116 DBusError(dbus::Error),
117 #[error("protocol buffers failure: {0:#}")]
118 ProtobufError(protobuf::Error),
119}