Skip to content

Commit

Permalink
Fixed testing to have comprehensive testing for the library
Browse files Browse the repository at this point in the history
Several bugs caught when trying to run cargo test with different
feature combinations. Fixed these bugs and made some slight tweaks to be
able to run comprehensive testing on the library.

- When running cargo test with dangerous_hw_tests enabled both has_sev
  and has_sev_guest tests were run leading to a failure. Fixed by
removing an unecessary or
- Renamed has_sev to host and renamed has_sev_guest to guest
- ID-BLOCK had to be put behind openssl only
- Changed snp_config test to hit only the IOCTL and not modify the
  config. This was done to avoid messing up system configs during
testing.
- Renamed the launch test to sev_launch test. This allows us to test
  that launch test individually.
- Added code to create a legacy SEV cert-chain locally. This allows us
  to test the SEV launch test without the need of an external tool.
- Cached Turin certificates to the SEV builtin certs and the SNP builtin
  certs.

Signed-off-by: DGonzalezVillal <Diego.GonzalezVillalobos@amd.com>
  • Loading branch information
DGonzalezVillal committed Nov 25, 2024
1 parent 1fe938f commit bce36bb
Show file tree
Hide file tree
Showing 15 changed files with 1,234 additions and 179 deletions.
1,115 changes: 1,047 additions & 68 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ doc = false
default = ["sev", "snp"]
openssl = ["dep:openssl", "dep:rdrand"]
hw_tests = []
dangerous_hw_tests = ["hw_tests"]
dangerous_hw_tests = ["hw_tests", "dep:reqwest", "dep:tokio"]
sev = []
snp = []
crypto_nossl = ["dep:p384", "dep:rsa", "dep:sha2", "dep:x509-cert"]
Expand Down Expand Up @@ -70,6 +70,8 @@ x509-cert = { version = "0.2.5", optional = true }
byteorder = "1.4.3"
base64 = "0.22.1"
rdrand = { version = "^0.8", optional = true }
reqwest = { version="0.11.10", features = ["blocking"], optional = true }
tokio = {version = "1.29.1", features =["rt-multi-thread"], optional = true }

