From 35e23d6d4184baed379047f89bbe5a8846c94226 Mon Sep 17 00:00:00 2001 From: Jesper Brynolf Date: Sat, 3 Feb 2024 22:24:01 +0100 Subject: [PATCH] Adds proper native types for TPMS_CONTEXT. - Adds TPM context data structures. - Moves TpmsContext into structures and renames it to SavedTpmContext. Signed-off-by: Jesper Brynolf --- tss-esapi/src/abstraction/transient/mod.rs | 7 +- .../tpm_commands/context_management.rs | 19 ++-- tss-esapi/src/interface_types/data_handles.rs | 12 ++ tss-esapi/src/structures/buffers.rs | 9 ++ tss-esapi/src/structures/mod.rs | 7 +- tss-esapi/src/structures/tagged/public.rs | 2 +- tss-esapi/src/structures/tpm_context.rs | 104 ++++++++++++++++++ tss-esapi/src/utils/mod.rs | 70 +----------- tss-esapi/tests/Dockerfile-ubuntu | 14 ++- 9 files changed, 157 insertions(+), 87 deletions(-) create mode 100644 tss-esapi/src/structures/tpm_context.rs diff --git a/tss-esapi/src/abstraction/transient/mod.rs b/tss-esapi/src/abstraction/transient/mod.rs index a08c0a59..3c27a3ef 100644 --- a/tss-esapi/src/abstraction/transient/mod.rs +++ b/tss-esapi/src/abstraction/transient/mod.rs @@ -20,10 +20,11 @@ use crate::{ structures::{ Auth, CreateKeyResult, Data, Digest, EccPoint, EccScheme, Public, PublicBuilder, PublicEccParametersBuilder, PublicKeyRsa, PublicRsaParametersBuilder, RsaExponent, - RsaScheme, Signature, SignatureScheme, SymmetricDefinitionObject, VerifiedTicket, + RsaScheme, SavedTpmContext, Signature, SignatureScheme, SymmetricDefinitionObject, + VerifiedTicket, }, tcti_ldr::TctiNameConf, - utils::{create_restricted_decryption_rsa_public, PublicKey, TpmsContext}, + utils::{create_restricted_decryption_rsa_public, PublicKey}, Context, Error, Result, ReturnCode, WrapperErrorKind as ErrorKind, }; @@ -336,7 +337,7 @@ impl TransientKeyContext { /// just a public key. pub fn migrate_key_from_ctx( &mut self, - context: TpmsContext, + context: SavedTpmContext, auth: Option, ) -> Result { self.set_session_attrs()?; diff --git a/tss-esapi/src/context/tpm_commands/context_management.rs b/tss-esapi/src/context/tpm_commands/context_management.rs index b5a601d0..5f2a1658 100644 --- a/tss-esapi/src/context/tpm_commands/context_management.rs +++ b/tss-esapi/src/context/tpm_commands/context_management.rs @@ -4,12 +4,12 @@ use crate::{ context::handle_manager::HandleDropAction, handles::{handle_conversion::TryIntoNotNone, AuthHandle, ObjectHandle, PersistentTpmHandle}, interface_types::{data_handles::Persistent, reserved_handles::Provision}, + structures::SavedTpmContext, tss2_esys::{Esys_ContextLoad, Esys_ContextSave, Esys_EvictControl, Esys_FlushContext}, - utils::TpmsContext, Context, Result, ReturnCode, }; use log::error; -use std::convert::{TryFrom, TryInto}; +use std::convert::TryFrom; use std::ptr::null_mut; impl Context { @@ -18,7 +18,7 @@ impl Context { /// # Errors /// * if conversion from `TPMS_CONTEXT` to `TpmsContext` fails, a `WrongParamSize` error will /// be returned - pub fn context_save(&mut self, handle: ObjectHandle) -> Result { + pub fn context_save(&mut self, handle: ObjectHandle) -> Result { let mut context_ptr = null_mut(); ReturnCode::ensure_success( unsafe { Esys_ContextSave(self.mut_context(), handle.into(), &mut context_ptr) }, @@ -26,7 +26,7 @@ impl Context { error!("Error in saving context: {:#010X}", ret); }, )?; - TpmsContext::try_from(Context::ffi_data_to_owned(context_ptr)) + SavedTpmContext::try_from(Context::ffi_data_to_owned(context_ptr)) } /// Load a previously saved context into the TPM and return the object handle. @@ -34,16 +34,11 @@ impl Context { /// # Errors /// * if conversion from `TpmsContext` to the native `TPMS_CONTEXT` fails, a `WrongParamSize` /// error will be returned - pub fn context_load(&mut self, context: TpmsContext) -> Result { + pub fn context_load(&mut self, context: SavedTpmContext) -> Result { let mut esys_loaded_handle = ObjectHandle::None.into(); + let tpm_context = context.into(); ReturnCode::ensure_success( - unsafe { - Esys_ContextLoad( - self.mut_context(), - &context.try_into()?, - &mut esys_loaded_handle, - ) - }, + unsafe { Esys_ContextLoad(self.mut_context(), &tpm_context, &mut esys_loaded_handle) }, |ret| { error!("Error in loading context: {:#010X}", ret); }, diff --git a/tss-esapi/src/interface_types/data_handles.rs b/tss-esapi/src/interface_types/data_handles.rs index 3f6fc663..4c45170a 100644 --- a/tss-esapi/src/interface_types/data_handles.rs +++ b/tss-esapi/src/interface_types/data_handles.rs @@ -177,3 +177,15 @@ impl TryFrom for Saved { }) } } + +impl From for TPMI_DH_SAVED { + fn from(native: Saved) -> TPMI_DH_SAVED { + match native { + Saved::Hmac(handle) => handle.into(), + Saved::Policy(handle) => handle.into(), + Saved::Transient => TransientTpmHandle::SavedTransient.into(), + Saved::Sequence => TransientTpmHandle::SavedSequence.into(), + Saved::TransientClear => TransientTpmHandle::SavedTransientClear.into(), + } + } +} diff --git a/tss-esapi/src/structures/buffers.rs b/tss-esapi/src/structures/buffers.rs index a67d4471..534f3c3f 100644 --- a/tss-esapi/src/structures/buffers.rs +++ b/tss-esapi/src/structures/buffers.rs @@ -390,3 +390,12 @@ pub mod symmetric_key { pub mod timeout { buffer_type!(Timeout, 8, TPM2B_TIMEOUT); } + +pub mod tpm_context_data { + use crate::tss2_esys::TPMS_CONTEXT_DATA; + buffer_type!( + TpmContextData, + std::mem::size_of::(), + TPM2B_CONTEXT_DATA + ); +} diff --git a/tss-esapi/src/structures/mod.rs b/tss-esapi/src/structures/mod.rs index 2c68b095..734f3bd5 100644 --- a/tss-esapi/src/structures/mod.rs +++ b/tss-esapi/src/structures/mod.rs @@ -41,7 +41,7 @@ pub use self::buffers::{ private_key_rsa::PrivateKeyRsa, private_vendor_specific::PrivateVendorSpecific, public::PublicBuffer, public_key_rsa::PublicKeyRsa, sensitive::SensitiveBuffer, sensitive_create::SensitiveCreateBuffer, sensitive_data::SensitiveData, - symmetric_key::SymmetricKey, timeout::Timeout, + symmetric_key::SymmetricKey, timeout::Timeout, tpm_context_data::TpmContextData, }; ///////////////////////////////////////////////////////// /// The creation section @@ -212,3 +212,8 @@ pub use nv::storage::{NvPublic, NvPublicBuilder}; ///////////////////////////////////////////////////////// mod algorithm; pub use algorithm::symmetric::sensitive_create::SensitiveCreate; +///////////////////////////////////////////////////////// +/// TPM context structures +///////////////////////////////////////////////////////// +mod tpm_context; +pub use tpm_context::SavedTpmContext; diff --git a/tss-esapi/src/structures/tagged/public.rs b/tss-esapi/src/structures/tagged/public.rs index 5f416a88..66e0cc0f 100644 --- a/tss-esapi/src/structures/tagged/public.rs +++ b/tss-esapi/src/structures/tagged/public.rs @@ -495,7 +495,7 @@ impl TryFrom for Public { impl_mu_standard!(Public, TPMT_PUBLIC); impl Serialize for Public { - /// Serialise the [Public] data into it's bytes representation of the TCG + /// Serialize the [Public] data into it's bytes representation of the TCG /// TPMT_PUBLIC structure. fn serialize(&self, serializer: S) -> std::result::Result where diff --git a/tss-esapi/src/structures/tpm_context.rs b/tss-esapi/src/structures/tpm_context.rs new file mode 100644 index 00000000..065813ab --- /dev/null +++ b/tss-esapi/src/structures/tpm_context.rs @@ -0,0 +1,104 @@ +// Copyright 2024 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +use crate::{ + handles::TpmHandle, + interface_types::{data_handles::Saved, reserved_handles::Hierarchy}, + structures::TpmContextData, + traits::impl_mu_standard, + traits::{Marshall, UnMarshall}, + tss2_esys::TPMS_CONTEXT, + Error, Result, +}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::convert::TryFrom; + +/// Structure holding the content of a TPM context. +#[derive(Debug, Clone)] +pub struct SavedTpmContext { + sequence: u64, + saved_handle: Saved, + hierarchy: Hierarchy, + context_blob: TpmContextData, +} + +impl SavedTpmContext { + /// The sequence parameter + /// + /// # Details + /// "The sequence parameter is used to differentiate the contexts and to allow the TPM to create a different + /// encryption key for each context." + pub const fn sequence(&self) -> u64 { + self.sequence + } + + /// The saved handle. + pub const fn saved_handle(&self) -> Saved { + self.saved_handle + } + + /// The hierarchy for the saved context. + pub const fn hierarchy(&self) -> Hierarchy { + self.hierarchy + } + + /// The context blob. + /// + /// # Details + /// "This is the hierarchy ([Hierarchy]) for the saved context and determines the proof value used + /// in the construction of the encryption and integrity values for the context. For session and sequence + /// contexts, the hierarchy is [Hierarchy::Null]. The hierarchy for a transient object may be [Hierarchy::Null] + /// but it is not required." + pub fn context_blob(&self) -> &TpmContextData { + &self.context_blob + } +} + +impl TryFrom for SavedTpmContext { + type Error = Error; + + fn try_from(tss: TPMS_CONTEXT) -> Result { + Ok(SavedTpmContext { + sequence: tss.sequence, + saved_handle: Saved::try_from(tss.savedHandle)?, + hierarchy: TpmHandle::try_from(tss.hierarchy).and_then(Hierarchy::try_from)?, + context_blob: TpmContextData::try_from(tss.contextBlob)?, + }) + } +} + +impl From for TPMS_CONTEXT { + fn from(native: SavedTpmContext) -> TPMS_CONTEXT { + TPMS_CONTEXT { + sequence: native.sequence, + savedHandle: native.saved_handle.into(), + hierarchy: TpmHandle::from(native.hierarchy).into(), + contextBlob: native.context_blob.into(), + } + } +} + +impl_mu_standard!(SavedTpmContext, TPMS_CONTEXT); + +impl Serialize for SavedTpmContext { + /// Serialize the [SavedTpmContext] data into it's bytes representation of the TCG + /// TPMT_PUBLIC structure. + fn serialize(&self, serializer: S) -> std::result::Result + where + S: Serializer, + { + let bytes = self.marshall().map_err(serde::ser::Error::custom)?; + serializer.serialize_bytes(&bytes) + } +} + +impl<'de> Deserialize<'de> for SavedTpmContext { + /// Deserialize the [Public] data from it's bytes representation of the TCG + /// TPMT_PUBLIC structure. + fn deserialize(deserializer: D) -> std::result::Result + where + D: Deserializer<'de>, + { + let bytes = >::deserialize(deserializer)?; + Self::unmarshall(&bytes).map_err(serde::de::Error::custom) + } +} diff --git a/tss-esapi/src/utils/mod.rs b/tss-esapi/src/utils/mod.rs index 5d9eff24..17103111 100644 --- a/tss-esapi/src/utils/mod.rs +++ b/tss-esapi/src/utils/mod.rs @@ -19,76 +19,10 @@ use crate::structures::{ EccPoint, EccScheme, Public, PublicBuilder, PublicEccParametersBuilder, PublicKeyRsa, PublicRsaParametersBuilder, RsaExponent, RsaScheme, SymmetricDefinitionObject, }; -use crate::tss2_esys::*; use crate::{Context, Error, Result, WrapperErrorKind}; use serde::{Deserialize, Serialize}; -use std::convert::{TryFrom, TryInto}; -use zeroize::{Zeroize, ZeroizeOnDrop}; - -/// Rust native wrapper for `TPMS_CONTEXT` objects. -/// -/// This structure is intended to help with persisting object contexts. As the main reason for -/// saving the context of an object is to be able to reuse it later, on demand, a serializable -/// structure is most commonly needed. `TpmsContext` implements the `Serialize` and `Deserialize` -/// defined by `serde`. -#[derive(Debug, Serialize, Deserialize, Clone, Zeroize, ZeroizeOnDrop)] -pub struct TpmsContext { - sequence: u64, - saved_handle: TPMI_DH_CONTEXT, - hierarchy: TPMI_RH_HIERARCHY, - context_blob: Vec, -} - -impl TpmsContext { - /// Get a reference to the `context_blob` field - pub fn context_blob(&self) -> &Vec { - &self.context_blob - } -} - -// TODO: Replace with `From` -impl TryFrom for TpmsContext { - type Error = Error; - - fn try_from(tss2_context: TPMS_CONTEXT) -> Result { - let mut context = TpmsContext { - sequence: tss2_context.sequence, - saved_handle: tss2_context.savedHandle, - hierarchy: tss2_context.hierarchy, - context_blob: tss2_context.contextBlob.buffer.to_vec(), - }; - context - .context_blob - .truncate(tss2_context.contextBlob.size.into()); - Ok(context) - } -} - -#[allow(clippy::needless_update)] -impl TryFrom for TPMS_CONTEXT { - type Error = Error; - - fn try_from(context: TpmsContext) -> Result { - let buffer_size = context.context_blob.len(); - if buffer_size > 5188 { - return Err(Error::local_error(WrapperErrorKind::WrongParamSize)); - } - let mut buffer = [0_u8; 5188]; - for (i, val) in context.context_blob.iter().enumerate() { - buffer[i] = *val; - } - Ok(TPMS_CONTEXT { - sequence: context.sequence, - savedHandle: context.saved_handle, - hierarchy: context.hierarchy, - contextBlob: TPM2B_CONTEXT_DATA { - size: buffer_size.try_into().unwrap(), // should not panic given the check above - buffer, - }, - ..Default::default() - }) - } -} +use std::convert::TryFrom; +use zeroize::Zeroize; /// Create the [Public] structure for a restricted decryption key. /// diff --git a/tss-esapi/tests/Dockerfile-ubuntu b/tss-esapi/tests/Dockerfile-ubuntu index 945f9237..9e19ff11 100644 --- a/tss-esapi/tests/Dockerfile-ubuntu +++ b/tss-esapi/tests/Dockerfile-ubuntu @@ -6,7 +6,7 @@ RUN curl https://sh.rustup.rs -sSf | bash -s -- -y ENV PATH="/root/.cargo/bin:${PATH}" FROM rust-toolchain AS tpm2-tss -# Download and install the TSS library +# Download, build and install the TSS libraries ARG TPM2_TSS_VERSION=3.2.2 ENV TPM2_TSS_VERSION=$TPM2_TSS_VERSION ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig @@ -18,10 +18,20 @@ RUN cd tpm2-tss \ && make install \ && ldconfig -FROM tpm2-tss AS tpm2-tools +FROM tpm2-tss AS tpm2-abrmd +# Download, build and install the TPM2 abrmd +RUN git clone https://github.com/tpm2-software/tpm2-abrmd.git --branch 3.0.0 +RUN cd tpm2-abrmd \ + && ./bootstrap \ + && ./configure \ + && make -j$(nproc) \ + && make install + +FROM tpm2-abrmd AS tpm2-tools # Download and install TPM2 tools RUN git clone https://github.com/tpm2-software/tpm2-tools.git --branch 5.6 RUN cd tpm2-tools \ && ./bootstrap \ && ./configure --enable-unit \ + && make -j$(nproc) \ && make install