use super::*;
use sev::firmware::guest::{DerivedKey, Firmware, GuestFieldSelect};
use std::io::Read;
use std::{fs, path::PathBuf};
#[derive(Parser)]
pub struct KeyArgs {
#[arg(value_name = "key-path", required = true)]
pub key_path: PathBuf,
#[arg(value_name = "root-key-select", required = true, ignore_case = true)]
pub root_key_select: String,
#[arg(short, long, value_name = "vmpl", default_value = "1")]
pub vmpl: Option<u32>,
#[arg(short, long = "guest_field_select", value_name = "######")]
pub gfs: Option<String>,
#[arg(short = 's', long = "guest_svn")]
pub gsvn: Option<u32>,
#[arg(short, long = "tcb_version")]
pub tcbv: Option<u64>,
}
pub fn get_derived_key(args: KeyArgs) -> Result<()> {
let root_key_select = match args.root_key_select.as_str() {
"vcek" => false,
"vmrk" => true,
_ => return Err(anyhow::anyhow!("Invalid input. Enter either vcek or vmrk")),
};
let vmpl = match args.vmpl {
Some(level) => {
if level <= 3 {
level
} else {
return Err(anyhow::anyhow!("Invalid Virtual Machine Privilege Level."));
}
}
None => 1,
};
let gfs = match args.gfs {
Some(gfs) => {
let value: u64 = u64::from_str_radix(gfs.as_str(), 2).unwrap();
if value <= 63 {
value
} else {
return Err(anyhow::anyhow!("Invalid Guest Field Select option."));
}
}
None => 0,
};
let gsvn: u32 = args.gsvn.unwrap_or(0);
let tcbv: u64 = args.tcbv.unwrap_or(0);
let request = DerivedKey::new(root_key_select, GuestFieldSelect(gfs), vmpl, gsvn, tcbv);
let mut sev_fw = Firmware::open().context("failed to open SEV firmware device.")?;
let derived_key: [u8; 32] = sev_fw
.get_derived_key(None, request)
.context("Failed to request derived key")?;
let key_path: PathBuf = args.key_path;
let mut key_file = if key_path.exists() {
std::fs::OpenOptions::new()
.write(true)
.truncate(true)
.open(key_path)
.context("Unable to overwrite derived key file contents")?
} else {
fs::File::create(key_path).context("Unable to create derived key file contents")?
};
bincode::serialize_into(&mut key_file, &derived_key)
.context("Could not serialize derived key into file.")?;
Ok(())
}
pub fn read_key(key_path: PathBuf) -> Result<Vec<u8>, anyhow::Error> {
let mut key_file = fs::File::open(key_path)?;
let mut key = Vec::new();
key_file.read_to_end(&mut key)?;
Ok(key)
}