Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 111 additions & 2 deletions tss-esapi/src/context/tpm_commands/non_volatile_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
interface_types::reserved_handles::{NvAuth, Provision},
structures::{Auth, MaxNvBuffer, Name, NvPublic},
tss2_esys::{
Esys_NV_DefineSpace, Esys_NV_Increment, Esys_NV_Read, Esys_NV_ReadPublic,
Esys_NV_DefineSpace, Esys_NV_Extend, Esys_NV_Increment, Esys_NV_Read, Esys_NV_ReadPublic,
Esys_NV_UndefineSpace, Esys_NV_UndefineSpaceSpecial, Esys_NV_Write,
},
Context, Result, ReturnCode,
Expand Down Expand Up @@ -698,7 +698,116 @@ impl Context {
)
}

// Missing function: NV_Extend
/// Extends data to the NV memory associated with a nv index.
///
/// # Details
/// This method is used to extend a value to the nv memory in the TPM.
///
/// Please beware that this method requires an authorization session handle to be present.
///
/// Any NV index (that is not already used) can be defined as an extend type. However various specifications define
/// indexes that have specific purposes or are reserved, for example the TCG PC Client Platform Firmware Profile
/// Specification Section 3.3.6 defines indexes within the 0x01c40200-0x01c402ff range for instance measurements.
/// Section 2.2 of TCG Registry of Reserved TPM 2.0 Handles and Localities provides additional context for specific
/// NV index ranges.
///
/// # Arguments
/// * `auth_handle` - Handle indicating the source of authorization value.
/// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
/// which will be extended by data hashed with the previous data.
/// * `data` - The data, in the form of a [MaxNvBuffer], that is to be written.
///
/// # Example
/// ```rust
/// # use tss_esapi::{
/// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
/// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
/// # structures::{SymmetricDefinition, NvPublic},
/// # constants::SessionType, constants::nv_index_type::NvIndexType,
/// # };
/// use tss_esapi::{
/// interface_types::reserved_handles::{Provision, NvAuth}, structures::MaxNvBuffer,
/// };
///
/// # // Create context
/// # let mut context =
/// # Context::new(
/// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
/// # ).expect("Failed to create Context");
/// #
/// # let session = context
/// # .start_auth_session(
/// # None,
/// # None,
/// # None,
/// # SessionType::Hmac,
/// # SymmetricDefinition::AES_256_CFB,
/// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
/// # )
/// # .expect("Failed to create session")
/// # .expect("Received invalid handle");
/// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
/// # .with_decrypt(true)
/// # .with_encrypt(true)
/// # .build();
/// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
/// # .expect("Failed to set attributes on session");
/// # context.set_sessions((Some(session), None, None));
/// #
/// # let nv_index = NvIndexTpmHandle::new(0x01500028)
/// # .expect("Failed to create NV index tpm handle");
/// #
/// // Create NV index attributes
/// let owner_nv_index_attributes = NvIndexAttributes::builder()
/// .with_owner_write(true)
/// .with_owner_read(true)
/// .with_orderly(true)
/// .with_nv_index_type(NvIndexType::Extend)
/// .build()
/// .expect("Failed to create owner nv index attributes");
///
/// // Create owner nv public.
/// let owner_nv_public = NvPublic::builder()
/// .with_nv_index(nv_index)
/// .with_index_name_algorithm(HashingAlgorithm::Sha256)
/// .with_index_attributes(owner_nv_index_attributes)
/// .with_data_area_size(32)
/// .build()
/// .expect("Failed to build NvPublic for owner");
///
/// let nv_index_handle = context
/// .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
/// .expect("Call to nv_define_space failed");
///
/// let data = MaxNvBuffer::try_from(vec![0x0]).unwrap();
/// let result = context.nv_extend(NvAuth::Owner, nv_index_handle, data);
///
/// # context
/// # .nv_undefine_space(Provision::Owner, nv_index_handle)
/// # .expect("Call to nv_undefine_space failed");
/// ```
pub fn nv_extend(
&mut self,
auth_handle: NvAuth,
nv_index_handle: NvIndexHandle,
data: MaxNvBuffer,
) -> Result<()> {
ReturnCode::ensure_success(
unsafe {
Esys_NV_Extend(
self.mut_context(),
AuthHandle::from(auth_handle).into(),
nv_index_handle.into(),
self.required_session_1()?,
self.optional_session_2(),
self.optional_session_3(),
&data.into(),
)
},
|ret| error!("Error when extending NV: {:#010X}", ret),
)
}

// Missing function: NV_SetBits
// Missing function: NV_WriteLock
// Missing function: NV_GlobalWriteLock
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,3 +421,125 @@ mod test_nv_increment {
assert_eq!(first_value + 1, second_value);
}
}