[target.'cfg(target_os = "linux")'.dev-dependencies]
kvm-ioctls = ">=0.16"
Expand Down
12 changes: 6 additions & 6 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ fn main() {
use std::path::Path;

// Add in configurations to be checked within the code.
println!("cargo::rustc-check-cfg=cfg(has_sev)");
println!("cargo::rustc-check-cfg=cfg(has_sev_guest)");
println!("cargo::rustc-check-cfg=cfg(host)");
println!("cargo::rustc-check-cfg=cfg(guest)");

if cfg!(feature = "hw_tests") || Path::new("/dev/sev").exists() {
println!("cargo:rustc-cfg=has_sev");
if Path::new("/dev/sev").exists() {
println!("cargo:rustc-cfg=host");
}

if cfg!(feature = "hw_tests") || Path::new("/dev/sev-guest").exists() {
println!("cargo:rustc-cfg=has_sev_guest");
if Path::new("/dev/sev-guest").exists() {
println!("cargo:rustc-cfg=guest");
}
}
1 change: 1 addition & 0 deletions src/certs/sev/builtin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ pub mod genoa;
pub mod milan;
pub mod naples;
pub mod rome;
pub mod turin;
Binary file added src/certs/sev/builtin/turin/ark.cert
Binary file not shown.
Binary file added src/certs/sev/builtin/turin/ask.cert
Binary file not shown.
14 changes: 14 additions & 0 deletions src/certs/sev/builtin/turin/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: Apache-2.0

//! AMD's TURIN certificates.
//!
//! Certificate provenance: <https://developer.amd.com/wp-content/resources/ask_ark_turin.cert>
//!
//! For convenience, the certificate chain has been split into individual
//! certificates and are embedded here as byte slices.
/// The public Turin ARK certificate.
pub const ARK: &[u8] = include_bytes!("ark.cert");

/// The public Turin ASK certificate.
pub const ASK: &[u8] = include_bytes!("ask.cert");
2 changes: 1 addition & 1 deletion src/certs/snp/builtin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub mod genoa;
/// Milan generation.
pub mod milan;

/// TURIN generation
/// Turin generation
pub mod turin;

use super::*;
20 changes: 20 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ pub mod vmsa;
/// Error module.
pub mod error;

#[cfg(all(feature = "sev", feature = "dangerous_hw_tests"))]
pub use util::cached_chain;
use util::{TypeLoad, TypeSave};

Expand Down Expand Up @@ -269,6 +270,10 @@ pub enum Generation {
/// Fourth generation EPYC (SEV, SEV-ES, SEV-SNP).
#[cfg(any(feature = "sev", feature = "snp"))]
Genoa,

/// Fifth generation EPYC (SEV, SEV-ES, SEV-SNP).
#[cfg(any(feature = "sev", feature = "snp"))]
Turin,
}

#[cfg(all(feature = "sev", feature = "openssl"))]
Expand All @@ -285,6 +290,8 @@ impl From<Generation> for CertSevCaChain {
Generation::Milan => (SevBuiltin::milan::ARK, SevBuiltin::milan::ASK),
#[cfg(any(feature = "sev", feature = "snp"))]
Generation::Genoa => (SevBuiltin::genoa::ARK, SevBuiltin::genoa::ASK),
#[cfg(any(feature = "sev", feature = "snp"))]
Generation::Turin => (SevBuiltin::turin::ARK, SevBuiltin::turin::ASK),
};

CertSevCaChain {
Expand All @@ -306,6 +313,10 @@ impl From<Generation> for CertSnpCaChain {
SnpBuiltin::genoa::ark().unwrap(),
SnpBuiltin::genoa::ask().unwrap(),
),
Generation::Turin => (
SnpBuiltin::turin::ark().unwrap(),
SnpBuiltin::turin::ask().unwrap(),
),
};

CertSnpCaChain { ark, ask }
Expand All @@ -323,6 +334,7 @@ impl TryFrom<&sev::Chain> for Generation {
let rome: CertSevCaChain = Generation::Rome.into();
let milan: CertSevCaChain = Generation::Milan.into();
let genoa: CertSevCaChain = Generation::Genoa.into();
let turin: CertSevCaChain = Generation::Turin.into();

Ok(if (&naples.ask, &schain.cek).verify().is_ok() {
Generation::Naples
Expand All @@ -332,6 +344,8 @@ impl TryFrom<&sev::Chain> for Generation {
Generation::Milan
} else if (&genoa.ask, &schain.cek).verify().is_ok() {
Generation::Genoa
} else if (&turin.ask, &schain.cek).verify().is_ok() {
Generation::Turin
} else {
return Err(());
})
Expand Down Expand Up @@ -362,6 +376,9 @@ impl TryFrom<String> for Generation {
#[cfg(any(feature = "sev", feature = "snp"))]
"siena" => Ok(Self::Genoa),

#[cfg(any(feature = "sev", feature = "snp"))]
"turin" => Ok(Self::Turin),

_ => Err(()),
}
}
Expand All @@ -383,6 +400,9 @@ impl Generation {

#[cfg(any(feature = "sev", feature = "snp"))]
Self::Genoa => "Genoa".to_string(),

#[cfg(any(feature = "sev", feature = "snp"))]
Self::Turin => "Turin".to_string(),
}
}
}
Expand Down
83 changes: 67 additions & 16 deletions src/util/cached_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,31 @@
//! An entire certificate chain can be created using the `sevctl`
//! utility.
#[cfg(feature = "sev")]
use crate::certs::sev::Chain;
#![cfg(all(feature = "sev", feature = "dangerous_hw_tests"))]

#[cfg(feature = "openssl")]
use crate::{
certs::sev::{ca::Chain as CaChain, Chain as FullChain},
firmware::host::Firmware,
sev::Certificate,
Generation,
};

#[cfg(feature = "openssl")]
use reqwest::{
blocking::{get, Response},
StatusCode,
};

use std::{
env,
path::{Path, PathBuf},
};

#[cfg(feature = "sev")]
use std::{
fs::File,
io::{ErrorKind, Result},
};
#[cfg(feature = "openssl")]
use std::io::Cursor;

#[cfg(feature = "sev")]
#[cfg(feature = "openssl")]
use codicon::Decoder;

fn append_rest<P: AsRef<Path>>(path: P) -> PathBuf {
Expand Down Expand Up @@ -67,13 +77,54 @@ pub fn path() -> Vec<PathBuf> {
.collect()
}

/// Searches for and decodes an SEV certificate chain.
#[cfg(feature = "sev")]
pub fn get() -> Result<Chain> {
let not_found: std::io::Error = ErrorKind::NotFound.into();
/// Remove any certificates that may have been chached to reset
/// testing for SEV APIS.
pub fn rm_cached_chain() {
let paths = path();
if let Some(path) = paths.first() {
if path.exists() {
std::fs::remove_file(path).unwrap();
}
}
}

/// Request CEK certificate from AMD KDS and generate a full chain.
#[cfg(all(feature = "sev", feature = "openssl"))]
pub fn get_chain() -> FullChain {
use std::convert::TryFrom;

let mut firmware = Firmware::open().unwrap();

let paths: Vec<_> = path().into_iter().filter(|p| p.exists()).collect();
let file_name = paths.first().ok_or(not_found)?;
let mut file = File::open(file_name)?;
Chain::decode(&mut file, ())
const CEK_SVC: &str = "https://kdsintf.amd.com/cek/id";

let mut sev_chain = firmware.pdh_cert_export().unwrap();

let id = firmware.get_identifier().unwrap();

let url = format!("{}/{}", CEK_SVC, id);

// VCEK in DER format
let vcek_rsp: Response = get(url).expect("Failed to get CEK certificate");

let cek_resp_bytes = match vcek_rsp.status() {
StatusCode::OK => {
let vcek_rsp_bytes: Vec<u8> = vcek_rsp.bytes().unwrap().to_vec();
vcek_rsp_bytes
}
_ => panic!("Cek request returned an error"),
};

// Create a Cursor around the byte vector
let cursor = Cursor::new(cek_resp_bytes);

sev_chain.cek = Certificate::decode(cursor, ()).expect("Failed to decode CEK cert");

let ca_chain: CaChain = Generation::try_from(&sev_chain)
.expect("Failed to generate SEV CA chain")
.into();

FullChain {
ca: ca_chain,
sev: sev_chain,
}
}
Loading

0 comments on commit bce36bb

Please sign in to comment.