Skip to content

Commit

Permalink
feat: configuration for attestation
Browse files Browse the repository at this point in the history
Signed-off-by: Richard Zak <[email protected]>
  • Loading branch information
rjzak committed Nov 9, 2022
1 parent 5fb350a commit 3bae6ca
Show file tree
Hide file tree
Showing 9 changed files with 280 additions and 5 deletions.
25 changes: 25 additions & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions crates/sgx_validation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ description = "Intel SGX Attestation validation library for Steward"
cryptography = { path = "../cryptography" }
anyhow = { version = "^1.0.55", default-features = false }
der = { version = "0.6", features = ["std"], default-features = false }
hex = "0.4"
serde = { version = "1.0", features = ["derive", "std"] }
sgx = { version = "0.5.0", default-features = false }

[dev-dependencies]
testaso = { version = "0.1", default-features = false }
toml = "0.5"
74 changes: 74 additions & 0 deletions crates/sgx_validation/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-FileCopyrightText: 2022 Profian Inc. <[email protected]>
// SPDX-License-Identifier: AGPL-3.0-only

use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize};

#[derive(Clone, Deserialize, Debug, Default, Serialize)]
struct Config {
/// Values for `mrsigner` in the report body.
/// This is the list of public keys which have signed the `enarx` binary.
#[serde(default)]
#[serde(deserialize_with = "from_hex")]
enarx_signer: Option<Vec<Vec<u8>>>,

/// Values allowed for `cpusvn`.
cpu_svn: Option<Vec<u8>>,

/// Value for `isv_svn`, do not allow versions below this.
enclave_security_version: Option<u16>,
}

fn from_hex<'de, D>(deserializer: D) -> Result<Option<Vec<Vec<u8>>>, D::Error>
where
D: Deserializer<'de>,
{
let s: Vec<&str> = match Deserialize::deserialize(deserializer) {
Ok(x) => x,
Err(_) => return Ok(None),
};

let mut outer_vec = Vec::new();
for hash_string in s {
outer_vec.push(hex::decode(hash_string).map_err(|_| Error::custom("invalid hex"))?);
}

Ok(Some(outer_vec))
}

#[cfg(test)]
mod tests {
use crate::config::Config;

#[test]
fn test_empty_config() {
let config_raw = r#"
something_else = 1
"#;

let config_obj: Config = toml::from_str(config_raw).expect("Couldn't deserialize");
assert!(config_obj.enarx_signer.is_none());
assert!(config_obj.enclave_security_version.is_none());
assert!(config_obj.cpu_svn.is_none());
}

#[test]
fn test_list_of_hashes() {
let config_raw = r#"
enarx_signer = ["1234567890", "00112233445566778899"]
"#;

let config_obj: Config = toml::from_str(config_raw).expect("Couldn't deserialize");
assert!(config_obj.enarx_signer.is_some());
assert_eq!(config_obj.enarx_signer.clone().unwrap().len(), 2);
assert_eq!(
config_obj.enarx_signer.clone().unwrap().first().unwrap(),
&hex::decode("1234567890").unwrap()
);
assert_eq!(
config_obj.enarx_signer.unwrap().get(1).unwrap(),
&hex::decode("00112233445566778899").unwrap()
);
assert!(config_obj.cpu_svn.is_none());
}
}
5 changes: 3 additions & 2 deletions crates/sgx_validation/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// SPDX-FileCopyrightText: 2022 Profian Inc. <[email protected]>
// SPDX-License-Identifier: AGPL-3.0-only

mod quote;
pub mod config;
pub mod quote;

