Skip to content

Commit

Permalink
VLEK: Adding VLEK support to tooling
Browse files Browse the repository at this point in the history
Signed-off-by: Larry Dewey <[email protected]>
  • Loading branch information
larrydewey committed Feb 16, 2024
1 parent 9418888 commit 864d3e3
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 81 deletions.
52 changes: 14 additions & 38 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ hyperv = ["tss-esapi"]
structopt = "0.3"
env_logger = "0.10.0"
anyhow = "1.0.69"
sev = { version = "^1.2", default-features = false, features = ['openssl','snp']}
#sev = { version = "^1.2", default-features = false, features = ['openssl','snp']}
sev = { path="../virtee-sev", default-features = false, features = ['openssl', 'snp']}
nix = "^0.23"
serde = { version = "1.0", features = ["derive"] }
bincode = "^1.2.1"
Expand Down
38 changes: 22 additions & 16 deletions src/certs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use openssl::x509::X509;
pub struct CertPaths {
pub ark_path: PathBuf,
pub ask_path: PathBuf,
pub vcek_path: PathBuf,
pub vek_path: PathBuf,
}
#[derive(StructOpt, Clone, Copy)]
pub enum CertFormat {
Expand Down Expand Up @@ -103,9 +103,18 @@ pub fn convert_path_to_cert(
impl TryFrom<CertPaths> for Chain {
type Error = anyhow::Error;
fn try_from(content: CertPaths) -> Result<Self, Self::Error> {
let ark_cert = convert_path_to_cert(&content.ark_path, "ark")?;
let ask_cert = convert_path_to_cert(&content.ask_path, "ask")?;
let vcek_cert = convert_path_to_cert(&content.vcek_path, "vcek")?;
let ark_cert: Certificate = convert_path_to_cert(&content.ark_path, "ark")?;
let ask_cert: Certificate = convert_path_to_cert(&content.ask_path, "ask")?;
let vek_cert: Certificate = if content
.vek_path
.to_string_lossy()
.to_lowercase()
.contains("vlek")
{
convert_path_to_cert(&content.vek_path, "vlek")?
} else {
convert_path_to_cert(&content.vek_path, "vcek")?
};

let ca_chain = ca::Chain {
ark: ark_cert,
Expand All @@ -114,7 +123,7 @@ impl TryFrom<CertPaths> for Chain {

Ok(Chain {
ca: ca_chain,
vcek: vcek_cert,
vek: vek_cert,
})
}
}
Expand Down Expand Up @@ -196,23 +205,20 @@ pub fn get_ext_certs(args: CertificatesArgs) -> Result<()> {
.get_ext_report(None, Some(request_data), None)
.context("Failed to get extended report.")?;

// Check if the returned table is empty
if certificates.is_empty() {
return Err(anyhow::anyhow!(
"The certificate chain is empty! Certificates probably not loaded by the host."
));
}

// Create certificate directory if missing
if !args.certs_dir.exists() {
fs::create_dir(args.certs_dir.clone()).context("Could not create certs folder")?;
};

// Write certs into directory
for cert in certificates.iter() {
let path = args.certs_dir.clone();
// If certificates are present, write certs into directory
if let Some(ref certificates) = certificates {
for cert in certificates.iter() {
let path = args.certs_dir.clone();

write_cert(path, &cert.cert_type, &cert.data, args.encoding)?;
write_cert(path, &cert.cert_type, &cert.data, args.encoding)?;
}
} else {
eprintln!("No certificates were loaded by the host...");
}

Ok(())
Expand Down
87 changes: 61 additions & 26 deletions src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use super::*;

use certs::{convert_path_to_cert, CertPaths};

use std::{io::ErrorKind, path::PathBuf};
use std::{
io::ErrorKind,
path::{Path, PathBuf},
};

use openssl::{ecdsa::EcdsaSig, sha::Sha384};
use sev::certs::snp::Chain;
Expand All @@ -27,7 +30,7 @@ pub fn cmd(cmd: VerifyCmd, quiet: bool) -> Result<()> {
}

// Find a certificate in specified directory according to its extension
pub fn find_cert_in_dir(dir: PathBuf, cert: &str) -> Result<PathBuf, anyhow::Error> {
pub fn find_cert_in_dir(dir: &Path, cert: &str) -> Result<PathBuf, anyhow::Error> {
if dir.join(format!("{cert}.pem")).exists() {
Ok(dir.join(format!("{cert}.pem")))
} else if dir.join(format!("{cert}.der")).exists() {
Expand All @@ -50,21 +53,28 @@ mod certificate_chain {

// Function to validate certificate chain
pub fn validate_cc(args: Args, quiet: bool) -> Result<()> {
let ark_path = find_cert_in_dir(args.certs_dir.clone(), "ark")?;
let ask_path = find_cert_in_dir(args.certs_dir.clone(), "ask")?;
let vcek_path = find_cert_in_dir(args.certs_dir, "vcek")?;
let ark_path = find_cert_in_dir(&args.certs_dir, "ark")?;
let ask_path = find_cert_in_dir(&args.certs_dir, "ask")?;
let mut vek_type: &str = "vcek";
let vek_path = match find_cert_in_dir(&args.certs_dir, "vlek") {
Ok(vlek_path) => {
vek_type = "vlek";
vlek_path
}
Err(_) => find_cert_in_dir(&args.certs_dir, "vcek")?,
};

// Get a cert chain from directory
let cert_chain: Chain = CertPaths {
ark_path,
ask_path,
vcek_path,
vek_path,
}
.try_into()?;

let ark = cert_chain.ca.ark;
let ask = cert_chain.ca.ask;
let vcek = cert_chain.vcek;
let vek = cert_chain.vek;

// Verify each signature and print result in console
match (&ark, &ark).verify() {
Expand Down Expand Up @@ -98,22 +108,19 @@ mod certificate_chain {
},
}

match (&ask, &vcek).verify() {
match (&ask, &vek).verify() {
Ok(()) => {
if !quiet {
println!("The VCEK was signed by the AMD ASK!");
println!("The {vek_type} was signed by the AMD ASK!");
}
}
Err(e) => match e.kind() {
ErrorKind::Other => {
return Err(anyhow::anyhow!("The VCEK was not signed by the AMD ASK!"))
}
_ => {
return Err(anyhow::anyhow!(
"Failed to verify VCEK certificate: {:?}",
e
"The {vek_type} was not signed by the AMD ASK!"
))
}
_ => return Err(anyhow::anyhow!("Failed to verify VEK certificate: {:?}", e)),
},
}
Ok(())
Expand All @@ -125,9 +132,12 @@ mod attestation {

use asn1_rs::{oid, FromDer, Oid};

use x509_parser::{self, certificate::X509Certificate, prelude::X509Extension};
use x509_parser::{self, certificate::X509Certificate, prelude::X509Extension, x509::X509Name};

use sev::{certs::snp::Certificate, firmware::guest::AttestationReport};
use sev::{
certs::snp::Certificate,
firmware::{guest::AttestationReport, host::CertType},
};

enum SnpOid {
BootLoader,
Expand Down Expand Up @@ -244,6 +254,27 @@ mod attestation {
}
}

fn parse_common_name(field: &X509Name<'_>) -> Result<CertType> {
if let Some(val) = field
.iter_common_name()
.next()
.and_then(|cn| cn.as_str().ok())
{
match val {
x if x.contains("ark") => Ok(CertType::ARK),
x if x.contains("ask") => Ok(CertType::ASK),
x if x.contains("vcek") => Ok(CertType::VCEK),
x if x.contains("vlek") => Ok(CertType::VLEK),
x if x.contains("crl") => Ok(CertType::CRL),
_ => Err(anyhow::anyhow!("Unknown certificate type encountered!")),
}
} else {
Err(anyhow::anyhow!(
"Certificate Subject Common Name is Unknown!"
))
}
}

fn verify_attestation_tcb(
vcek: Certificate,
att_report: AttestationReport,
Expand All @@ -258,6 +289,8 @@ mod attestation {
.extensions_map()
.context("Failed getting VCEK oids.")?;

let common_name: CertType = parse_common_name(vcek_x509.subject())?;

// Compare bootloaders
if let Some(cert_bl) = extensions.get(&SnpOid::BootLoader.oid()) {
if !check_cert_bytes(cert_bl, &att_report.reported_tcb.bootloader.to_le_bytes()) {
Expand Down Expand Up @@ -308,15 +341,17 @@ mod attestation {
}
}

// Compare HWID information
if let Some(cert_hwid) = extensions.get(&SnpOid::HwId.oid()) {
if !check_cert_bytes(cert_hwid, &att_report.chip_id) {
return Err(anyhow::anyhow!(
"Report TCB ID and Certificate ID mismatch encountered."
));
}
if !quiet {
println!("Chip ID from certificate matches the attestation report.");
// Compare HWID information only on VCEK
if common_name == CertType::VCEK {
if let Some(cert_hwid) = extensions.get(&SnpOid::HwId.oid()) {
if !check_cert_bytes(cert_hwid, &att_report.chip_id) {
return Err(anyhow::anyhow!(
"Report TCB ID and Certificate ID mismatch encountered."
));
}
if !quiet {
println!("Chip ID from certificate matches the attestation report.");
}
}
}

Expand All @@ -333,7 +368,7 @@ mod attestation {
};

// Get VCEK and grab its public key
let vcek_path = find_cert_in_dir(args.certs_dir, "vcek")?;
let vcek_path = find_cert_in_dir(&args.certs_dir, "vcek")?;
let vcek = convert_path_to_cert(&vcek_path, "vcek")?;

if args.tcb || args.signature {
Expand Down

0 comments on commit 864d3e3

Please sign in to comment.