use std::time::Duration;
use base::error;
use protobuf::Message;
use remain::sorted;
use system_api::client::OrgChromiumVtpm;
use system_api::vtpm_interface::SendCommandRequest;
use system_api::vtpm_interface::SendCommandResponse;
use thiserror::Error;
use super::virtio::TpmBackend;
const VTPM_DBUS_TIMEOUT: Duration = Duration::from_secs(300);
const TPM_RC_INSUFFICIENT_RESPONSE: &[u8] = &[
0x80, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x9A, ];
const TPM_RC_FAILURE_RESPONSE: &[u8] = &[
0x80, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x01, ];
pub struct VtpmProxy {
dbus_connection: Option<dbus::blocking::Connection>,
buf: Vec<u8>,
}
impl VtpmProxy {
pub fn new() -> Self {
VtpmProxy {
dbus_connection: None,
buf: Vec::new(),
}
}
fn get_or_create_dbus_connection(
&mut self,
) -> anyhow::Result<&dbus::blocking::Connection, dbus::Error> {
return match self.dbus_connection {
Some(ref dbus_connection) => Ok(dbus_connection),
None => {
let dbus_connection = dbus::blocking::Connection::new_system()?;
self.dbus_connection = Some(dbus_connection);
return self.get_or_create_dbus_connection();
}
};
}
fn try_execute_command(&mut self, command: &[u8]) -> anyhow::Result<(), Error> {
let dbus_connection = self
.get_or_create_dbus_connection()
.map_err(Error::DBusError)?;
let proxy = dbus_connection.with_proxy(
"org.chromium.Vtpm",
"/org/chromium/Vtpm",
VTPM_DBUS_TIMEOUT,
);
let mut proto = SendCommandRequest::new();
proto.set_command(command.to_vec());
let bytes = proto.write_to_bytes().map_err(Error::ProtobufError)?;
let resp_bytes = proxy.send_command(bytes).map_err(Error::DBusError)?;
let response =
SendCommandResponse::parse_from_bytes(&resp_bytes).map_err(Error::ProtobufError)?;
self.buf = response.response().to_vec();
Ok(())
}
}
impl Default for VtpmProxy {
fn default() -> Self {
Self::new()
}
}
impl TpmBackend for VtpmProxy {
fn execute_command<'a>(&'a mut self, command: &[u8]) -> &'a [u8] {
match self.try_execute_command(command) {
Ok(()) => &self.buf,
Err(e) => {
error!("{:#}", e);
match e {
Error::ProtobufError(_) => TPM_RC_INSUFFICIENT_RESPONSE,
Error::DBusError(_) => TPM_RC_FAILURE_RESPONSE,
}
}
}
}
}
#[sorted]
#[derive(Error, Debug)]
enum Error {
#[error("D-Bus failure: {0:#}")]
DBusError(dbus::Error),
#[error("protocol buffers failure: {0:#}")]
ProtobufError(protobuf::Error),
}