use cryptography::ext::*;
use quote::traits::ParseBytes;
Expand Down Expand Up @@ -29,7 +30,7 @@ impl Sgx {
pub const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.58270.1.2");
pub const ATT: bool = true;

fn trusted<'c>(&'c self, chain: &'c [Certificate<'c>]) -> Result<&'c TbsCertificate<'c>> {
pub fn trusted<'c>(&'c self, chain: &'c [Certificate<'c>]) -> Result<&'c TbsCertificate<'c>> {
let mut signer = &self.0[0].tbs_certificate;
for cert in self.0.iter().chain(chain.iter()) {
signer = signer.verify_crt(cert)?;
Expand Down
46 changes: 46 additions & 0 deletions crates/sgx_validation/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use cryptography;
use cryptography::x509::attr::Attribute;
use cryptography::x509::request::{CertReq, ExtensionReq};
use cryptography::x509::Certificate;
use der::Decode;
use sgx_validation::quote::traits::ParseBytes;
use sgx_validation::quote::Quote;
use sgx_validation::Sgx;
use std::env;
use std::fs::File;
use std::io::Read;
use std::path::Path;

fn main() {
let args: Vec<String> = env::args().collect();
let fname = Path::new(args.get(1).expect("CSR file not specified"));
let mut file = File::open(fname).expect("no such file");
let mut contents = Vec::new();
file.read_to_end(&mut contents)
.expect("failed to read file");

let cr = CertReq::from_der(&contents).expect("failed to decode DER");
let cri = cr.info;
#[allow(unused_variables)]
for Attribute { oid, values } in cri.attributes.iter() {
for any in values.iter() {
let ereq: ExtensionReq<'_> = any.decode_into().unwrap();
for ext in Vec::from(ereq) {
let (quote, bytes): (Quote<'_>, _) =
ext.extn_value.parse().expect("failed to parse");
let chain = quote.chain().unwrap();
let chain = chain
.iter()
.map(|c| Certificate::from_der(c))
.collect::<Result<Vec<_>, _>>()
.unwrap();

// Validate the report.
let sgx = Sgx::default();
let pck = sgx.trusted(&chain).unwrap();
let report = quote.verify(pck).unwrap();
println!("{:?}", report);
}
}
}
}
2 changes: 2 additions & 0 deletions crates/snp_validation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ cryptography = { path = "../cryptography" }
anyhow = { version = "^1.0.55", default-features = false }
der = { version = "0.6", features = ["std"], default-features = false }
flagset = { version = "0.4.3", default-features = false}
serde = { version = "1.0", features = ["derive"] }

[dev-dependencies]
testaso = { version = "0.1", default-features = false }
toml = "0.5"
84 changes: 84 additions & 0 deletions crates/snp_validation/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// SPDX-FileCopyrightText: 2022 Profian Inc. <[email protected]>
// SPDX-License-Identifier: AGPL-3.0-only

use crate::{PlatformInfoFlags, PolicyFlags};
use flagset::FlagSet;
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize};

#[derive(Clone, Deserialize, Debug, Default, Serialize)]
struct Config {
#[serde(default)]
#[serde(deserialize_with = "from_policy_string")]
policy_flags: Option<u8>,
platform_info_flags: Option<Vec<PlatformInfoFlags>>,
}

fn from_policy_string<'de, D>(deserializer: D) -> Result<Option<u8>, D::Error>
where
D: Deserializer<'de>,
{
let s: &str = match Deserialize::deserialize(deserializer) {
Ok(x) => x,
Err(_) => return Ok(None),
};

let mut flags = FlagSet::<PolicyFlags>::from(PolicyFlags::Reserved);

eprintln!("String: {}", s);

for flag in s.to_string().split("|") {
match flag.trim() {
"Debug" => {
flags = flags | PolicyFlags::Debug;
}
"MigrateMA" => {
flags = flags | PolicyFlags::MigrateMA;
}
"SingleSocket" => {
flags = flags | PolicyFlags::SingleSocket;
}
"SMT" => {
flags = flags | PolicyFlags::SMT;
}
_ => return Err(D::Error::custom(format!("unknown flag '{}'", flag))),
}
}

Ok(Some(flags.bits()))
}

#[cfg(test)]
mod tests {
use crate::config::Config;
use crate::PolicyFlags;
use flagset::FlagSet;

#[test]
fn test_empty_config() {
let config_raw = r#"
something_else = 1
"#;

let config_obj: Config = toml::from_str(config_raw).expect("Couldn't deserialize");
assert!(config_obj.policy_flags.is_none());
assert!(config_obj.platform_info_flags.is_none());
}

#[test]
fn test_flags() {
let config_raw = r#"
policy_flags = "SingleSocket | Debug"
"#;

let config_obj: Config = toml::from_str(config_raw).expect("Couldn't deserialize");
assert!(config_obj.policy_flags.is_some());
assert!(config_obj.platform_info_flags.is_none());

let flags = FlagSet::<PolicyFlags>::new(config_obj.policy_flags.unwrap()).unwrap();
assert_eq!(
flags,
PolicyFlags::SingleSocket | PolicyFlags::Debug | PolicyFlags::Reserved
);
}
}
11 changes: 8 additions & 3 deletions crates/snp_validation/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: 2022 Profian Inc. <[email protected]>
// SPDX-License-Identifier: AGPL-3.0-only

pub mod config;

use cryptography::ext::*;

use std::{fmt::Debug, mem::size_of};
Expand All @@ -16,6 +18,7 @@ use cryptography::x509::{PkiPath, TbsCertificate};
use der::asn1::UIntRef;
use der::{Decode, Encode, Sequence};
use flagset::{flags, FlagSet};
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, PartialEq, Eq, Sequence)]
pub struct Evidence<'a> {
Expand All @@ -26,6 +29,7 @@ pub struct Evidence<'a> {
}

