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
2 changes: 1 addition & 1 deletion config/templates/policy_v2.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion config/templates/policy_v2_signed.json

Large diffs are not rendered by default.

154 changes: 154 additions & 0 deletions src/crypto/src/crl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Copyright (c) 2022 Intel Corporation
//
// SPDX-License-Identifier: BSD-2-Clause-Patent

use crate::x509::{Extension, Time};
use crate::Error;
use alloc::vec::Vec;
use der::asn1::{AnyRef, BitStringRef, ObjectIdentifier};
use der::{Choice, Decode, Encode, ErrorKind, Header, Sequence, Tag, TagMode, TagNumber, Tagged};
use rustls_pemfile::Item;

const CRL_NUMBER_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.5.29.20");

#[derive(Sequence)]
pub struct Crl<'a> {
tbs_cert_list: TbsCertList<'a>,
signature_algorithm: AnyRef<'a>,
signature_value: BitStringRef<'a>,
}

#[derive(Sequence)]
struct TbsCertList<'a> {
version: Option<AnyRef<'a>>,
signature: AnyRef<'a>,
issuer: AnyRef<'a>,
this_update: Time,
next_update: Option<Time>,
revoked_certificates: Option<Vec<RevokedCertificate<'a>>>,
crl_extensions: Option<Extensions<'a>>,
}

#[derive(Sequence)]
struct RevokedCertificate<'a> {
user_certificate: AnyRef<'a>,
revocation_date: AnyRef<'a>,
crl_entry_extensions: Option<AnyRef<'a>>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Extensions<'a>(Vec<Extension<'a>>);

impl<'a> Extensions<'a> {
pub fn get(&self) -> &Vec<Extension<'a>> {
&self.0
}
}

impl Encode for Extensions<'_> {
fn encoded_len(&self) -> der::Result<der::Length> {
let len = self.0.encoded_len()?;
let explicit = Header::new(
Tag::ContextSpecific {
constructed: true,
number: TagNumber::new(0),
},
len,
)?;
explicit.encoded_len() + len
}

fn encode(&self, encoder: &mut impl der::Writer) -> der::Result<()> {
let len = self.0.encoded_len()?;
let explicit = Header::new(
Tag::ContextSpecific {
constructed: true,
number: TagNumber::new(0),
},
len,
)?;
explicit.encode(encoder)?;
self.0.encode(encoder)
}
}

impl<'a> Decode<'a> for Extensions<'a> {
fn decode<R: der::Reader<'a>>(decoder: &mut R) -> der::Result<Self> {
let ext = decoder
.context_specific(TagNumber::new(0), TagMode::Explicit)?
.ok_or(der::Error::new(ErrorKind::Failed, decoder.position()))?;
Ok(Self(ext))
}
}

impl Tagged for Extensions<'_> {
fn tag(&self) -> Tag {
Tag::ContextSpecific {
constructed: true,
number: TagNumber::new(0),
}
}
}

impl<'a> Choice<'a> for Extensions<'a> {
fn can_decode(tag: Tag) -> bool {
tag == Tag::ContextSpecific {
constructed: true,
number: TagNumber::new(0),
}
}
}

/// Parses a CRL and returns the CRL Number extension value
pub fn get_crl_number(crl: &[u8]) -> Result<u32, Error> {
let crl_der = match rustls_pemfile::read_one_from_slice(crl) {
Ok(Some((Item::Crl(data), _))) => data.to_vec(),
Ok(Some(_)) | Ok(None) | Err(_) => return Err(Error::DecodePemCert),
};

let crl = Crl::from_der(&crl_der).map_err(|_| Error::ParseCertificate)?;

if let Some(cs) = crl.tbs_cert_list.crl_extensions {
for ext in cs.get().iter() {
if ext.extn_id == CRL_NUMBER_OID {
let number =
u32::from_der(ext.extn_value.ok_or(Error::CrlNumberNotFound)?.as_bytes())
.map_err(|_| Error::CrlNumberNotFound)?;
return Ok(number);
}
}
}

Err(Error::CrlNumberNotFound)
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_get_crl_number() {
const CRL1: &[u8] = b"-----BEGIN X509 CRL-----
MIIBITCByAIBATAKBggqhkjOPQQDAjBoMRowGAYDVQQDDBFJbnRlbCBTR1ggUm9v
dCBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNVBAcMC1NhbnRh
IENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTI1MDkxNjExNTMxMloX
DTI2MDkxNjExNTMxMlqgLzAtMAoGA1UdFAQDAgEBMB8GA1UdIwQYMBaAFOnoRFJT
NlxLGJoR/EMYLKXcIIBIMAoGCCqGSM49BAMCA0gAMEUCIQDv5KEBogNCzPgupOPj
FIYJaOubypBPCGqnE0XcYTgFDwIgeSfXk71tIbV5lqp6gWCpN98/xu/8c7y36EV3
pkfootI=
-----END X509 CRL-----";

const CRL2: &[u8] = b"-----BEGIN X509 CRL-----
MIIBKTCB0AIBATAKBggqhkjOPQQDAjBwMSIwIAYDVQQDDBlJbnRlbCBTR1ggUENL
IFBsYXRmb3JtIENBMRowGAYDVQQKDBFJbnRlbCBDb3Jwb3JhdGlvbjEUMBIGA1UE
BwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYDVQQGEwJVUxcNMjUxMTIw
MDY0ODQ5WhcNMjUxMjIwMDY0ODQ5WqAvMC0wCgYDVR0UBAMCAQEwHwYDVR0jBBgw
FoAUWSPTp0qoY1QuOXCt4A8HK1ckKrcwCgYIKoZIzj0EAwIDSAAwRQIgQB8+Xmh7
QJEvrDG15ucaA2b2pByR86M8+3mDd5g5c0sCIQD1WVRItKvP90kBT6EZp03qAOCU
IrrRoE+AsML37e56hg==
-----END X509 CRL-----";

assert_eq!(get_crl_number(CRL1).unwrap(), 1);
assert_eq!(get_crl_number(CRL2).unwrap(), 1);
}
}
4 changes: 4 additions & 0 deletions src/crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ cfg_if::cfg_if! {
}
}

