diff --git a/Cargo.toml b/Cargo.toml index 38e4bcf..0f644ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ simple_logger = "1" yaml-rust = "0.4" zeroize = "1.4" data-encoding = "2.3" +enum-iterator = "2.0" # Used by 'awskms' and 'gcpkms' futures = { version = "^0.3", optional = true } diff --git a/benches/roughenough-bench.rs b/benches/roughenough-bench.rs index 20865e2..cd9c513 100644 --- a/benches/roughenough-bench.rs +++ b/benches/roughenough-bench.rs @@ -9,6 +9,7 @@ use criterion::Throughput::Elements; use roughenough::merkle::MerkleTree; use roughenough::{RtMessage, Tag}; use roughenough::key::OnlineKey; +use roughenough::version::Version; fn create_signed_srep_tags(c: &mut Criterion) { let mut group = c.benchmark_group("signing"); @@ -18,7 +19,7 @@ fn create_signed_srep_tags(c: &mut Criterion) { group.throughput(Elements(1)); group.bench_function("create signed SREP tag", |b| { let now = SystemTime::now(); - b.iter(|| black_box(key.make_srep(now, data.as_ref()))) + b.iter(|| black_box(key.make_srep(Version::Rfc, now, data.as_ref(), ))) }); group.finish(); } diff --git a/src/bin/roughenough-client.rs b/src/bin/roughenough-client.rs index d36db2e..d757704 100644 --- a/src/bin/roughenough-client.rs +++ b/src/bin/roughenough-client.rs @@ -82,17 +82,17 @@ fn make_request(ver: Version, nonce: &Nonce, text_dump: bool) -> Vec { msg.encode().unwrap() } Version::Rfc => { - msg.add_field(Tag::PAD_RFC, &[]).unwrap(); msg.add_field(Tag::VER, ver.wire_bytes()).unwrap(); msg.add_field(Tag::NONC, nonce).unwrap(); + msg.add_field(Tag::ZZZZ, &[]).unwrap(); let padding_needed = msg.calculate_padding_length(); let padding: Vec = (0..padding_needed).map(|_| 0).collect(); msg.clear(); - msg.add_field(Tag::PAD_RFC, &padding).unwrap(); msg.add_field(Tag::VER, ver.wire_bytes()).unwrap(); msg.add_field(Tag::NONC, nonce).unwrap(); + msg.add_field(Tag::ZZZZ, &padding).unwrap(); if text_dump { eprintln!("Request = {}", msg); diff --git a/src/key/online.rs b/src/key/online.rs index 5663c95..3c9ac45 100644 --- a/src/key/online.rs +++ b/src/key/online.rs @@ -22,6 +22,7 @@ use crate::message::RtMessage; use crate::sign::Signer; use crate::SIGNED_RESPONSE_CONTEXT; use crate::tag::Tag; +use crate::version::Version; /// /// Represents the delegated Roughtime ephemeral online key. @@ -57,26 +58,42 @@ impl OnlineKey { dele_msg } + /// Classic protocol, epoch time in microseconds + fn classic_midp(&self, now: SystemTime) -> u64 { + let d = now + .duration_since(UNIX_EPOCH) + .expect("duration since epoch"); + let secs = d.as_secs() * 1_000_000; + let nsecs = (d.subsec_nanos() as u64) / 1_000; + + secs + nsecs + } + + /// RFC protocol, a uint64 count of seconds since the Unix epoch in UTC. + fn rfc_midp(&self, now: SystemTime) -> u64 { + now.duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() + } + /// Create an SREP response containing the provided time and Merkle root, /// signed by this online key. - pub fn make_srep(&mut self, now: SystemTime, merkle_root: &[u8]) -> RtMessage { + pub fn make_srep(&mut self, ver: Version, now: SystemTime, merkle_root: &[u8]) -> RtMessage { let mut radi = [0; 4]; let mut midp = [0; 8]; - // one second (in microseconds) + let radi_time = match ver { + Version::Classic => 1_000_000, // one second in microseconds + Version::Rfc => 1, // one second + }; + (&mut radi as &mut [u8]) - .write_u32::(1_000_000) + .write_u32::(radi_time) .unwrap(); - // current epoch time in microseconds - let midp_time = { - let d = now - .duration_since(UNIX_EPOCH) - .expect("duration since epoch"); - let secs = d.as_secs() * 1_000_000; - let nsecs = (d.subsec_nanos() as u64) / 1_000; - - secs + nsecs + let midp_time = match ver { + Version::Classic => self.classic_midp(now), + Version::Rfc => self.rfc_midp(now), }; (&mut midp as &mut [u8]) diff --git a/src/responder.rs b/src/responder.rs index 471ed3b..245bb48 100644 --- a/src/responder.rs +++ b/src/responder.rs @@ -98,7 +98,7 @@ impl Responder { let merkle_root = self.merkle.compute_root(); // The SREP tag is identical for each response - let srep = self.online_key.make_srep(SystemTime::now(), &merkle_root); + let srep = self.online_key.make_srep(self.version, SystemTime::now(), &merkle_root); for (idx, &(ref nonce, ref src_addr)) in self.requests.iter().enumerate() { let paths = self.merkle.get_paths(idx); diff --git a/src/tag.rs b/src/tag.rs index dc90ea7..c1b130f 100644 --- a/src/tag.rs +++ b/src/tag.rs @@ -13,19 +13,19 @@ // limitations under the License. use std::fmt::{Display, Formatter}; +use enum_iterator::Sequence; use crate::error::Error; /// An unsigned 32-bit value (key) that maps to a byte-string (value). #[allow(non_camel_case_types)] -#[derive(Debug, PartialEq, Eq, PartialOrd, Hash, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Hash, Clone, Copy, Sequence)] pub enum Tag { // Enforcement of the "tags in strictly increasing order" rule is done using the // little-endian encoding of the ASCII tag value; e.g. 'SIG\x00' is 0x00474953 and // 'NONC' is 0x434e4f4e. // // Tags are written here in ascending order - PAD_RFC, SIG, VER, DUT1, @@ -43,6 +43,7 @@ pub enum Tag { CERT, MAXT, INDX, + ZZZZ, PAD_CLASSIC, } @@ -55,7 +56,6 @@ impl Tag { const BYTES_MINT: &'static [u8] = b"MINT"; const BYTES_NONC: &'static [u8] = b"NONC"; const BYTES_PAD_CLASSIC: &'static [u8] = b"PAD\xff"; - const BYTES_PAD_RFC: &'static [u8] = b"PAD\x00"; const BYTES_PATH: &'static [u8] = b"PATH"; const BYTES_PUBK: &'static [u8] = b"PUBK"; const BYTES_RADI: &'static [u8] = b"RADI"; @@ -66,6 +66,7 @@ impl Tag { const BYTES_DUT1: &'static [u8] = b"DUT1"; const BYTES_DTAI: &'static [u8] = b"DTAI"; const BYTES_LEAP: &'static [u8] = b"LEAP"; + const BYTES_ZZZZ: &'static [u8] = b"ZZZZ"; /// Translates a tag into its on-the-wire representation pub fn wire_value(self) -> &'static [u8] { @@ -78,7 +79,6 @@ impl Tag { Tag::MINT => Tag::BYTES_MINT, Tag::NONC => Tag::BYTES_NONC, Tag::PAD_CLASSIC => Tag::BYTES_PAD_CLASSIC, - Tag::PAD_RFC => Tag::BYTES_PAD_RFC, Tag::PATH => Tag::BYTES_PATH, Tag::PUBK => Tag::BYTES_PUBK, Tag::RADI => Tag::BYTES_RADI, @@ -89,6 +89,7 @@ impl Tag { Tag::DUT1 => Tag::BYTES_DUT1, Tag::DTAI => Tag::BYTES_DTAI, Tag::LEAP => Tag::BYTES_LEAP, + Tag::ZZZZ => Tag::BYTES_ZZZZ, } } @@ -104,7 +105,6 @@ impl Tag { Tag::BYTES_MINT => Ok(Tag::MINT), Tag::BYTES_NONC => Ok(Tag::NONC), Tag::BYTES_PAD_CLASSIC => Ok(Tag::PAD_CLASSIC), - Tag::BYTES_PAD_RFC => Ok(Tag::PAD_RFC), Tag::BYTES_PATH => Ok(Tag::PATH), Tag::BYTES_PUBK => Ok(Tag::PUBK), Tag::BYTES_RADI => Ok(Tag::RADI), @@ -115,6 +115,7 @@ impl Tag { Tag::BYTES_DUT1 => Ok(Tag::DUT1), Tag::BYTES_DTAI => Ok(Tag::DTAI), Tag::BYTES_LEAP => Ok(Tag::LEAP), + Tag::BYTES_ZZZZ => Ok(Tag::ZZZZ), _ => Err(Error::InvalidTag(Box::from(bytes))), } } @@ -127,7 +128,6 @@ impl Tag { /// A short (non canonical) string representation of the tag fn to_string(&self) -> String { match self { - Tag::PAD_RFC => String::from("PAD00"), Tag::PAD_CLASSIC => String::from("PADff"), Tag::SIG => String::from("SIG"), Tag::VER => String::from("VER"), @@ -141,3 +141,22 @@ impl Display for Tag { write!(f, "{}", self.to_string()) } } + + +#[cfg(test)] +mod test { + use super::*; + use enum_iterator; + + #[test] + fn tags_in_increasing_order() { + let values = enum_iterator::all::().collect::>(); + for (idx, _) in values.iter().enumerate() { + if idx == 0 { + continue + } + assert!(values[idx - 1] < values[idx]); + } + + } +} \ No newline at end of file