flags! {
#[derive(Deserialize, Serialize)]
pub enum PolicyFlags: u8 {
/// Indicates if only one socket is permitted
SingleSocket = 1 << 4,
Expand All @@ -39,6 +43,7 @@ flags! {
SMT = 1 << 0,
}

#[derive(Deserialize, Serialize)]
pub enum PlatformInfoFlags: u8 {
TSME = 1 << 1,
SMT = 1 << 0,
Expand Down Expand Up @@ -69,7 +74,7 @@ pub struct PlatformInfo {

#[repr(C, packed)]
#[derive(Copy, Clone, Debug)]
struct Body {
pub struct Body {
/// The version of the attestation report, currently 2
pub version: u32,
/// Guest Security Version Number (SVN)
Expand Down Expand Up @@ -178,15 +183,15 @@ impl Es384 {

#[repr(C, packed)]
#[derive(Copy, Clone)]
union Signature {
pub union Signature {
bytes: [u8; 512],
es384: Es384,
}

/// The attestation report from the trusted environment on an AMD system
#[repr(C, packed)]
#[derive(Copy, Clone)]
struct Report {
pub struct Report {
pub body: Body,
pub signature: Signature,
}
Expand Down
35 changes: 35 additions & 0 deletions crates/snp_validation/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use cryptography;
use cryptography::x509::attr::Attribute;
use cryptography::x509::request::{CertReq, ExtensionReq};
use der::Decode;
use snp_validation;
use snp_validation::Evidence;
use snp_validation::Report;
use std::env;
use std::fs::File;
use std::io::Read;
use std::path::Path;

fn main() {
let args: Vec<String> = env::args().collect();
let fname = Path::new(args.get(1).expect("CSR file not specified"));
let mut file = File::open(fname).expect("no such file");
let mut contents = Vec::new();
file.read_to_end(&mut contents)
.expect("failed to read file");

let cr = CertReq::from_der(&contents).expect("failed to decode DER");
let cri = cr.info;
#[allow(unused_variables)]
for Attribute { oid, values } in cri.attributes.iter() {
for any in values.iter() {
let ereq: ExtensionReq<'_> = any.decode_into().unwrap();
for ext in Vec::from(ereq) {
let evidence = Evidence::from_der(ext.extn_value).unwrap();
let array = evidence.report.try_into().unwrap();
let report = Report::cast(array);
println!("{:?}", report);
}
}
}
}

0 comments on commit 3bae6ca

Please sign in to comment.