diff --git a/Cargo.lock b/Cargo.lock index d118c6e..5491e7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -205,7 +205,7 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "azure_cvm" -version = "1.6.0" +version = "1.6.1" dependencies = [ "base64 0.22.1", "bincode", @@ -1417,7 +1417,7 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "maa_client" -version = "1.6.0" +version = "1.6.1" dependencies = [ "base64 0.22.1", "hex", @@ -1688,7 +1688,7 @@ dependencies = [ [[package]] name = "pccs_client" -version = "1.6.0" +version = "1.6.1" dependencies = [ "hex", "reqwest", @@ -1925,7 +1925,7 @@ dependencies = [ [[package]] name = "ratls" -version = "1.6.0" +version = "1.6.1" dependencies = [ "const-oid", "der", @@ -2317,7 +2317,7 @@ dependencies = [ [[package]] name = "sev_quote" -version = "1.6.0" +version = "1.6.1" dependencies = [ "asn1-rs", "bincode", @@ -2337,7 +2337,7 @@ dependencies = [ [[package]] name = "sgx_pck_extension" -version = "1.6.0" +version = "1.6.1" dependencies = [ "asn1", "asn1-rs", @@ -2347,7 +2347,7 @@ dependencies = [ [[package]] name = "sgx_quote" -version = "1.6.0" +version = "1.6.1" dependencies = [ "chrono", "env_logger 0.11.3", @@ -2556,7 +2556,7 @@ dependencies = [ [[package]] name = "tdx_quote" -version = "1.6.0" +version = "1.6.1" dependencies = [ "env_logger 0.11.3", "hex", @@ -2575,7 +2575,7 @@ dependencies = [ [[package]] name = "tee_attestation" -version = "1.6.0" +version = "1.6.1" dependencies = [ "azure_cvm", "env_logger 0.11.3", @@ -2810,7 +2810,7 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tpm_quote" -version = "1.6.0" +version = "1.6.1" dependencies = [ "env_logger 0.11.3", "hex", diff --git a/Cargo.toml b/Cargo.toml index a01e671..fd3d58c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ ] [workspace.package] -version = "1.6.0" +version = "1.6.1" edition = "2021" license = "BUSL-1.1" # "Business Source License 1.1" license-file = "LICENSE" diff --git a/crate/tpm_quote/src/lib.rs b/crate/tpm_quote/src/lib.rs index 7210230..b650397 100644 --- a/crate/tpm_quote/src/lib.rs +++ b/crate/tpm_quote/src/lib.rs @@ -1,17 +1,14 @@ use crate::key::{get_key_from_persistent_handle, TPM_AK_NVINDEX}; use error::Error; use policy::TpmPolicy; -use sha2::Digest; use std::convert::TryInto; use tss_esapi::{ interface_types::algorithm::HashingAlgorithm, - structures::{ - Attest, AttestInfo, PcrSelectionListBuilder, PcrSlot, Public, QuoteInfo, Signature, - }, + structures::{Attest, AttestInfo, PcrSelectionListBuilder, PcrSlot, Public, Signature}, traits::{Marshall, UnMarshall}, Context, }; -use verify::verify_quote_signature; +use verify::{verify_pcr_value, verify_quote_policy, verify_quote_signature}; pub mod command; pub mod convert; @@ -85,6 +82,20 @@ pub fn get_quote( )) } +/// Extract the digest of PCRs in TPM `quote`. +/// +/// # Returns +/// +/// Either [`Vec`] or [`Error`]. +pub fn get_pcr_digest_from_quote(quote: &[u8]) -> Result, Error> { + let attestation_data = Attest::unmarshall(quote)?; + let AttestInfo::Quote { info: quote_info } = attestation_data.attested() else { + return Err(Error::QuoteError("unexpected attestion type".to_owned())); + }; + + Ok(quote_info.pcr_digest().to_owned().to_vec()) +} + /// Verify signature of the `quote` with `public_key`` and `nonce`. /// /// # Returns @@ -127,55 +138,6 @@ pub fn verify_quote( Ok(()) } -/// Verify the quote against expected values -pub(crate) fn verify_quote_policy( - attestation_data: &Attest, - policy: &TpmPolicy, -) -> Result<(), Error> { - if let Some(reset_count) = policy.reset_count { - if attestation_data.clock_info().reset_count() != reset_count { - return Err(Error::VerificationError(format!( - "Attestation reset count '{}' is not equal to the set value '{}'", - attestation_data.clock_info().reset_count(), - reset_count - ))); - } - } - - if let Some(restart_count) = policy.restart_count { - if attestation_data.clock_info().restart_count() != restart_count { - return Err(Error::VerificationError(format!( - "Attestation restart count '{}' is not equal to the set value '{}'", - attestation_data.clock_info().restart_count(), - restart_count - ))); - } - } - - Ok(()) -} - -/// Verify the digest of the `pcr_value`. -/// -/// # Returns -/// -/// Either [`()`] or [`Error`]. -pub fn verify_pcr_value(quote_info: &QuoteInfo, pcr_value: &[u8]) -> Result<(), Error> { - let hpcr_value: [u8; 32] = quote_info.pcr_digest().to_owned().try_into()?; - - let expected_hpcr_value = sha2::Sha256::digest(pcr_value).to_vec(); - if expected_hpcr_value != hpcr_value[..] { - return Err(Error::VerificationError(format!( - "Bad Hash(PCR digest) in quote '{}', expected: '{}' from '{}'", - hex::encode(hpcr_value), - hex::encode(expected_hpcr_value), - hex::encode(pcr_value), - ))); - } - - Ok(()) -} - #[cfg(test)] mod tests { use std::str::FromStr; diff --git a/crate/tpm_quote/src/verify.rs b/crate/tpm_quote/src/verify.rs index f49f45c..6eebf84 100644 --- a/crate/tpm_quote/src/verify.rs +++ b/crate/tpm_quote/src/verify.rs @@ -1,16 +1,19 @@ -use crate::error::Error; +use crate::{error::Error, policy::TpmPolicy}; use std::convert::TryInto; +use sha2::Digest; + use p256::ecdsa::{signature::Verifier, VerifyingKey}; use tss_esapi::{ interface_types::{ algorithm::HashingAlgorithm, ecc::EccCurve, structure_tags::AttestationType, }, - structures::{Attest, EccScheme, Public, Signature}, + structures::{Attest, EccScheme, Public, QuoteInfo, Signature}, traits::Marshall, }; +/// Verify signature of TPM attestation with public key `pk`. pub(crate) fn verify_quote_signature( attestation_data: &Attest, signature: &Signature, @@ -107,3 +110,48 @@ pub(crate) fn verify_quote_signature( Ok(nonce) } + +/// Verify the quote against expected values in `TpmPolicy`. +pub(crate) fn verify_quote_policy( + attestation_data: &Attest, + policy: &TpmPolicy, +) -> Result<(), Error> { + if let Some(reset_count) = policy.reset_count { + if attestation_data.clock_info().reset_count() != reset_count { + return Err(Error::VerificationError(format!( + "Attestation reset count '{}' is not equal to the set value '{}'", + attestation_data.clock_info().reset_count(), + reset_count + ))); + } + } + + if let Some(restart_count) = policy.restart_count { + if attestation_data.clock_info().restart_count() != restart_count { + return Err(Error::VerificationError(format!( + "Attestation restart count '{}' is not equal to the set value '{}'", + attestation_data.clock_info().restart_count(), + restart_count + ))); + } + } + + Ok(()) +} + +/// Verify the digest of PCRs in `QuoteInfo` against expected `pcr_value`. +pub(crate) fn verify_pcr_value(quote_info: &QuoteInfo, pcr_value: &[u8]) -> Result<(), Error> { + let hpcr_value: [u8; 32] = quote_info.pcr_digest().to_owned().try_into()?; + + let expected_hpcr_value = sha2::Sha256::digest(pcr_value).to_vec(); + if expected_hpcr_value != hpcr_value[..] { + return Err(Error::VerificationError(format!( + "Bad Hash(PCR digest) in quote '{}', expected: '{}' from '{}'", + hex::encode(hpcr_value), + hex::encode(expected_hpcr_value), + hex::encode(pcr_value), + ))); + } + + Ok(()) +}