Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/bin/appraiser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use log::{debug, info};
use sha2::{Digest, Sha256};
use std::{fs, net::TcpStream, os::unix::net::UnixStream, path::PathBuf};
use vm_attest::{
QualifyingData, RotType, VmInstanceAttestation, VmInstanceConf,
VmInstanceRot,
QualifyingData, RotType, VmInstanceAttestation, VmInstanceAttester,
VmInstanceConf,
socket::{VmInstanceRotSocketClient, VmInstanceTcp},
vsock::VmInstanceRotVsockClient,
};
Expand Down
8 changes: 4 additions & 4 deletions src/bin/vm-instance-rot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::{fs, os::unix::net::UnixListener, path::PathBuf};
use vsock::{VsockAddr, VsockListener};

use vm_attest::{
VmInstanceConf, mock::VmInstanceRotMock, socket::VmInstanceRotSocketServer,
VmInstanceConf, VmInstanceRot, socket::VmInstanceRotSocketServer,
vsock::VmInstanceRotVsockServer,
};

Expand Down Expand Up @@ -83,7 +83,7 @@ fn main() -> Result<()> {
debug!("creating instance of VmInstanceAttestMock");
// instantiate an `AttestMock` w/ the Oxide platform RoT instance requested
// by the caller & the config
let attest = VmInstanceRotMock::new(oxide_platform_rot, instance_cfg);
let rot = VmInstanceRot::new(oxide_platform_rot, instance_cfg);

match args.socket_type {
SocketType::Unix { sock } => {
Expand All @@ -96,15 +96,15 @@ fn main() -> Result<()> {
.context("failed to bind to socket")?;
debug!("listening on socket file: {}", sock.display());

Ok(VmInstanceRotSocketServer::new(attest, listener).run()?)
Ok(VmInstanceRotSocketServer::new(rot, listener).run()?)
}
SocketType::Vsock { cid, port } => {
debug!("binding to vsock cid:port: ({cid}, {port})");
let listener = VsockListener::bind(&VsockAddr::new(cid, port))
.with_context(|| format!("bind to cid,pid: ({cid},{port})"))?;
debug!("listening on cid,port: ({cid},{port})");

Ok(VmInstanceRotVsockServer::new(attest, listener).run()?)
Ok(VmInstanceRotVsockServer::new(rot, listener).run()?)
}
}
}
9 changes: 5 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ use sha2::{
use std::{error, fmt, str};
use uuid::Uuid;

pub mod mock;
mod rot;
pub use rot::{VmInstanceRot, VmInstanceRotError};
pub mod socket;
#[cfg(feature = "vsock")]
pub mod vsock;
Expand Down Expand Up @@ -123,8 +124,8 @@ pub struct MeasurementLog {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct VmInstanceConf {
pub uuid: Uuid,
#[serde(rename = "image-digest")]
pub image_digest: Option<Measurement>,
#[serde(rename = "boot-digest")]
pub boot_digest: Option<Measurement>,
}

#[derive(Debug, Deserialize, Serialize)]
Expand Down Expand Up @@ -167,7 +168,7 @@ pub enum Response {

/// An interface for obtaining attestations and supporting data from the VM
/// Instance RoT
pub trait VmInstanceRot {
pub trait VmInstanceAttester {
type Error: error::Error + fmt::Debug;

/// Get an attestation from each of the RoTs resident on the host platform
Expand Down
23 changes: 13 additions & 10 deletions src/mock.rs → src/rot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ use x509_cert::der::Encode;

use crate::{
MeasurementLog, QualifyingData, RotType, VmInstanceAttestation,
VmInstanceConf, VmInstanceRot,
VmInstanceAttester, VmInstanceConf,
};

/// Errors returned when trying to sign an attestation
#[derive(Debug, thiserror::Error)]
pub enum VmInstanceRotMockError {
pub enum VmInstanceRotError {
#[error("error encoding cert as DER")]
DerEncodeError(#[from] x509_cert::der::Error),
#[error("error deserializing data")]
Expand All @@ -34,19 +34,19 @@ pub enum VmInstanceRotMockError {
}

/// This type mocks the `propolis` process that backs a VM.
pub struct VmInstanceRotMock {
pub struct VmInstanceRot {
oxattest_mock: Box<dyn OxAttest>,
log: VmInstanceConf,
}

impl VmInstanceRotMock {
impl VmInstanceRot {
pub fn new(oxattest_mock: Box<dyn OxAttest>, log: VmInstanceConf) -> Self {
Self { oxattest_mock, log }
}
}

impl VmInstanceRot for VmInstanceRotMock {
type Error = VmInstanceRotMockError;
impl VmInstanceAttester for VmInstanceRot {
type Error = VmInstanceRotError;

/// `propolis` receives qualifying data from the caller. It then combines
/// this data w/ attributes describing the VM (rootfs, instance UUID etc)
Expand Down Expand Up @@ -113,8 +113,11 @@ impl VmInstanceRot for VmInstanceRotMock {

#[cfg(test)]
mod test {
use crate::{mock::*, *};
use dice_verifier::{AttestMock as OxAttestMock, Nonce};
use crate::*;
use dice_verifier::{
AttestMock as OxAttestMock, Attestation as OxAttestation, Log, Nonce,
};
use sha2::{Digest, Sha256};
use std::fs;
use x509_cert::{Certificate, der::Decode};

Expand All @@ -125,7 +128,7 @@ mod test {
}

/// Pull in test data generated by build.rs & create mock RoT-Rs
fn setup() -> VmInstanceRotMock {
fn setup() -> VmInstanceRot {
let oxattest = Box::new(
OxAttestMock::load(
config::SIGNER_PKIPATH,
Expand All @@ -141,7 +144,7 @@ mod test {
let instance_cfg: VmInstanceConf = serde_json::from_str(&instance_cfg)
.expect("parse JSON from mock cfg for instance RoT");

VmInstanceRotMock::new(oxattest, instance_cfg)
VmInstanceRot::new(oxattest, instance_cfg)
}

fn mock_qualifying_data() -> QualifyingData {
Expand Down
28 changes: 14 additions & 14 deletions src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ use std::{
};

use crate::{
QualifyingData, Request, Response, VmInstanceAttestation, VmInstanceRot,
mock::{VmInstanceRotMock, VmInstanceRotMockError},
QualifyingData, Request, Response, VmInstanceAttestation,
VmInstanceAttester,
rot::{VmInstanceRot, VmInstanceRotError},
};

/// the maximum length of a message that we'll accept from clients
Expand Down Expand Up @@ -52,7 +53,7 @@ pub enum VmInstanceRotSocketClientError {
VmInstanceRot(String),
}

impl VmInstanceRot for VmInstanceRotSocketClient {
impl VmInstanceAttester for VmInstanceRotSocketClient {
type Error = VmInstanceRotSocketClientError;

/// Turn the `QualifyingData` provided into a JSON message that we send
Expand All @@ -77,7 +78,6 @@ impl VmInstanceRot for VmInstanceRotSocketClient {
reader.read_line(&mut response)?;

debug!("got response: {response}");
// map `Response` to `Result<PlatformAttestation, Self::Error>`
let response: Response = serde_json::from_str(&response)?;
match response {
Response::Attest(p) => Ok(p),
Expand All @@ -90,15 +90,15 @@ impl VmInstanceRot for VmInstanceRotSocketClient {
/// `QualifyingData` from the `VmInstanceRotSocketClient`. The `QualifyingData`
/// is then passed to an instance of the `VmInstanceRotMock`.
pub struct VmInstanceRotSocketServer {
mock: VmInstanceRotMock,
rot: VmInstanceRot,
listener: UnixListener,
}

/// Possible errors from `VmInstanceAttestSocketServer::run`
#[derive(Debug, thiserror::Error)]
pub enum VmInstanceRotSocketRunError {
#[error("error from underlying VmInstanceRoT mock")]
MockRotError(#[from] VmInstanceRotMockError),
MockRotError(#[from] VmInstanceRotError),

#[error("failed to deserialize QualifyingData request from JSON")]
Request(serde_json::Error),
Expand All @@ -111,8 +111,8 @@ pub enum VmInstanceRotSocketRunError {
}

impl VmInstanceRotSocketServer {
pub fn new(mock: VmInstanceRotMock, listener: UnixListener) -> Self {
Self { mock, listener }
pub fn new(rot: VmInstanceRot, listener: UnixListener) -> Self {
Self { rot, listener }
}

// message handling loop
Expand Down Expand Up @@ -175,8 +175,8 @@ impl VmInstanceRotSocketServer {
Request::Attest(q) => {
debug!("qualifying data received: {q:?}");
// NOTE: We do not contribute to the `QualifyingData`
// here. The self.mock impl will handle this for us.
match self.mock.attest(&q) {
// here. The self.rot impl will handle this for us.
match self.rot.attest(&q) {
Ok(a) => Response::Attest(a),
Err(e) => Response::Error(e.to_string()),
}
Expand Down Expand Up @@ -206,7 +206,7 @@ pub enum VmInstanceAttestDataResponse {

/// Possible errors from `VmInstanceAttestSocketServer::run`
#[derive(Debug, thiserror::Error)]
pub enum VmInstanceTcpServerError<T: VmInstanceRot> {
pub enum VmInstanceTcpServerError<T: VmInstanceAttester> {
#[error("failed to deserialize QualifyingData request from JSON")]
Request(serde_json::Error),

Expand All @@ -217,7 +217,7 @@ pub enum VmInstanceTcpServerError<T: VmInstanceRot> {
Socket(#[from] std::io::Error),

#[error("error from the underlying VmInstanceRot")]
VmInstanceRotError(<T as VmInstanceRot>::Error),
VmInstanceRotError(<T as VmInstanceAttester>::Error),
}

/// This type wraps a TcpListener accepting JSON encoded `QualifyingData` from
Expand All @@ -227,12 +227,12 @@ pub enum VmInstanceTcpServerError<T: VmInstanceRot> {
/// This `QualifyingData` is then sent down to the `VmInstanceRot` by way of the
/// `vm_instance_rot` member.
#[derive(Debug)]
pub struct VmInstanceTcpServer<T: VmInstanceRot> {
pub struct VmInstanceTcpServer<T: VmInstanceAttester> {
challenge_listener: TcpListener,
vm_instance_rot: T,
}

impl<T: VmInstanceRot> VmInstanceTcpServer<T> {
impl<T: VmInstanceAttester> VmInstanceTcpServer<T> {
pub fn new(challenge_listener: TcpListener, vm_instance_rot: T) -> Self {
Self {
challenge_listener,
Expand Down
21 changes: 11 additions & 10 deletions src/vsock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ use std::{
use vsock::{VsockListener, VsockStream};

use crate::{
QualifyingData, Request, Response, VmInstanceAttestation, VmInstanceRot,
mock::{VmInstanceRotMock, VmInstanceRotMockError},
QualifyingData, Request, Response, VmInstanceAttestation,
VmInstanceAttester,
rot::{VmInstanceRot, VmInstanceRotError},
};

/// the maximum length of a message that we'll accept from clients
Expand All @@ -22,14 +23,14 @@ const MAX_LINE_LENGTH: usize = 1024;
/// connections on a vsock. It receives JSON messages that encode the sole
/// parameter to the `VmInstanceRot::attest` function.
pub struct VmInstanceRotVsockServer {
mock: VmInstanceRotMock,
rot: VmInstanceRot,
listener: VsockListener,
}

#[derive(Debug, thiserror::Error)]
pub enum VmInstanceRotVsockError {
#[error("error from underlying VmInstanceRoT mock")]
MockRotError(#[from] VmInstanceRotMockError),
#[error("error from underlying VmInstanceRoT")]
MockRotError(#[from] VmInstanceRotError),

#[error("error deserializing Command from JSON")]
Request(serde_json::Error),
Expand All @@ -42,8 +43,8 @@ pub enum VmInstanceRotVsockError {
}

impl VmInstanceRotVsockServer {
pub fn new(mock: VmInstanceRotMock, listener: VsockListener) -> Self {
Self { mock, listener }
pub fn new(rot: VmInstanceRot, listener: VsockListener) -> Self {
Self { rot, listener }
}

// message handling loop
Expand Down Expand Up @@ -107,8 +108,8 @@ impl VmInstanceRotVsockServer {
Request::Attest(q) => {
debug!("qualifying data received: {q:?}");
// NOTE: We do not contribute to the `QualifyingData`
// here. The self.mock impl will handle this for us.
match self.mock.attest(&q) {
// here. The self.rot impl will handle this for us.
match self.rot.attest(&q) {
Ok(a) => Response::Attest(a),
Err(e) => Response::Error(e.to_string()),
}
Expand Down Expand Up @@ -154,7 +155,7 @@ pub enum VmInstanceRotVsockClientError {
VmInstanceRotError(String),
}

impl VmInstanceRot for VmInstanceRotVsockClient {
impl VmInstanceAttester for VmInstanceRotVsockClient {
type Error = VmInstanceRotVsockClientError;

fn attest(
Expand Down
Loading