mirror of
https://github.com/edera-dev/sprout.git
synced 2025-12-19 15:40:16 +00:00
feat(tpm): initial tpm support code, we just tell systemd about the pcr banks right now
This commit is contained in:
@@ -148,4 +148,16 @@ impl BootloaderInterface {
|
|||||||
VariableClass::BootAndRuntimeTemporary,
|
VariableClass::BootAndRuntimeTemporary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tell the system what the number of active PCR banks is.
|
||||||
|
/// If this is zero, that is okay.
|
||||||
|
pub fn set_tpm2_active_pcr_banks(value: u32) -> Result<()> {
|
||||||
|
// Format the value into the specification format.
|
||||||
|
let value = format!("0x{:08x}", value);
|
||||||
|
Self::VENDOR.set_cstr16(
|
||||||
|
"LoaderTpm2ActivePcrBanks",
|
||||||
|
&value,
|
||||||
|
VariableClass::BootAndRuntimeTemporary,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use crate::options::SproutOptions;
|
|||||||
use crate::options::parser::OptionsRepresentable;
|
use crate::options::parser::OptionsRepresentable;
|
||||||
use crate::phases::phase;
|
use crate::phases::phase;
|
||||||
use crate::platform::timer::PlatformTimer;
|
use crate::platform::timer::PlatformTimer;
|
||||||
|
use crate::platform::tpm::PlatformTpm;
|
||||||
use crate::secure::SecureBoot;
|
use crate::secure::SecureBoot;
|
||||||
use crate::utils::PartitionGuidForm;
|
use crate::utils::PartitionGuidForm;
|
||||||
use anyhow::{Context, Result, bail};
|
use anyhow::{Context, Result, bail};
|
||||||
@@ -92,6 +93,13 @@ fn run() -> Result<()> {
|
|||||||
BootloaderInterface::set_loader_info()
|
BootloaderInterface::set_loader_info()
|
||||||
.context("unable to set loader info in bootloader interface")?;
|
.context("unable to set loader info in bootloader interface")?;
|
||||||
|
|
||||||
|
// Acquire the number of active PCR banks on the TPM.
|
||||||
|
// If no TPM is available, this will return zero.
|
||||||
|
let active_pcr_banks = PlatformTpm::active_pcr_banks()?;
|
||||||
|
// Tell the bootloader interface what the number of active PCR banks is.
|
||||||
|
BootloaderInterface::set_tpm2_active_pcr_banks(active_pcr_banks)
|
||||||
|
.context("unable to set tpm2 active PCR banks in bootloader interface")?;
|
||||||
|
|
||||||
// Parse the options to the sprout executable.
|
// Parse the options to the sprout executable.
|
||||||
let options = SproutOptions::parse().context("unable to parse options")?;
|
let options = SproutOptions::parse().context("unable to parse options")?;
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
/// timer: Platform timer support.
|
/// timer: Platform timer support.
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
/// tpm: Platform TPM support.
|
||||||
|
pub mod tpm;
|
||||||
|
|||||||
96
src/platform/tpm.rs
Normal file
96
src/platform/tpm.rs
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
use crate::utils;
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
use uefi::boot::ScopedProtocol;
|
||||||
|
use uefi::proto::tcg::v2::Tcg;
|
||||||
|
use uefi_raw::protocol::tcg::v2::{Tcg2Protocol, Tcg2Version};
|
||||||
|
|
||||||
|
/// Represents the platform TPM.
|
||||||
|
pub struct PlatformTpm;
|
||||||
|
|
||||||
|
/// Represents an open TPM handle.
|
||||||
|
pub struct TpmProtocolHandle {
|
||||||
|
/// The version of the TPM protocol.
|
||||||
|
version: Tcg2Version,
|
||||||
|
/// The protocol itself.
|
||||||
|
protocol: ScopedProtocol<Tcg>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TpmProtocolHandle {
|
||||||
|
/// Construct a new [TpmProtocolHandle] from the `version` and `protocol`.
|
||||||
|
pub fn new(version: Tcg2Version, protocol: ScopedProtocol<Tcg>) -> Self {
|
||||||
|
Self { version, protocol }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the version provided by the tcg2 protocol.
|
||||||
|
pub fn version(&self) -> Tcg2Version {
|
||||||
|
self.version
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the protocol interface for tcg2.
|
||||||
|
pub fn protocol(&mut self) -> &mut ScopedProtocol<Tcg> {
|
||||||
|
&mut self.protocol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlatformTpm {
|
||||||
|
/// Acquire access to the TPM protocol handle, if possible.
|
||||||
|
/// Returns None if TPM is not available.
|
||||||
|
fn protocol() -> Result<Option<TpmProtocolHandle>> {
|
||||||
|
// Attempt to acquire the TCG2 protocol handle. If it's not available, return None.
|
||||||
|
let Some(handle) =
|
||||||
|
utils::find_handle(&Tcg2Protocol::GUID).context("unable to determine tpm presence")?
|
||||||
|
else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
// If we reach here, we've already validated that the handle
|
||||||
|
// implements the TCG2 protocol.
|
||||||
|
let mut protocol = uefi::boot::open_protocol_exclusive::<Tcg>(handle)
|
||||||
|
.context("unable to open tcg2 protocol")?;
|
||||||
|
|
||||||
|
// Acquire the capabilities of the TPM.
|
||||||
|
let capability = protocol
|
||||||
|
.get_capability()
|
||||||
|
.context("unable to get tcg2 boot service capability")?;
|
||||||
|
|
||||||
|
// If the TPM is not present, return None.
|
||||||
|
if !capability.tpm_present() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the TPM is present, we need to determine the version of the TPM.
|
||||||
|
let version = capability.protocol_version;
|
||||||
|
|
||||||
|
// We have a TPM, so return the protocol version and the protocol handle.
|
||||||
|
Ok(Some(TpmProtocolHandle::new(version, protocol)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines whether the platform TPM is present.
|
||||||
|
pub fn present() -> Result<bool> {
|
||||||
|
Ok(PlatformTpm::protocol()?.is_some())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determine the number of active PCR banks on the TPM.
|
||||||
|
/// If no TPM is available, this will return zero.
|
||||||
|
pub fn active_pcr_banks() -> Result<u32> {
|
||||||
|
// Acquire access to the TPM protocol handle.
|
||||||
|
let Some(mut handle) = PlatformTpm::protocol()? else {
|
||||||
|
return Ok(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if the TPM supports `GetActivePcrBanks`, and if it doesn't return zero.
|
||||||
|
if handle.version().major < 1 || handle.version().major == 1 && handle.version().minor < 1 {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The safe wrapper for this function will decode the bitmap.
|
||||||
|
// Strictly speaking, it's not future-proof to re-encode that, but in practice it will work.
|
||||||
|
let banks = handle
|
||||||
|
.protocol()
|
||||||
|
.get_active_pcr_banks()
|
||||||
|
.context("unable to get active pcr banks")?;
|
||||||
|
|
||||||
|
// Return the number of active PCR banks.
|
||||||
|
Ok(banks.bits())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user