pub mod crl;
pub mod x509;

pub type Result<T> = core::result::Result<T, Error>;
Expand Down Expand Up @@ -80,6 +81,9 @@ pub enum Error {
/// Unsupported signature algorithm
UnsupportedAlgorithm,

/// CRL number extension missing
CrlNumberNotFound,

/// Unexpected error that should not happen
Unexpected,
}
Expand Down
8 changes: 7 additions & 1 deletion src/migtd/src/mig_policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ mod v2 {
use alloc::{string::String, string::ToString, vec::Vec};
use attestation::verify_quote_with_collaterals;
use chrono::DateTime;
use crypto::pem_cert_to_der;
use crypto::{crl::get_crl_number, pem_cert_to_der};
use lazy_static::lazy_static;
use policy::*;
use spin::Once;
Expand Down Expand Up @@ -272,6 +272,10 @@ mod v2 {
.get_engine_svn_by_report(&report_value);

let migtd_tcb = migtd_svn.and_then(|svn| policy.servtd_identity.get_tcb_level_by_svn(svn));
let pck_crl_num = get_crl_number(collaterals.pck_crl.as_bytes())
.map_err(|_| PolicyError::InvalidCollateral)?;
let root_ca_crl_num = get_crl_number(collaterals.root_ca_crl.as_bytes())
.map_err(|_| PolicyError::InvalidCollateral)?;

Ok(PolicyEvaluationInfo {
tcb_date: Some(tcb_date.to_string()),
Expand All @@ -281,6 +285,8 @@ mod v2 {
migtd_isvsvn: migtd_svn,
migtd_tcb_date: migtd_tcb.map(|tcb| tcb.tcb_date.clone()),
migtd_tcb_status: migtd_tcb.map(|tcb| tcb.tcb_status.clone()),
pck_crl_num: Some(pck_crl_num),
root_ca_crl_num: Some(root_ca_crl_num),
})
}

Expand Down
1 change: 1 addition & 0 deletions src/policy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub enum PolicyError {
InvalidQuote,
SvnMismatch,
TcbEvaluation,
CrlEvaluation,
HashCalculation,
QuoteVerification,
QuoteGeneration,
Expand Down
44 changes: 44 additions & 0 deletions src/policy/src/v2/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ pub struct PolicyEvaluationInfo {

/// The date of the MigTD TCB in ISO-8601 format, e.g. "2023-06-19T00:00:00Z"
pub migtd_tcb_date: Option<String>,

/// The minimal crl_num of pck_crl
pub pck_crl_num: Option<u32>,

/// The minimal crl_num of root_ca_crl
pub root_ca_crl_num: Option<u32>,
}

pub struct VerifiedPolicy<'a> {
Expand Down Expand Up @@ -295,6 +301,7 @@ enum PolicyTypes {
struct GlobalPolicy {
tcb: Option<TcbPolicy>,
platform: Option<PlatformPolicy>,
crl: Option<CrlPolicy>,
}

impl GlobalPolicy {
Expand All @@ -311,6 +318,10 @@ impl GlobalPolicy {
platform_policy.evaluate(value, relative_reference)?;
}

if let Some(crl_policy) = &self.crl {
crl_policy.evaluate(value, relative_reference)?;
}

Ok(())
}
}
Expand Down Expand Up @@ -399,6 +410,37 @@ impl PlatformPolicy {
}
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CrlPolicy {
pck_crl_num: Option<PolicyProperty>,
root_ca_crl_num: Option<PolicyProperty>,
}

impl CrlPolicy {
fn evaluate(
&self,
value: &PolicyEvaluationInfo,
relative_reference: &PolicyEvaluationInfo,
) -> Result<(), PolicyError> {
if let Some(property) = &self.pck_crl_num {
let pck_crl_num = value.pck_crl_num.ok_or(PolicyError::CrlEvaluation)?;
if !property.evaluate_integer(pck_crl_num, relative_reference.pck_crl_num)? {
return Err(PolicyError::CrlEvaluation);
}
}

if let Some(property) = &self.root_ca_crl_num {
let root_ca_crl_num = value.root_ca_crl_num.ok_or(PolicyError::CrlEvaluation)?;
if !property.evaluate_integer(root_ca_crl_num, relative_reference.root_ca_crl_num)? {
return Err(PolicyError::CrlEvaluation);
}
}

Ok(())
}
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ServtdPolicy {
Expand Down Expand Up @@ -691,6 +733,8 @@ mod test {
migtd_tcb_status: None,
migtd_tcb_date: None,
migtd_isvsvn: None,
pck_crl_num: None,
root_ca_crl_num: None,
};
let relative_ref = PolicyEvaluationInfo::default();
assert!(global_policy.evaluate(&value, &relative_ref).is_ok());
Expand Down
Loading