use crate::{
error::{FirmwareError, SevError},
firmware::host::Version,
parser::{Decoder, Encoder},
util::{TypeLoad, TypeSave},
};
#[cfg(target_os = "linux")]
use crate::launch::linux::ioctl::*;
#[cfg(target_os = "linux")]
use crate::launch::linux::{sev::*, shared::*};
use crate::*;
use std::{convert::TryFrom, mem::MaybeUninit, os::unix::io::AsRawFd, result::Result};
use bitflags::bitflags;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub struct New;
pub struct Started(Handle);
pub struct Measured(Handle, Measurement);
pub struct Finished;
pub struct Launcher<T, U: AsRawFd, V: AsRawFd> {
state: T,
vm_fd: U,
sev: V,
}
impl<T, U: AsRawFd, V: AsRawFd> Launcher<T, U, V> {
pub fn as_mut_vmfd(&mut self) -> &mut U {
&mut self.vm_fd
}
}
impl<U: AsRawFd, V: AsRawFd> Launcher<New, U, V> {
pub fn new(kvm: U, sev: V) -> Result<Self, FirmwareError> {
let mut launcher = Launcher {
vm_fd: kvm,
sev,
state: New,
};
let init = Init2::init_default_sev();
let mut cmd = Command::from(&launcher.sev, &init);
INIT2
.ioctl(&mut launcher.vm_fd, &mut cmd)
.map_err(|_| cmd.encapsulate())?;
Ok(launcher)
}
pub fn new_es(kvm: U, sev: V) -> Result<Self, FirmwareError> {
let mut launcher = Launcher {
vm_fd: kvm,
sev,
state: New,
};
let init = Init2::init_default_es();
let mut cmd = Command::from(&launcher.sev, &init);
INIT2
.ioctl(&mut launcher.vm_fd, &mut cmd)
.map_err(|_| cmd.encapsulate())?;
Ok(launcher)
}
pub fn start(mut self, start: Start) -> Result<Launcher<Started, U, V>, FirmwareError> {
let mut launch_start = LaunchStart::new(&start.policy, &start.cert, &start.session);
let mut cmd = Command::from_mut(&self.sev, &mut launch_start);
LAUNCH_START
.ioctl(&mut self.vm_fd, &mut cmd)
.map_err(|_| cmd.encapsulate())?;
let next = Launcher {
state: Started(launch_start.into()),
vm_fd: self.vm_fd,
sev: self.sev,
};
Ok(next)
}
}
impl<U: AsRawFd, V: AsRawFd> Launcher<Started, U, V> {
pub fn update_data(&mut self, data: &[u8]) -> Result<(), FirmwareError> {
let launch_update_data = LaunchUpdateData::new(data);
let mut cmd = Command::from(&self.sev, &launch_update_data);
KvmEncRegion::new(data).register(&mut self.vm_fd)?;
LAUNCH_UPDATE_DATA
.ioctl(&mut self.vm_fd, &mut cmd)
.map_err(|_| cmd.encapsulate())?;
Ok(())
}
pub fn register_kvm_enc_region(&mut self, data: &[u8]) -> Result<(), FirmwareError> {
KvmEncRegion::new(data).register(&mut self.vm_fd)?;
Ok(())
}
pub fn update_data_without_registration(&mut self, data: &[u8]) -> Result<(), FirmwareError> {
let launch_update_data = LaunchUpdateData::new(data);
let mut cmd = Command::from(&self.sev, &launch_update_data);
LAUNCH_UPDATE_DATA
.ioctl(&mut self.vm_fd, &mut cmd)
.map_err(|_| cmd.encapsulate())?;
Ok(())
}
pub fn update_vmsa(&mut self) -> Result<(), FirmwareError> {
let launch_update_vmsa = LaunchUpdateVmsa::new();
let mut cmd = Command::from(&self.sev, &launch_update_vmsa);
LAUNCH_UPDATE_VMSA
.ioctl(&mut self.vm_fd, &mut cmd)
.map_err(|_| cmd.encapsulate())?;
Ok(())
}
pub fn measure(mut self) -> Result<Launcher<Measured, U, V>, FirmwareError> {
let mut measurement = MaybeUninit::uninit();
let mut launch_measure = LaunchMeasure::new(&mut measurement);
let mut cmd = Command::from_mut(&self.sev, &mut launch_measure);
LAUNCH_MEASUREMENT
.ioctl(&mut self.vm_fd, &mut cmd)
.map_err(|_| cmd.encapsulate())?;
let next = Launcher {
state: Measured(self.state.0, unsafe { measurement.assume_init() }),
vm_fd: self.vm_fd,
sev: self.sev,
};
Ok(next)
}
}
impl<U: AsRawFd, V: AsRawFd> Launcher<Measured, U, V> {
pub fn measurement(&self) -> Measurement {
self.state.1
}
pub fn inject(&mut self, secret: &Secret, guest: usize) -> Result<(), FirmwareError> {
let launch_secret = LaunchSecret::new(&secret.header, guest, &secret.ciphertext[..]);
let mut cmd = Command::from(&self.sev, &launch_secret);
LAUNCH_SECRET
.ioctl(&mut self.vm_fd, &mut cmd)
.map_err(|_| cmd.encapsulate())?;
Ok(())
}
pub fn finish(mut self) -> Result<Handle, FirmwareError> {
let mut cmd = Command::from(&self.sev, &LaunchFinish);
LAUNCH_FINISH
.ioctl(&mut self.vm_fd, &mut cmd)
.map_err(|_| cmd.encapsulate())?;
Ok(self.state.0)
}
pub fn finish_attestable(mut self) -> Result<Launcher<Finished, U, V>, FirmwareError> {
let mut cmd = Command::from(&self.sev, &LaunchFinish);
LAUNCH_FINISH
.ioctl(&mut self.vm_fd, &mut cmd)
.map_err(|_| cmd.encapsulate())?;
let next = Launcher {
state: Finished,
vm_fd: self.vm_fd,
sev: self.sev,
};
Ok(next)
}
}
impl<U: AsRawFd, V: AsRawFd> Launcher<Finished, U, V> {
pub fn report(&mut self, mnonce: [u8; 16]) -> Result<Vec<u8>, FirmwareError> {
let mut first = LaunchAttestation::default();
let mut cmd = Command::from_mut(&self.sev, &mut first);
let mut len = 0;
let e = LAUNCH_ATTESTATION
.ioctl(&mut self.vm_fd, &mut cmd)
.map_err(|_| cmd.encapsulate());
if let Err(err) = e {
if let FirmwareError::KnownSevError(SevError::InvalidLen) = err {
len = first.len;
} else {
return Err(err)?;
}
}
let mut bytes = vec![0u8; usize::try_from(len).unwrap()];
let mut second = LaunchAttestation::new(mnonce, &mut bytes);
cmd = Command::from_mut(&self.sev, &mut second);
LAUNCH_ATTESTATION
.ioctl(&mut self.vm_fd, &mut cmd)
.map_err(|_| cmd.encapsulate())?;
Ok(bytes)
}
}
bitflags! {
#[derive(Copy, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct PolicyFlags: u16 {
const NO_DEBUG = 0b00000001u16.to_le();
const NO_KEY_SHARING = 0b00000010u16.to_le();
const ENCRYPTED_STATE = 0b00000100u16.to_le();
const NO_SEND = 0b00001000u16.to_le();
const DOMAIN = 0b00010000u16.to_le();
const SEV = 0b00100000u16.to_le();
}
}
#[cfg(feature = "serde")]
impl Serialize for PolicyFlags {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut flags = 0u16;
if self.contains(PolicyFlags::NO_DEBUG) {
flags |= PolicyFlags::NO_DEBUG.bits();
}
if self.contains(PolicyFlags::NO_KEY_SHARING) {
flags |= PolicyFlags::NO_KEY_SHARING.bits();
}
if self.contains(PolicyFlags::ENCRYPTED_STATE) {
flags |= PolicyFlags::ENCRYPTED_STATE.bits();
}
if self.contains(PolicyFlags::NO_SEND) {
flags |= PolicyFlags::NO_SEND.bits();
}
if self.contains(PolicyFlags::DOMAIN) {
flags |= PolicyFlags::DOMAIN.bits();
}
if self.contains(PolicyFlags::SEV) {
flags |= PolicyFlags::SEV.bits();
}
serializer.serialize_u16(flags)
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for PolicyFlags {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let flags = u16::deserialize(deserializer)?;
let flags = PolicyFlags::from_bits_truncate(flags);
Ok(flags)
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct Policy {
pub flags: PolicyFlags,
pub minfw: Version,
}
impl From<u32> for Policy {
fn from(p: u32) -> Self {
let flags = p as u16;
let flags = PolicyFlags::from_bits_truncate(flags);
let p = p >> 16;
let p = p as u16;
let minfw = Version::from(p);
Self { flags, minfw }
}
}
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Session {
pub nonce: [u8; 16],
pub wrap_tk: [u8; 32],
pub wrap_iv: [u8; 16],
pub wrap_mac: [u8; 32],
pub policy_mac: [u8; 32],
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Start {
pub policy: Policy,
pub cert: certs::sev::sev::Certificate,
pub session: Session,
}
impl Decoder<()> for Start {
fn decode(reader: &mut impl Read, _: ()) -> std::io::Result<Self> {
reader.load()
}
}
impl Encoder<()> for Start {
fn encode(&self, writer: &mut impl Write, _: ()) -> std::io::Result<()> {
writer.save(self)
}
}
bitflags! {
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct HeaderFlags: u32 {
const COMPRESSED = 0b00000001u32.to_le();
}
}
#[cfg(feature = "serde")]
impl Serialize for HeaderFlags {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut flags = 0u32;
if self.contains(HeaderFlags::COMPRESSED) {
flags |= HeaderFlags::COMPRESSED.bits();
}
serializer.serialize_u32(flags)
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for HeaderFlags {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let flags = u32::deserialize(deserializer)?;
let flags = HeaderFlags::from_bits_truncate(flags);
Ok(flags)
}
}
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Header {
pub flags: HeaderFlags,
pub iv: [u8; 16],
pub mac: [u8; 32],
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Secret {
pub header: Header,
pub ciphertext: Vec<u8>,
}
impl Decoder<()> for Secret {
fn decode(reader: &mut impl Read, _: ()) -> std::io::Result<Self> {
let header = reader.load()?;
let mut ciphertext = vec![];
let _ = reader.read_to_end(&mut ciphertext)?;
Ok(Self { header, ciphertext })
}
}
impl Encoder<()> for Secret {
fn encode(&self, writer: &mut impl Write, _: ()) -> std::io::Result<()> {
writer.save(&self.header)?;
writer.write_all(&self.ciphertext)
}
}
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Measurement {
pub measure: [u8; 32],
pub mnonce: [u8; 16],
}
impl Decoder<()> for Measurement {
fn decode(reader: &mut impl Read, _: ()) -> std::io::Result<Self> {
reader.load()
}
}
impl Encoder<()> for Measurement {
fn encode(&self, writer: &mut impl Write, _: ()) -> std::io::Result<()> {
writer.save(self)
}
}