From ec7a7370b1c84b56e97fac9b82a02d3dcbdb9e03 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Tue, 23 Jul 2024 16:29:01 -0400 Subject: [PATCH] messages WIP --- Cargo.lock | 12 ++ Cargo.toml | 1 + attest-data/Cargo.toml | 1 + attest-data/src/lib.rs | 2 + attest-data/src/messages.rs | 288 ++++++++++++++++++++++++++++++++++++ dice-cert-tmpl/src/csr.rs | 12 +- dice-cert-tmpl/src/lib.rs | 2 +- dice-mfg-msgs/src/lib.rs | 6 +- verifier-cli/src/main.rs | 7 + 9 files changed, 321 insertions(+), 10 deletions(-) create mode 100644 attest-data/src/messages.rs diff --git a/Cargo.lock b/Cargo.lock index 1225490..57745b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,6 +120,7 @@ dependencies = [ "hubpack", "salty", "serde", + "serde_repr", "serde_with", "sha3", "thiserror", @@ -1206,6 +1207,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + [[package]] name = "serde_with" version = "3.7.0" diff --git a/Cargo.toml b/Cargo.toml index cac28e5..b29f4cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ ron = "0.8" rpassword = "7.3.1" salty = { version = "0.3", default-features = false } serde = { version = "1", default-features = false } +serde_repr = { version = "0.1", default-features = false } serde-big-array = "0.5" serde_json = { version = "1", features = ["std", "alloc"] } serde_with = { version = "3.6", default-features = false } diff --git a/attest-data/Cargo.toml b/attest-data/Cargo.toml index 497f49f..bb8f619 100644 --- a/attest-data/Cargo.toml +++ b/attest-data/Cargo.toml @@ -9,6 +9,7 @@ hubpack.workspace = true thiserror = { workspace = true, optional = true } salty.workspace = true serde = { workspace = true, features = ["derive"] } +serde_repr.workspace = true serde_with = { workspace = true, features = ["macros"] } sha3.workspace = true diff --git a/attest-data/src/lib.rs b/attest-data/src/lib.rs index c5cef73..3d8c04f 100644 --- a/attest-data/src/lib.rs +++ b/attest-data/src/lib.rs @@ -13,6 +13,8 @@ use sha3::{ Sha3_256Core, }; +pub mod messages; + #[cfg(feature = "std")] use thiserror::Error; diff --git a/attest-data/src/messages.rs b/attest-data/src/messages.rs new file mode 100644 index 0000000..e8f2c14 --- /dev/null +++ b/attest-data/src/messages.rs @@ -0,0 +1,288 @@ +use crate::NONCE_SIZE; +use hubpack::SerializedSize; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; + +use hubpack::error::Error as HubpackError; + +/// Magic value for [`Header::magic`] +pub const ATTEST_MAGIC: u32 = 0xA77E5700; + +/// Right now `Attest` is the only command that takes data (nonce) +pub const MAX_DATA_LEN: usize = NONCE_SIZE; + +pub const MAX_REQUEST_SIZE: usize = + HostRotHeader::MAX_SIZE + HostToRotCommand::MAX_SIZE + MAX_DATA_LEN; + +pub mod version { + pub const V1: u32 = 1; +} + +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, SerializedSize, +)] +pub struct HostRotHeader { + magic: u32, + version: u32, +} + +impl Default for HostRotHeader { + fn default() -> Self { + Self::new() + } +} + +impl HostRotHeader { + pub fn new() -> Self { + Self { + magic: ATTEST_MAGIC, + version: version::V1, + } + } +} + +#[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + Deserialize, + Serialize, + SerializedSize, +)] +#[repr(u32)] +pub enum HostToRotCommand { + /// Returns the certificate chain associated with the RoT + GetCertificates = 0, + /// Returns the measurement log + GetMeasurementLog = 1, + /// Calculates sign(sha3_256(hubpack(measurement_log) | nonce)) + /// and returns the result. + Attest = 2, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] +//#[repr(u32)] +pub enum HostToRotError { + _Unused, + /// Header magic was incorrect + MagicMismatch, + /// Mismatch of protocol versions + VersionMismatch, + /// Message failed to deserialize + Deserialize, + /// Wrong length of data arguments (expected no data or incorrect length) + IncorrectDataLen, + /// Unexpected command returned + UnexpectedCommand, + /// Error return from the sprot command + SprotError(SprotError), +} + +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Deserialize_repr, Serialize_repr, +)] +#[repr(u32)] +// Errors returned from the hubris side. This is _so many_ +pub enum SprotError { + // protocol + /// CRC check failed. + ProtocolInvalidCrc, + /// FIFO overflow/underflow + ProtocolFlowError, + /// Unsupported protocol version + ProtocolUnsupportedProtocol, + /// Unknown message + ProtocolBadMessageType, + /// Transfer size is outside of maximum and minimum lenghts for message type. + ProtocolBadMessageLength, + // We cannot assert chip select + ProtocolCannotAssertCSn, + // The request timed out + ProtocolTimeout, + // Hubpack error + ProtocolDeserialization, + // The RoT has not de-asserted ROT_IRQ + ProtocolRotIrqRemainsAsserted, + // An unexpected response was received. + // This should basically be impossible. We only include it so we can + // return this error when unpacking a RspBody in idol calls. + ProtocolUnexpectedResponse, + // Failed to load update status + ProtocolBadUpdateStatus, + // Used for mapping From + ProtocolTaskRestarted, + // The SP and RoT did not agree on whether the SP is sending + // a request or waiting for a reply. + ProtocolDesynchronized, + + // Spi + SpiBadTransferSize, + SpiTaskRestarted, + + // Update -- this should not get returned + UpdateError, + // Sprockets is deprecated but we still keep the error type + SprocketsError, + // Watchdog error, we should not get this + WatchdogError, + + // Attest errors + AttestCertTooBig, + AttestInvalidCertIndex, + AttestNoCerts, + AttestOutOfRange, + AttestLogFull, + AttestLogTooBig, + AttestTaskRestarted, + AttestBadLease, + AttestUnsupportedAlgorithm, + AttestSerializeLog, + AttestSerializeSignature, + AttestSignatureTooBig, +} + +impl From for HostToRotError { + fn from(_: HubpackError) -> Self { + Self::Deserialize + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] +pub enum RotToHost { + HostToRotError(HostToRotError), + RotCertificates, + RotMeasurementLog, + RotAttestation, +} + +impl From for RotToHost { + fn from(e: SprotError) -> Self { + RotToHost::HostToRotError(HostToRotError::SprotError(e)) + } +} + +pub fn deserialize( + data: &[u8], +) -> Result<(HostRotHeader, T, &[u8]), HostToRotError> { + let (header, leftover) = hubpack::deserialize::(data)?; + let (command, leftover) = hubpack::deserialize::(leftover)?; + + Ok((header, command, leftover)) +} + +pub fn parse_message( + buf: &[u8], +) -> Result<(HostToRotCommand, &[u8]), HostToRotError> { + let (header, command, leftover) = deserialize::(buf)?; + + if header.magic != ATTEST_MAGIC { + return Err(HostToRotError::MagicMismatch); + } + + if header.version != version::V1 { + return Err(HostToRotError::VersionMismatch); + } + + match command { + // These commands don't take data + HostToRotCommand::GetCertificates + | HostToRotCommand::GetMeasurementLog => { + if !leftover.is_empty() { + return Err(HostToRotError::IncorrectDataLen); + } + } + HostToRotCommand::Attest => { + if leftover.len() != NONCE_SIZE { + return Err(HostToRotError::IncorrectDataLen); + } + } + } + + Ok((command, leftover)) +} + +pub fn parse_response( + buf: &[u8], + expected: RotToHost, +) -> Result<&[u8], HostToRotError> { + let (header, command, leftover) = deserialize::(buf)?; + + if header.magic != ATTEST_MAGIC { + return Err(HostToRotError::MagicMismatch); + } + + if header.version != version::V1 { + return Err(HostToRotError::VersionMismatch); + } + + if command != expected { + return Err(HostToRotError::UnexpectedCommand); + } + Ok(leftover) +} + +fn raw_serialize( + out: &mut [u8], + header: &HostRotHeader, + command: &S, + fill_data: F, +) -> Result +where + F: FnOnce(&mut [u8]) -> Result, + S: Serialize, +{ + let header_len = hubpack::serialize(out, header)?; + let mut n = header_len; + + let out_data_end = out.len(); + + n += hubpack::serialize(&mut out[n..out_data_end], command)?; + + match fill_data(&mut out[n..out_data_end]) { + Ok(data_this_message) => { + assert!(data_this_message <= out_data_end - n); + n += data_this_message; + } + Err(e) => { + n = header_len; + n += hubpack::serialize(&mut out[n..out_data_end], &e)?; + } + } + + Ok(n) +} + +pub fn try_serialize( + out: &mut [u8], + command: &S, + fill_data: F, +) -> Result +where + F: FnOnce(&mut [u8]) -> Result, + S: Serialize, +{ + let header = HostRotHeader { + magic: ATTEST_MAGIC, + version: version::V1, + }; + + raw_serialize(out, &header, command, fill_data) +} + +pub fn serialize( + out: &mut [u8], + command: &impl Serialize, + fill_data: F, +) -> Result +where + F: FnOnce(&mut [u8]) -> usize, +{ + let header = HostRotHeader { + magic: ATTEST_MAGIC, + version: version::V1, + }; + + raw_serialize(out, &header, command, |buf| Ok(fill_data(buf))) +} diff --git a/dice-cert-tmpl/src/csr.rs b/dice-cert-tmpl/src/csr.rs index a3a357c..6f5bdb1 100644 --- a/dice-cert-tmpl/src/csr.rs +++ b/dice-cert-tmpl/src/csr.rs @@ -166,7 +166,7 @@ mod tests { ]; #[rustfmt::skip] - const PUB: &'static [u8] = &[ + const PUB: &[u8] = &[ 0x27, 0xfb, 0x87, 0x77, 0x77, 0x36, 0x54, 0xfb, 0x78, 0xb3, 0x46, 0x6b, 0x95, 0x0e, 0x15, 0x2b, 0x8b, 0xcd, 0x0c, 0x9b, 0x8a, 0x08, 0xfc, 0x7a, @@ -174,7 +174,7 @@ mod tests { ]; #[rustfmt::skip] - const SIG: &'static [u8] = &[ + const SIG: &[u8] = &[ 0xf5, 0xf5, 0xcf, 0xde, 0x58, 0x87, 0x6a, 0x0e, 0xa6, 0xb3, 0x3f, 0x23, 0x98, 0xd6, 0x97, 0x0c, 0x3a, 0xaa, 0xb2, 0xdf, 0xa0, 0x6e, 0x5b, 0xf7, @@ -186,7 +186,7 @@ mod tests { ]; #[rustfmt::skip] - const SIGNDATA: &'static [u8] = &[ + const SIGNDATA: &[u8] = &[ 0x30, 0x81, 0x90, 0x02, 0x01, 0x00, 0x30, 0x5d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x10, 0x30, @@ -210,7 +210,7 @@ mod tests { #[test] fn get_pub_offsets() -> Result { - let mut csr = CSR.clone(); + let mut csr = CSR; let csr = Csr::from_slice(&mut csr); let (start, end) = csr.get_pub_offsets()?; assert_eq!(&csr.as_bytes()[start..end], PUB); @@ -219,7 +219,7 @@ mod tests { #[test] fn get_sig_offsets() -> Result { - let mut csr = CSR.clone(); + let mut csr = CSR; let csr = Csr::from_slice(&mut csr); let (start, end) = csr.get_sig_offsets()?; assert_eq!(&csr.as_bytes()[start..end], SIG); @@ -228,7 +228,7 @@ mod tests { #[test] fn get_signdata_offsets() -> Result { - let mut csr = CSR.clone(); + let mut csr = CSR; let csr = Csr::from_slice(&mut csr); let (start, end) = csr.get_signdata_offsets()?; assert_eq!(&csr.as_bytes()[start..end], SIGNDATA); diff --git a/dice-cert-tmpl/src/lib.rs b/dice-cert-tmpl/src/lib.rs index 7e06912..2f1a505 100644 --- a/dice-cert-tmpl/src/lib.rs +++ b/dice-cert-tmpl/src/lib.rs @@ -180,7 +180,7 @@ pub fn write_range( mod tests { use super::*; - const DATA: &'static [u8] = &[0xca, 0xfe, 0xba, 0xbe, 0xca, 0xfe]; + const DATA: &[u8] = &[0xca, 0xfe, 0xba, 0xbe, 0xca, 0xfe]; #[test] fn get_pattern_offset_none() { diff --git a/dice-mfg-msgs/src/lib.rs b/dice-mfg-msgs/src/lib.rs index 4c97de7..85acb15 100644 --- a/dice-mfg-msgs/src/lib.rs +++ b/dice-mfg-msgs/src/lib.rs @@ -206,7 +206,7 @@ fn platform_id_from_0xv2(s: &str) -> Result { bytes[PLATFORM_ID_V1_PREFIX.len()..16] .copy_from_slice(&s[PLATFORM_ID_V2_PREFIX.len()..16]); - bytes[16..20].copy_from_slice(&[b':', b'R', b'R', b'R']); + bytes[16..20].copy_from_slice(b":RRR"); // copy ':SN' bytes[20..32].copy_from_slice(&s[20..32]); @@ -404,14 +404,14 @@ mod tests { #[test] fn rfd308_v2_good() -> Result { - assert!(!validate_0xv2(RFD308_V2_GOOD).is_err()); + assert!(validate_0xv2(RFD308_V2_GOOD).is_ok()); Ok(()) } #[test] fn pid_v1_good() -> Result { - assert!(!validate_pdv1(PID_V1_GOOD).is_err()); + assert!(validate_pdv1(PID_V1_GOOD).is_ok()); Ok(()) } diff --git a/verifier-cli/src/main.rs b/verifier-cli/src/main.rs index 5defc3e..be96634 100644 --- a/verifier-cli/src/main.rs +++ b/verifier-cli/src/main.rs @@ -41,6 +41,13 @@ struct Args { verbose: bool, } +#[derive(Debug, Clone, ValueEnum, Parser)] +enum HostCmd { + Certs, + Log, + Attest, +} + /// An enum of the HIF operations supported by the `Attest` interface. #[derive(Debug, Subcommand)] enum AttestCommand {