mod test_nv_extend {
use crate::common::create_ctx_with_session;
use tss_esapi::{
attributes::NvIndexAttributesBuilder,
constants::nv_index_type::NvIndexType,
handles::NvIndexTpmHandle,
interface_types::{
algorithm::HashingAlgorithm,
reserved_handles::{NvAuth, Provision},
},
structures::{MaxNvBuffer, NvPublicBuilder},
};

#[test]
fn test_nv_extend() {
let mut context = create_ctx_with_session();
let nv_index = NvIndexTpmHandle::new(0x01500029).unwrap();

// Create owner nv public.
let owner_nv_index_attributes = NvIndexAttributesBuilder::new()
.with_owner_write(true)
.with_owner_read(true)
.with_orderly(true)
.with_nv_index_type(NvIndexType::Extend)
.build()
.expect("Failed to create owner nv index attributes");

let owner_nv_public = NvPublicBuilder::new()
.with_nv_index(nv_index)
.with_index_name_algorithm(HashingAlgorithm::Sha256)
.with_index_attributes(owner_nv_index_attributes)
.with_data_area_size(32)
.build()
.expect("Failed to build NvPublic for owner");

let owner_nv_index_handle = context
.nv_define_space(Provision::Owner, None, owner_nv_public)
.expect("Call to nv_define_space failed");

// Attempt to read an un-"written"/uninitialized NV index that is defined as extend type
let nv_read_result = context.nv_read(NvAuth::Owner, owner_nv_index_handle, 32, 0);
assert!(nv_read_result.is_err());

// Extend NV index with data
let data = MaxNvBuffer::try_from(vec![0x0]).unwrap();
context
.nv_extend(NvAuth::Owner, owner_nv_index_handle, data)
.expect("Failed to extend NV index");

// Validate the new state of the index, which was extended by the data
let nv_read_result = context.nv_read(NvAuth::Owner, owner_nv_index_handle, 32, 0);
let read_data = nv_read_result.expect("Call to nv_read failed");

// Expected value is sha256([0; 32] + [0; 1])
assert_eq!(
[
0x7f, 0x9c, 0x9e, 0x31, 0xac, 0x82, 0x56, 0xca, 0x2f, 0x25, 0x85, 0x83, 0xdf, 0x26,
0x2d, 0xbc, 0x7d, 0x6f, 0x68, 0xf2, 0xa0, 0x30, 0x43, 0xd5, 0xc9, 0x9a, 0x4a, 0xe5,
0xa7, 0x39, 0x6c, 0xe9
],
read_data.as_ref()
);

// Clean up defined NV index
context
.nv_undefine_space(Provision::Owner, owner_nv_index_handle)
.expect("Call to nv_undefine_space failed");

// Create platform nv public that is cleared on TPM reset/shutdown
let platform_nv_index_attributes = NvIndexAttributesBuilder::new()
.with_pp_write(true)
.with_pp_read(true)
.with_orderly(true)
.with_platform_create(true)
.with_nv_index_type(NvIndexType::Extend)
.with_clear_stclear(true)
.build()
.expect("Failed to create owner nv index attributes");

let platform_nv_public = NvPublicBuilder::new()
.with_nv_index(nv_index)
.with_index_name_algorithm(HashingAlgorithm::Sha256)
.with_index_attributes(platform_nv_index_attributes)
.with_data_area_size(32)
.build()
.expect("Failed to build NvPublic for owner");

let platform_nv_index_handle = context
.nv_define_space(Provision::Platform, None, platform_nv_public)
.expect("Call to nv_define_space failed");

// Attempt to read an un-"written"/uninitialized NV index that is defined as extend type
let nv_read_result = context.nv_read(NvAuth::Platform, platform_nv_index_handle, 32, 0);
assert!(nv_read_result.is_err());

// Extend NV index with data
let data = MaxNvBuffer::try_from(vec![0x0]).unwrap();
context
.nv_extend(NvAuth::Platform, platform_nv_index_handle, data)
.expect("Failed to extend NV index");

// Validate the new state of the index, which was extended by the data
let nv_read_result = context.nv_read(NvAuth::Platform, platform_nv_index_handle, 32, 0);
let read_data = nv_read_result.expect("Call to nv_read failed");

// Expected value is sha256([0; 32] + [0; 1])
assert_eq!(
[
0x7f, 0x9c, 0x9e, 0x31, 0xac, 0x82, 0x56, 0xca, 0x2f, 0x25, 0x85, 0x83, 0xdf, 0x26,
0x2d, 0xbc, 0x7d, 0x6f, 0x68, 0xf2, 0xa0, 0x30, 0x43, 0xd5, 0xc9, 0x9a, 0x4a, 0xe5,
0xa7, 0x39, 0x6c, 0xe9
],
read_data.as_ref()
);

// Clean up defined NV index
context
.nv_undefine_space(Provision::Platform, platform_nv_index_handle)
.expect("Call to nv_undefine_space failed");
}
}