Skip to content

Adds the attest structures #293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Dec 2, 2021
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
8 changes: 4 additions & 4 deletions tss-esapi/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub struct Context {
),
/// TCTI context handle associated with the ESYS context.
/// As with the ESYS context, an optional Mbox wrapper allows the context to be deallocated.
tcti_context: TctiContext,
_tcti_context: TctiContext,
/// Handle manager that keep tracks of the state of the handles and how they are to be
/// disposed.
handle_manager: HandleManager,
Expand Down Expand Up @@ -91,12 +91,12 @@ impl Context {
pub fn new(tcti_name_conf: TctiNameConf) -> Result<Self> {
let mut esys_context = null_mut();

let mut tcti_context = TctiContext::initialize(tcti_name_conf)?;
let mut _tcti_context = TctiContext::initialize(tcti_name_conf)?;

let ret = unsafe {
Esys_Initialize(
&mut esys_context,
tcti_context.tcti_context_ptr(),
_tcti_context.tcti_context_ptr(),
null_mut(),
)
};
Expand All @@ -107,7 +107,7 @@ impl Context {
let context = Context {
esys_context,
sessions: (None, None, None),
tcti_context,
_tcti_context,
handle_manager: HandleManager::new(),
cached_tpm_properties: HashMap::new(),
};
Expand Down
11 changes: 7 additions & 4 deletions tss-esapi/src/context/tpm_commands/attestation_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::{
handles::KeyHandle,
structures::{Data, PcrSelectionList, Signature, SignatureScheme},
structures::{Attest, AttestBuffer, Data, PcrSelectionList, Signature, SignatureScheme},
tss2_esys::*,
Context, Error, Result,
};
Expand All @@ -25,7 +25,7 @@ impl Context {
qualifying_data: &Data,
signing_scheme: SignatureScheme,
pcr_selection_list: PcrSelectionList,
) -> Result<(TPM2B_ATTEST, Signature)> {
) -> Result<(Attest, Signature)> {
let mut quoted = null_mut();
let mut signature = null_mut();
let ret = unsafe {
Expand All @@ -45,9 +45,12 @@ impl Context {
let ret = Error::from_tss_rc(ret);

if ret.is_success() {
let quoted = unsafe { MBox::<TPM2B_ATTEST>::from_raw(quoted) };
let quoted = unsafe { MBox::from_raw(quoted) };
let signature = unsafe { MBox::from_raw(signature) };
Ok((*quoted, Signature::try_from(*signature)?))
Ok((
Attest::try_from(AttestBuffer::try_from(*quoted)?)?,
Signature::try_from(*signature)?,
))
} else {
error!("Error in quoting PCR: {}", ret);
Err(ret)
Expand Down
5 changes: 5 additions & 0 deletions tss-esapi/src/interface_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@

//! This module contains the different interface types defined in
//! the TPM 2.0 specification.
mod yes_no;

pub mod algorithm;
pub mod dynamic_handles;
pub mod ecc;
pub mod key_bits;
pub mod resource_handles;
pub mod session_handles;
pub mod structure_tags;

pub use yes_no::YesNo;
68 changes: 68 additions & 0 deletions tss-esapi/src/interface_types/structure_tags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2021 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0

use crate::{constants::StructureTag, tss2_esys::TPMI_ST_ATTEST, Error, Result, WrapperErrorKind};
use std::convert::TryFrom;

/// Type of attestation.
///
/// # Details
/// Corresponds to `TPMI_ST_ATTEST`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AttestationType {
Certify,
Quote,
SessionAudit,
CommandAudit,
Time,
Creation,
Nv,
NvDigest,
}

impl From<AttestationType> for StructureTag {
fn from(native: AttestationType) -> Self {
match native {
AttestationType::Certify => StructureTag::AttestCertify,
AttestationType::Quote => StructureTag::AttestQuote,
AttestationType::SessionAudit => StructureTag::AttestSessionAudit,
AttestationType::CommandAudit => StructureTag::AttestCommandAudit,
AttestationType::Time => StructureTag::AttestTime,
AttestationType::Creation => StructureTag::AttestCreation,
AttestationType::Nv => StructureTag::AttestNv,
AttestationType::NvDigest => StructureTag::AttestNvDigest,
}
}
}

impl TryFrom<StructureTag> for AttestationType {
type Error = Error;

fn try_from(structure_tag: StructureTag) -> Result<AttestationType> {
match structure_tag {
StructureTag::AttestCertify => Ok(AttestationType::Certify),
StructureTag::AttestQuote => Ok(AttestationType::Quote),
StructureTag::AttestSessionAudit => Ok(AttestationType::SessionAudit),
StructureTag::AttestCommandAudit => Ok(AttestationType::CommandAudit),
StructureTag::AttestTime => Ok(AttestationType::Time),
StructureTag::AttestCreation => Ok(AttestationType::Creation),
StructureTag::AttestNv => Ok(AttestationType::Nv),
StructureTag::AttestNvDigest => Ok(AttestationType::NvDigest),
_ => Err(Error::local_error(WrapperErrorKind::InvalidParam)),
}
}
}

impl From<AttestationType> for TPMI_ST_ATTEST {
fn from(attestation_type: AttestationType) -> Self {
StructureTag::from(attestation_type).into()
}
}

impl TryFrom<TPMI_ST_ATTEST> for AttestationType {
type Error = Error;

fn try_from(tpmi_st_attest: TPMI_ST_ATTEST) -> Result<Self> {
AttestationType::try_from(StructureTag::try_from(tpmi_st_attest)?)
}
}
54 changes: 54 additions & 0 deletions tss-esapi/src/interface_types/yes_no.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2021 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
use crate::{tss2_esys::TPMI_YES_NO, Error, Result, WrapperErrorKind};
use std::convert::TryFrom;

/// Enum representing a yes or no.
///
/// # Details
/// This corresponds to the TPMI_YES_NO interface type.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum YesNo {
Yes,
No,
}

impl From<bool> for YesNo {
fn from(value: bool) -> Self {
if value {
YesNo::Yes
} else {
YesNo::No
}
}
}

impl From<YesNo> for bool {
fn from(yes_no: YesNo) -> Self {
match yes_no {
YesNo::Yes => true,
YesNo::No => false,
}
}
}

impl From<YesNo> for TPMI_YES_NO {
fn from(yes_no: YesNo) -> Self {
match yes_no {
YesNo::Yes => 1,
YesNo::No => 0,
}
}
}

impl TryFrom<TPMI_YES_NO> for YesNo {
type Error = Error;

fn try_from(tpmi_yes_no: TPMI_YES_NO) -> Result<Self> {
match tpmi_yes_no {
0 => Ok(YesNo::No),
1 => Ok(YesNo::Yes),
_ => Err(Error::local_error(WrapperErrorKind::InvalidParam)),
}
}
}
1 change: 1 addition & 0 deletions tss-esapi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,5 @@ pub mod interface_types;
pub mod nv;
pub mod structures;
pub mod tcti_ldr;
pub mod traits;
pub mod utils;
178 changes: 178 additions & 0 deletions tss-esapi/src/structures/attest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright 2021 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0

use crate::{
constants::tss::TPM2_GENERATED_VALUE,
interface_types::structure_tags::AttestationType,
structures::{AttestInfo, ClockInfo, Data, Name},
traits::{Marshall, UnMarshall},
tss2_esys::TPMS_ATTEST,
Error, Result, WrapperErrorKind,
};
use log::error;
use std::convert::{TryFrom, TryInto};

/// Type for holding attestation data
///
/// # Details
/// Corresponds to `TPMS_ATTEST`.
#[derive(Debug, Clone)]
pub struct Attest {
attestation_type: AttestationType,
qualified_signer: Name,
extra_data: Data,
clock_info: ClockInfo,
firmware_version: u64,
attested: AttestInfo,
}

impl Attest {
/// Returns ttestation type
pub const fn attestation_type(&self) -> AttestationType {
self.attestation_type
}

/// Returns the qualified name of the signing object.
pub const fn qualified_signer(&self) -> &Name {
&self.qualified_signer
}

/// Retirns the extra data specified by the caller.
pub const fn extra_data(&self) -> &Data {
&self.extra_data
}

/// Returns the internal TPM clock data.
pub const fn clock_info(&self) -> &ClockInfo {
&self.clock_info
}

/// Returns TPM firmware version number.
pub const fn firmware_version(&self) -> u64 {
self.firmware_version
}

/// Returns types specific attestation information
pub const fn attested(&self) -> &AttestInfo {
&self.attested
}
}

impl From<Attest> for TPMS_ATTEST {
fn from(attest: Attest) -> Self {
TPMS_ATTEST {
magic: TPM2_GENERATED_VALUE,
type_: attest.attestation_type.into(),
qualifiedSigner: attest.qualified_signer.into(),
extraData: attest.extra_data.into(),
clockInfo: attest.clock_info.into(),
firmwareVersion: attest.firmware_version,
attested: attest.attested.into(),
}
}
}

impl TryFrom<TPMS_ATTEST> for Attest {
type Error = Error;

fn try_from(tpms_attest: TPMS_ATTEST) -> Result<Self> {
if tpms_attest.magic != TPM2_GENERATED_VALUE {
return Err(Error::local_error(WrapperErrorKind::InvalidParam));
}

let attestation_type = AttestationType::try_from(tpms_attest.type_)?;
Ok(Attest {
attestation_type,
qualified_signer: Name::try_from(tpms_attest.qualifiedSigner)?,
extra_data: Data::try_from(tpms_attest.extraData)?,
clock_info: ClockInfo::try_from(tpms_attest.clockInfo)?,
firmware_version: tpms_attest.firmwareVersion,
attested: match attestation_type {
AttestationType::Certify => AttestInfo::Certify {
info: unsafe { tpms_attest.attested.certify }.try_into()?,
},
AttestationType::Quote => AttestInfo::Quote {
info: unsafe { tpms_attest.attested.quote }.try_into()?,
},
AttestationType::SessionAudit => AttestInfo::SessionAudit {
info: unsafe { tpms_attest.attested.sessionAudit }.try_into()?,
},
AttestationType::CommandAudit => AttestInfo::CommandAudit {
info: unsafe { tpms_attest.attested.commandAudit }.try_into()?,
},
AttestationType::Time => AttestInfo::Time {
info: unsafe { tpms_attest.attested.time }.try_into()?,
},
AttestationType::Creation => AttestInfo::Creation {
info: unsafe { tpms_attest.attested.creation }.try_into()?,
},
AttestationType::Nv => AttestInfo::Nv {
info: unsafe { tpms_attest.attested.nv }.try_into()?,
},
AttestationType::NvDigest => {
error!("NvDigest attestation type is currently not supported");
return Err(Error::local_error(WrapperErrorKind::UnsupportedParam));
}
},
})
}
}

impl Marshall for Attest {
const BUFFER_SIZE: usize = std::mem::size_of::<TPMS_ATTEST>();

fn marshall(&self) -> Result<Vec<u8>> {
let mut buffer = vec![0; Self::BUFFER_SIZE];
let mut offset = 0;

let ret = Error::from_tss_rc(unsafe {
crate::tss2_esys::Tss2_MU_TPMS_ATTEST_Marshal(
&self.clone().into(),
buffer.as_mut_ptr(),
Self::BUFFER_SIZE.try_into().map_err(|e| {
error!("Failed to convert size of buffer to TSS size_t type: {}", e);
Error::local_error(WrapperErrorKind::InvalidParam)
})?,
&mut offset,
)
});

if !ret.is_success() {
return Err(ret);
}

let checked_offset = usize::try_from(offset).map_err(|e| {
error!("Failed to parse offset as usize: {}", e);
Error::local_error(WrapperErrorKind::InvalidParam)
})?;

buffer.truncate(checked_offset);

Ok(buffer)
}
}

impl UnMarshall for Attest {
fn unmarshall(marshalled_data: &[u8]) -> Result<Self> {
let mut dest = TPMS_ATTEST::default();
let mut offset = 0;

let ret = Error::from_tss_rc(unsafe {
crate::tss2_esys::Tss2_MU_TPMS_ATTEST_Unmarshal(
marshalled_data.as_ptr(),
marshalled_data.len().try_into().map_err(|e| {
error!("Failed to convert length of marshalled data: {}", e);
Error::local_error(WrapperErrorKind::InvalidParam)
})?,
&mut offset,
&mut dest,
)
});

if !ret.is_success() {
return Err(ret);
}

Attest::try_from(dest)
}
}
Loading