Skip to content

Commit

Permalink
Return details about the endorsement from verify_endorsement().
Browse files Browse the repository at this point in the history
The public version returns a proto, the crate-internal version returns the parsed statement as a Rust struct.

Bug: 366215880
Change-Id: I7cdc298619f91d7b0d5599f8d92cd543cabbd482
  • Loading branch information
thmsbinder committed Oct 8, 2024
1 parent af17dd7 commit 13de644
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 10 deletions.
16 changes: 9 additions & 7 deletions oak_attestation_verification/src/endorsement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,10 @@ pub fn is_kernel_type(statement: &DefaultStatement) -> bool {
|| statement.predicate.claims.iter().any(|x| x.r#type == KERNEL_CLAIM_TYPE);
}

/// Verifies a signed endorsement against reference value.
/// Verifies a signed endorsement against a reference value.
///
/// Returns Ok whenever the verification succeeds, or an error otherwise.
/// Returns the parsed statement whenever the verification succeeds, or an error
/// otherwise.
///
/// `now_utc_millis`: The current time in milliseconds UTC since Unix Epoch.
/// `signed_endorsement`: The endorsement along with signature and (optional)
Expand All @@ -163,7 +164,7 @@ pub fn verify_endorsement(
now_utc_millis: i64,
signed_endorsement: &SignedEndorsement,
ref_value: &EndorsementReferenceValue,
) -> anyhow::Result<()> {
) -> anyhow::Result<DefaultStatement> {
// Reject ref_value instances using the potentially deprecated fields.
if !ref_value.endorser_public_key.is_empty() || !ref_value.rekor_public_key.is_empty() {
anyhow::bail!("verify_endorsement does not support the deprecated fields");
Expand Down Expand Up @@ -192,15 +193,16 @@ pub fn verify_endorsement(
let rekor_ref_value =
ref_value.rekor.as_ref().context("no rekor key set in signed endorsement")?;
return match rekor_ref_value.r#type.as_ref() {
Some(verifying_key_reference_value::Type::Skip(_)) => Ok(()),
Some(verifying_key_reference_value::Type::Skip(_)) => Ok(statement),
Some(verifying_key_reference_value::Type::Verify(key_set)) => {
let log_entry = &signed_endorsement.rekor_log_entry;
if log_entry.is_empty() {
anyhow::bail!("log entry unavailable but verification was requested");
}
verify_rekor_log_entry(log_entry, key_set, &endorsement.serialized)
.context("verifying rekor log entry")?;
verify_endorser_public_key(log_entry, signature.key_id, endorser_key_set)
verify_endorser_public_key(log_entry, signature.key_id, endorser_key_set)?;
Ok(statement)
}
None => Err(anyhow::anyhow!("empty Rekor verifying key set reference value")),
};
Expand Down Expand Up @@ -325,10 +327,10 @@ pub fn validate_statement(

match &statement.predicate.validity {
Some(validity) => {
if validity.not_before.unix_timestamp_nanos() / 1000000 > now_utc_millis.into() {
if 1000 * validity.not_before.unix_timestamp() > now_utc_millis.into() {
anyhow::bail!("the claim is not yet applicable")
}
if validity.not_after.unix_timestamp_nanos() / 1000000 < now_utc_millis.into() {
if 1000 * validity.not_after.unix_timestamp() < now_utc_millis.into() {
anyhow::bail!("the claim is no longer applicable")
}
}
Expand Down
33 changes: 31 additions & 2 deletions oak_attestation_verification/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,34 @@ pub mod verifier;
#[cfg(test)]
mod test_util;

pub use endorsement::verify_endorsement;
pub use util::{convert_pem_to_raw, reference_values_from_evidence};
use anyhow::Context;
use oak_proto_rust::oak::attestation::v1::{
EndorsementDetails, EndorsementReferenceValue, SignedEndorsement, Validity,
};
pub use util::{
convert_pem_to_raw, hex_to_raw_digest, raw_to_hex_digest, reference_values_from_evidence,
};

/// Verifies a signed endorsement against a reference value.
///
/// `now_utc_millis`: The current time in milliseconds UTC since Unix Epoch.
/// `signed_endorsement`: The endorsement along with signature and (optional)
/// Rekor log entry.
/// `ref_value`: A reference value containing e.g. the public keys needed
/// for the verification.
pub fn verify_endorsement(
now_utc_millis: i64,
signed_endorsement: &SignedEndorsement,
ref_value: &EndorsementReferenceValue,
) -> anyhow::Result<EndorsementDetails> {
let s = endorsement::verify_endorsement(now_utc_millis, signed_endorsement, ref_value)?;
let digest = hex_to_raw_digest(&endorsement::get_digest(&s)?)?;
let validity = s.predicate.validity.context("missing validity in statement")?;
Ok(EndorsementDetails {
subject_digest: Some(digest),
validity: Some(Validity {
not_before: 1000 * validity.not_before.unix_timestamp(),
not_after: 1000 * validity.not_after.unix_timestamp(),
}),
})
}
12 changes: 11 additions & 1 deletion oak_attestation_verification/tests/endorsement_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

use std::fs;

use oak_attestation_verification::{convert_pem_to_raw, verify_endorsement};
use oak_attestation_verification::{convert_pem_to_raw, raw_to_hex_digest, verify_endorsement};
use oak_file_utils::data_path;
use oak_proto_rust::oak::attestation::v1::{
endorsement::Format, verifying_key_reference_value, ClaimReferenceValue, Endorsement,
Expand Down Expand Up @@ -110,6 +110,16 @@ fn test_verify_endorsement_success() {
&testdata.ref_value,
);
assert!(result.is_ok(), "{:?}", result);

let details = result.unwrap();
let d = raw_to_hex_digest(&details.subject_digest.as_ref().unwrap());
assert!(
d.sha2_256 == "18c34d8cc737fb5709a99acb073cdc5ed8a404503f626cea6e0bad0a406002fc",
"{:?}",
details
);
assert!(details.validity.as_ref().unwrap().not_before == 1709113632000, "{:?}", details);
assert!(details.validity.as_ref().unwrap().not_after == 1740649632000, "{:?}", details);
}

#[test]
Expand Down
25 changes: 25 additions & 0 deletions oak_proto_rust/generated/oak.attestation.v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,31 @@ pub mod attestation_results {
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost_derive::Message)]
pub struct EventAttestationResults {}
/// Specifies a temporal range of validity for an endorsement.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost_derive::Message)]
pub struct Validity {
/// The time the endorsement first became valid. In milliseconds UTC since
/// Unix Epoch.
#[prost(int64, tag = "1")]
pub not_before: i64,
/// The time the endorsement was last valid. In milliseconds UTC since
/// Unix Epoch.
#[prost(int64, tag = "2")]
pub not_after: i64,
}
/// Details about the endorsement statement which can be passed across FFI
/// boundaries.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost_derive::Message)]
pub struct EndorsementDetails {
/// Digest of the first subject in the endorsement.
#[prost(message, optional, tag = "1")]
pub subject_digest: ::core::option::Option<super::super::RawDigest>,
/// Validity of the verified endorsement.
#[prost(message, optional, tag = "2")]
pub validity: ::core::option::Option<Validity>,
}
/// Evidence values extracted from attestation evidence during verification.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost_derive::Message)]
Expand Down
21 changes: 21 additions & 0 deletions proto/attestation/verification.proto
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,27 @@ message AttestationResults {
// TODO: b/366419879 - Implement descriptive per-event attestation results.
message EventAttestationResults {}

// Specifies a temporal range of validity for an endorsement.
message Validity {
// The time the endorsement first became valid. In milliseconds UTC since
// Unix Epoch.
int64 not_before = 1;

// The time the endorsement was last valid. In milliseconds UTC since
// Unix Epoch.
int64 not_after = 2;
}

// Details about the endorsement statement which can be passed across FFI
// boundaries.
message EndorsementDetails {
// Digest of the first subject in the endorsement.
RawDigest subject_digest = 1;

// Validity of the verified endorsement.
Validity validity = 2;
}

// Evidence values extracted from attestation evidence during verification.
message ExtractedEvidence {
oneof evidence_values {
Expand Down

0 comments on commit 13de644

Please sign in to comment.