Skip to content

Commit 41bd9e9

Browse files
authored
Merge pull request #584 from nathanrossi/nathanrossi/nv-extend
Add definition for NV_Extend
2 parents a33e447 + ecdd815 commit 41bd9e9

File tree

2 files changed

+233
-2
lines changed

2 files changed

+233
-2
lines changed

tss-esapi/src/context/tpm_commands/non_volatile_storage.rs

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
interface_types::reserved_handles::{NvAuth, Provision},
77
structures::{Auth, MaxNvBuffer, Name, NvPublic},
88
tss2_esys::{
9-
Esys_NV_DefineSpace, Esys_NV_Increment, Esys_NV_Read, Esys_NV_ReadPublic,
9+
Esys_NV_DefineSpace, Esys_NV_Extend, Esys_NV_Increment, Esys_NV_Read, Esys_NV_ReadPublic,
1010
Esys_NV_UndefineSpace, Esys_NV_UndefineSpaceSpecial, Esys_NV_Write,
1111
},
1212
Context, Result, ReturnCode,
@@ -698,7 +698,116 @@ impl Context {
698698
)
699699
}
700700

701-
// Missing function: NV_Extend
701+
/// Extends data to the NV memory associated with a nv index.
702+
///
703+
/// # Details
704+
/// This method is used to extend a value to the nv memory in the TPM.
705+
///
706+
/// Please beware that this method requires an authorization session handle to be present.
707+
///
708+
/// Any NV index (that is not already used) can be defined as an extend type. However various specifications define
709+
/// indexes that have specific purposes or are reserved, for example the TCG PC Client Platform Firmware Profile
710+
/// Specification Section 3.3.6 defines indexes within the 0x01c40200-0x01c402ff range for instance measurements.
711+
/// Section 2.2 of TCG Registry of Reserved TPM 2.0 Handles and Localities provides additional context for specific
712+
/// NV index ranges.
713+
///
714+
/// # Arguments
715+
/// * `auth_handle` - Handle indicating the source of authorization value.
716+
/// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
717+
/// which will be extended by data hashed with the previous data.
718+
/// * `data` - The data, in the form of a [MaxNvBuffer], that is to be written.
719+
///
720+
/// # Example
721+
/// ```rust
722+
/// # use tss_esapi::{
723+
/// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
724+
/// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
725+
/// # structures::{SymmetricDefinition, NvPublic},
726+
/// # constants::SessionType, constants::nv_index_type::NvIndexType,
727+
/// # };
728+
/// use tss_esapi::{
729+
/// interface_types::reserved_handles::{Provision, NvAuth}, structures::MaxNvBuffer,
730+
/// };
731+
///
732+
/// # // Create context
733+
/// # let mut context =
734+
/// # Context::new(
735+
/// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
736+
/// # ).expect("Failed to create Context");
737+
/// #
738+
/// # let session = context
739+
/// # .start_auth_session(
740+
/// # None,
741+
/// # None,
742+
/// # None,
743+
/// # SessionType::Hmac,
744+
/// # SymmetricDefinition::AES_256_CFB,
745+
/// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
746+
/// # )
747+
/// # .expect("Failed to create session")
748+
/// # .expect("Received invalid handle");
749+
/// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
750+
/// # .with_decrypt(true)
751+
/// # .with_encrypt(true)
752+
/// # .build();
753+
/// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
754+
/// # .expect("Failed to set attributes on session");
755+
/// # context.set_sessions((Some(session), None, None));
756+
/// #
757+
/// # let nv_index = NvIndexTpmHandle::new(0x01500028)
758+
/// # .expect("Failed to create NV index tpm handle");
759+
/// #
760+
/// // Create NV index attributes
761+
/// let owner_nv_index_attributes = NvIndexAttributes::builder()
762+
/// .with_owner_write(true)
763+
/// .with_owner_read(true)
764+
/// .with_orderly(true)
765+
/// .with_nv_index_type(NvIndexType::Extend)
766+
/// .build()
767+
/// .expect("Failed to create owner nv index attributes");
768+
///
769+
/// // Create owner nv public.
770+
/// let owner_nv_public = NvPublic::builder()
771+
/// .with_nv_index(nv_index)
772+
/// .with_index_name_algorithm(HashingAlgorithm::Sha256)
773+
/// .with_index_attributes(owner_nv_index_attributes)
774+
/// .with_data_area_size(32)
775+
/// .build()
776+
/// .expect("Failed to build NvPublic for owner");
777+
///
778+
/// let nv_index_handle = context
779+
/// .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
780+
/// .expect("Call to nv_define_space failed");
781+
///
782+
/// let data = MaxNvBuffer::try_from(vec![0x0]).unwrap();
783+
/// let result = context.nv_extend(NvAuth::Owner, nv_index_handle, data);
784+
///
785+
/// # context
786+
/// # .nv_undefine_space(Provision::Owner, nv_index_handle)
787+
/// # .expect("Call to nv_undefine_space failed");
788+
/// ```
789+
pub fn nv_extend(
790+
&mut self,
791+
auth_handle: NvAuth,
792+
nv_index_handle: NvIndexHandle,
793+
data: MaxNvBuffer,
794+
) -> Result<()> {
795+
ReturnCode::ensure_success(
796+
unsafe {
797+
Esys_NV_Extend(
798+
self.mut_context(),
799+
AuthHandle::from(auth_handle).into(),
800+
nv_index_handle.into(),
801+
self.required_session_1()?,
802+
self.optional_session_2(),
803+
self.optional_session_3(),
804+
&data.into(),
805+
)
806+
},
807+
|ret| error!("Error when extending NV: {:#010X}", ret),
808+
)
809+
}
810+
702811
// Missing function: NV_SetBits
703812
// Missing function: NV_WriteLock
704813
// Missing function: NV_GlobalWriteLock

