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