Skip to content

Commit

Permalink
feat: handle many cert requests
Browse files Browse the repository at this point in the history
Co-authored-by: Roman Volosatovs <roman@profian.com>
Co-authored-by: Nathaniel McCallum <nathaniel@profian.com>
Signed-off-by: Richard Zak <richard@profian.com>
  • Loading branch information
3 people committed Sep 21, 2022
1 parent 457aa05 commit e7840a4
Show file tree
Hide file tree
Showing 2 changed files with 188 additions and 152 deletions.
54 changes: 50 additions & 4 deletions src/crypto/certreq.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
// SPDX-FileCopyrightText: 2022 Profian Inc. <opensource@profian.com>
// SPDX-License-Identifier: AGPL-3.0-only

use anyhow::{anyhow, Result};
use anyhow::{anyhow, bail, Result};
use der::{asn1::BitStringRef, Encode};
use pkcs8::PrivateKeyInfo;
use x509::request::{CertReq, CertReqInfo};
use x509::ext::Extension;
use x509::request::{CertReq, CertReqInfo, ExtensionReq};

use super::{PrivateKeyInfoExt, SubjectPublicKeyInfoExt};
use crate::ext::{kvm::Kvm, sgx::Sgx, snp::Snp, ExtVerifier};

use const_oid::db::rfc5912::ID_EXTENSION_REQ;
use x509::Certificate;

pub trait CertReqExt<'a> {
/// Verifies that a certification request is sane.
Expand All @@ -33,12 +38,15 @@ impl<'a> CertReqExt<'a> for CertReq<'a> {
}
}

pub trait CertReqInfoExt {
pub trait CertReqInfoExt<'a> {
/// Signs the `CertReqInfo` with the specified `PrivateKeyInfo`
fn sign(self, pki: &PrivateKeyInfo<'_>) -> Result<Vec<u8>>;

/// Check that the `CertReqInfo`
fn attest(&self, issuer: &Certificate<'_>) -> Result<Vec<Extension<'a>>>;
}

impl<'a> CertReqInfoExt for CertReqInfo<'a> {
impl<'a> CertReqInfoExt<'a> for CertReqInfo<'a> {
fn sign(self, pki: &PrivateKeyInfo<'_>) -> Result<Vec<u8>> {
let algo = pki.signs_with()?;
let body = self.to_vec()?;
Expand All @@ -52,4 +60,42 @@ impl<'a> CertReqInfoExt for CertReqInfo<'a> {

Ok(rval.to_vec()?)
}

fn attest(&self, issuer: &Certificate<'_>) -> Result<Vec<Extension<'a>>> {
let mut extensions = Vec::new();
let mut attested = false;
for attr in self.attributes.iter() {
if attr.oid != ID_EXTENSION_REQ {
bail!("invalid extension");
}

for any in attr.values.iter() {
let ereq: ExtensionReq<'_> = any.decode_into().or_else(|e| bail!(e))?;
for ext in Vec::from(ereq) {
// If the issuer is self-signed, we are in debug mode.
let iss = &issuer.tbs_certificate;
let dbg = iss.issuer_unique_id == iss.subject_unique_id;
let dbg = dbg && iss.issuer == iss.subject;

// Validate the extension.
let (copy, att) = match ext.extn_id {
Kvm::OID => (Kvm::default().verify(self, &ext, dbg), Kvm::ATT),
Sgx::OID => (Sgx::default().verify(self, &ext, dbg), Sgx::ATT),
Snp::OID => (Snp::default().verify(self, &ext, dbg), Snp::ATT),
_ => bail!("unsupported extension"),
};

// Save results.
attested |= att;
if copy.or_else(|e| bail!(e))? {
extensions.push(ext);
}
}
}
}
if !attested {
bail!("attestation failed");
}
Ok(extensions)
}
}
Loading

0 comments on commit e7840a4

Please sign in to comment.