diff --git a/src/bin/appraiser.rs b/src/bin/appraiser.rs index 82c75cd..e7498c7 100644 --- a/src/bin/appraiser.rs +++ b/src/bin/appraiser.rs @@ -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, }; diff --git a/src/bin/vm-instance-rot.rs b/src/bin/vm-instance-rot.rs index 4d4e6d7..980ed07 100644 --- a/src/bin/vm-instance-rot.rs +++ b/src/bin/vm-instance-rot.rs @@ -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, }; @@ -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 } => { @@ -96,7 +96,7 @@ 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})"); @@ -104,7 +104,7 @@ fn main() -> Result<()> { .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()?) } } } diff --git a/src/lib.rs b/src/lib.rs index b9caa0e..a032a57 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; @@ -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, + #[serde(rename = "boot-digest")] + pub boot_digest: Option, } #[derive(Debug, Deserialize, Serialize)] @@ -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 diff --git a/src/mock.rs b/src/rot.rs similarity index 96% rename from src/mock.rs rename to src/rot.rs index e64fe95..bd5e64f 100644 --- a/src/mock.rs +++ b/src/rot.rs @@ -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")] @@ -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, log: VmInstanceConf, } -impl VmInstanceRotMock { +impl VmInstanceRot { pub fn new(oxattest_mock: Box, 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) @@ -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}; @@ -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, @@ -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 { diff --git a/src/socket.rs b/src/socket.rs index 354b79f..6f279cd 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -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 @@ -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 @@ -77,7 +78,6 @@ impl VmInstanceRot for VmInstanceRotSocketClient { reader.read_line(&mut response)?; debug!("got response: {response}"); - // map `Response` to `Result` let response: Response = serde_json::from_str(&response)?; match response { Response::Attest(p) => Ok(p), @@ -90,7 +90,7 @@ 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, } @@ -98,7 +98,7 @@ pub struct VmInstanceRotSocketServer { #[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), @@ -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 @@ -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()), } @@ -206,7 +206,7 @@ pub enum VmInstanceAttestDataResponse { /// Possible errors from `VmInstanceAttestSocketServer::run` #[derive(Debug, thiserror::Error)] -pub enum VmInstanceTcpServerError { +pub enum VmInstanceTcpServerError { #[error("failed to deserialize QualifyingData request from JSON")] Request(serde_json::Error), @@ -217,7 +217,7 @@ pub enum VmInstanceTcpServerError { Socket(#[from] std::io::Error), #[error("error from the underlying VmInstanceRot")] - VmInstanceRotError(::Error), + VmInstanceRotError(::Error), } /// This type wraps a TcpListener accepting JSON encoded `QualifyingData` from @@ -227,12 +227,12 @@ pub enum VmInstanceTcpServerError { /// This `QualifyingData` is then sent down to the `VmInstanceRot` by way of the /// `vm_instance_rot` member. #[derive(Debug)] -pub struct VmInstanceTcpServer { +pub struct VmInstanceTcpServer { challenge_listener: TcpListener, vm_instance_rot: T, } -impl VmInstanceTcpServer { +impl VmInstanceTcpServer { pub fn new(challenge_listener: TcpListener, vm_instance_rot: T) -> Self { Self { challenge_listener, diff --git a/src/vsock.rs b/src/vsock.rs index d67515b..5ab9a48 100644 --- a/src/vsock.rs +++ b/src/vsock.rs @@ -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 @@ -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), @@ -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 @@ -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()), } @@ -154,7 +155,7 @@ pub enum VmInstanceRotVsockClientError { VmInstanceRotError(String), } -impl VmInstanceRot for VmInstanceRotVsockClient { +impl VmInstanceAttester for VmInstanceRotVsockClient { type Error = VmInstanceRotVsockClientError; fn attest(