tss-esapi/tests/integration_tests/context_tests/tpm_commands/non_volatile_storage_tests.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,3 +421,125 @@ mod test_nv_increment {
421421
assert_eq!(first_value + 1, second_value);
422422
}
423423
}
424+
425+
mod test_nv_extend {
426+
use crate::common::create_ctx_with_session;
427+
use tss_esapi::{
428+
attributes::NvIndexAttributesBuilder,
429+
constants::nv_index_type::NvIndexType,
430+
handles::NvIndexTpmHandle,
431+
interface_types::{
432+
algorithm::HashingAlgorithm,
433+
reserved_handles::{NvAuth, Provision},
434+
},
435+
structures::{MaxNvBuffer, NvPublicBuilder},
436+
};
437+
438+
#[test]
439+
fn test_nv_extend() {
440+
let mut context = create_ctx_with_session();
441+
let nv_index = NvIndexTpmHandle::new(0x01500029).unwrap();
442+
443+
// Create owner nv public.
444+
let owner_nv_index_attributes = NvIndexAttributesBuilder::new()
445+
.with_owner_write(true)
446+
.with_owner_read(true)
447+
.with_orderly(true)
448+
.with_nv_index_type(NvIndexType::Extend)
449+
.build()
450+
.expect("Failed to create owner nv index attributes");
451+
452+
let owner_nv_public = NvPublicBuilder::new()
453+
.with_nv_index(nv_index)
454+
.with_index_name_algorithm(HashingAlgorithm::Sha256)
455+
.with_index_attributes(owner_nv_index_attributes)
456+
.with_data_area_size(32)
457+
.build()
458+
.expect("Failed to build NvPublic for owner");
459+
460+
let owner_nv_index_handle = context
461+
.nv_define_space(Provision::Owner, None, owner_nv_public)
462+
.expect("Call to nv_define_space failed");
463+
464+
// Attempt to read an un-"written"/uninitialized NV index that is defined as extend type
465+
let nv_read_result = context.nv_read(NvAuth::Owner, owner_nv_index_handle, 32, 0);
466+
assert!(nv_read_result.is_err());
467+
468+
// Extend NV index with data
469+
let data = MaxNvBuffer::try_from(vec![0x0]).unwrap();
470+
context
471+
.nv_extend(NvAuth::Owner, owner_nv_index_handle, data)
472+
.expect("Failed to extend NV index");
473+
474+
// Validate the new state of the index, which was extended by the data
475+
let nv_read_result = context.nv_read(NvAuth::Owner, owner_nv_index_handle, 32, 0);
476+
let read_data = nv_read_result.expect("Call to nv_read failed");
477+
478+
// Expected value is sha256([0; 32] + [0; 1])
479+
assert_eq!(
480+
[
481+
0x7f, 0x9c, 0x9e, 0x31, 0xac, 0x82, 0x56, 0xca, 0x2f, 0x25, 0x85, 0x83, 0xdf, 0x26,
482+
0x2d, 0xbc, 0x7d, 0x6f, 0x68, 0xf2, 0xa0, 0x30, 0x43, 0xd5, 0xc9, 0x9a, 0x4a, 0xe5,
483+
0xa7, 0x39, 0x6c, 0xe9
484+
],
485+
read_data.as_ref()
486+
);
487+
488+
// Clean up defined NV index
489+
context
490+
.nv_undefine_space(Provision::Owner, owner_nv_index_handle)
491+
.expect("Call to nv_undefine_space failed");
492+
493+
// Create platform nv public that is cleared on TPM reset/shutdown
494+
let platform_nv_index_attributes = NvIndexAttributesBuilder::new()
495+
.with_pp_write(true)
496+
.with_pp_read(true)
497+
.with_orderly(true)
498+
.with_platform_create(true)
499+
.with_nv_index_type(NvIndexType::Extend)
500+
.with_clear_stclear(true)
501+
.build()
502+
.expect("Failed to create owner nv index attributes");
503+
504+
let platform_nv_public = NvPublicBuilder::new()
505+
.with_nv_index(nv_index)
506+
.with_index_name_algorithm(HashingAlgorithm::Sha256)
507+
.with_index_attributes(platform_nv_index_attributes)
508+
.with_data_area_size(32)
509+
.build()
510+
.expect("Failed to build NvPublic for owner");
511+
512+
let platform_nv_index_handle = context
513+
.nv_define_space(Provision::Platform, None, platform_nv_public)
514+
.expect("Call to nv_define_space failed");
515+
516+
// Attempt to read an un-"written"/uninitialized NV index that is defined as extend type
517+
let nv_read_result = context.nv_read(NvAuth::Platform, platform_nv_index_handle, 32, 0);
518+
assert!(nv_read_result.is_err());
519+
520+
// Extend NV index with data
521+
let data = MaxNvBuffer::try_from(vec![0x0]).unwrap();
522+
context
523+
.nv_extend(NvAuth::Platform, platform_nv_index_handle, data)
524+
.expect("Failed to extend NV index");
525+
526+
// Validate the new state of the index, which was extended by the data
527+
let nv_read_result = context.nv_read(NvAuth::Platform, platform_nv_index_handle, 32, 0);
528+
let read_data = nv_read_result.expect("Call to nv_read failed");
529+
530+
// Expected value is sha256([0; 32] + [0; 1])
531+
assert_eq!(
532+
[
533+
0x7f, 0x9c, 0x9e, 0x31, 0xac, 0x82, 0x56, 0xca, 0x2f, 0x25, 0x85, 0x83, 0xdf, 0x26,
534+
0x2d, 0xbc, 0x7d, 0x6f, 0x68, 0xf2, 0xa0, 0x30, 0x43, 0xd5, 0xc9, 0x9a, 0x4a, 0xe5,
535+
0xa7, 0x39, 0x6c, 0xe9
536+
],
537+
read_data.as_ref()
538+
);
539+
540+
// Clean up defined NV index
541+
context
542+
.nv_undefine_space(Provision::Platform, platform_nv_index_handle)
543+
.expect("Call to nv_undefine_space failed");
544+
}
545+
}

0 commit comments

Comments
 (0)