diff --git a/src/metadata.rs b/src/metadata.rs index 1bb110d9..2cc14336 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -1900,6 +1900,7 @@ mod test { let jsn = json!({ "_type": "root", + "spec_version": "1.0", "version": 1, "expires": "2017-01-01T00:00:00Z", "consistent_snapshot": false, @@ -1971,6 +1972,7 @@ mod test { let jsn = json!({ "_type": "timestamp", + "spec_version": "1.0", "version": 1, "expires": "2017-01-01T00:00:00Z", "snapshot": { @@ -2006,6 +2008,7 @@ mod test { let jsn = json!({ "_type": "snapshot", + "spec_version": "1.0", "version": 1, "expires": "2017-01-01T00:00:00Z", "meta": { @@ -2038,6 +2041,7 @@ mod test { let jsn = json!({ "_type": "targets", + "spec_version": "1.0", "version": 1, "expires": "2017-01-01T00:00:00Z", "targets": { @@ -2081,6 +2085,7 @@ mod test { let jsn = json!({ "_type": "targets", + "spec_version": "1.0", "version": 1, "expires": "2017-01-01T00:00:00Z", "targets": {}, @@ -2135,13 +2140,14 @@ mod test { "signatures": [ { "keyid": "qfrfBrkB4lBBSDEBlZgaTGS_SrE6UfmON9kP4i3dJFY=", - "sig": "2e92cab0ef3e5fafaef0a376d77d0811632be25729ee7b7e7c\ - 41c4af0759950406141d159b3e8c50336535927148180153d2d9da\ - fca8960c9fc918c68030c803", + "sig": "6af7a8b13ea4ab59e6483490c8bb7ac1dec7354042c00bbc84\ + e0df928ffccfc8654f41191c438efb2bf6f7f44f57750eebde0893\ + cbe64eb8073132017937770b", } ], "signed": { "_type": "snapshot", + "spec_version": "1.0", "version": 1, "expires": "2017-01-01T00:00:00Z", "meta": { @@ -2298,6 +2304,7 @@ mod test { fn deserialize_json_root_duplicate_keys() { let root_json = r#"{ "type": "root", + "spec_version": "1.0", "version": 1, "expires": "2017-01-01T00:00:00Z", "consistent_snapshot": false, @@ -2387,7 +2394,7 @@ mod test { assert!(serde_json::from_value::(jsn).is_err()); } - // Refuse to deserialilze root metadata with wrong type field + // Refuse to deserialize root metadata with wrong type field #[test] fn deserialize_json_root_bad_type() { let mut root = make_root(); @@ -2395,6 +2402,14 @@ mod test { assert!(serde_json::from_value::(root).is_err()); } + // Refuse to deserialize root metadata with unknown spec version + #[test] + fn deserialize_json_root_bad_spec_version() { + let mut root = make_root(); + let _ = root.as_object_mut().unwrap().insert("spec_version".into(), json!("0")); + assert!(serde_json::from_value::(root).is_err()); + } + // Refuse to deserialize role definitions with duplicated key ids #[test] fn deserialize_json_role_definition_duplicate_key_ids() { @@ -2428,7 +2443,7 @@ mod test { assert!(serde_json::from_value::(snapshot).is_err()); } - // Refuse to deserialilze snapshot metadata with wrong type field + // Refuse to deserialize snapshot metadata with wrong type field #[test] fn deserialize_json_snapshot_bad_type() { let mut snapshot = make_snapshot(); @@ -2436,6 +2451,14 @@ mod test { assert!(serde_json::from_value::(snapshot).is_err()); } + // Refuse to deserialize snapshot metadata with unknown spec version + #[test] + fn deserialize_json_snapshot_spec_version() { + let mut snapshot = make_snapshot(); + let _ = snapshot.as_object_mut().unwrap().insert("spec_version".into(), json!("0")); + assert!(serde_json::from_value::(snapshot).is_err()); + } + // Refuse to deserialize timestamp metadata with illegal versions #[test] fn deserialize_json_timestamp_illegal_version() { @@ -2448,7 +2471,7 @@ mod test { assert!(serde_json::from_value::(timestamp).is_err()); } - // Refuse to deserialilze timestamp metadata with wrong type field + // Refuse to deserialize timestamp metadata with wrong type field #[test] fn deserialize_json_timestamp_bad_type() { let mut timestamp = make_timestamp(); @@ -2456,6 +2479,14 @@ mod test { assert!(serde_json::from_value::(timestamp).is_err()); } + // Refuse to deserialize timestamp metadata with unknown spec version + #[test] + fn deserialize_json_timestamp_bad_spec_version() { + let mut timestamp = make_timestamp(); + let _ = timestamp.as_object_mut().unwrap().insert("spec_version".into(), json!("0")); + assert!(serde_json::from_value::(timestamp).is_err()); + } + // Refuse to deserialize targets metadata with illegal versions #[test] fn deserialize_json_targets_illegal_version() { @@ -2468,7 +2499,7 @@ mod test { assert!(serde_json::from_value::(targets).is_err()); } - // Refuse to deserialilze targets metadata with wrong type field + // Refuse to deserialize targets metadata with wrong type field #[test] fn deserialize_json_targets_bad_type() { let mut targets = make_targets(); @@ -2476,6 +2507,14 @@ mod test { assert!(serde_json::from_value::(targets).is_err()); } + // Refuse to deserialize targets metadata with unknown spec version + #[test] + fn deserialize_json_targets_bad_spec_version() { + let mut targets = make_targets(); + let _ = targets.as_object_mut().unwrap().insert("spec_version".into(), json!("0")); + assert!(serde_json::from_value::(targets).is_err()); + } + // Refuse to deserialize delegations with no keys #[test] fn deserialize_json_delegations_no_keys() { diff --git a/src/shims.rs b/src/shims.rs index 95975ac6..6ac553be 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -9,6 +9,8 @@ use crate::error::Error; use crate::metadata::{self, Metadata}; use crate::Result; +const SPEC_VERSION: &str = "1.0"; + fn parse_datetime(ts: &str) -> Result> { Utc.datetime_from_str(ts, "%FT%TZ") .map_err(|e| Error::Encoding(format!("Can't parse DateTime: {:?}", e))) @@ -30,6 +32,7 @@ fn format_datetime(ts: &DateTime) -> String { pub struct RootMetadata { #[serde(rename = "_type")] typ: metadata::Role, + spec_version: String, version: u32, consistent_snapshot: bool, expires: String, @@ -42,6 +45,7 @@ impl RootMetadata { pub fn from(meta: &metadata::RootMetadata) -> Result { Ok(RootMetadata { typ: metadata::Role::Root, + spec_version: SPEC_VERSION.to_string(), version: meta.version(), expires: format_datetime(&meta.expires()), consistent_snapshot: meta.consistent_snapshot(), @@ -63,6 +67,11 @@ impl RootMetadata { ))); } + if self.spec_version != SPEC_VERSION { + return Err(Error::Encoding(format!( + "Unknown spec version {}", self.spec_version))); + } + metadata::RootMetadata::new( self.version, parse_datetime(&self.expires)?, @@ -120,6 +129,7 @@ impl RoleDefinition { pub struct TimestampMetadata { #[serde(rename = "_type")] typ: metadata::Role, + spec_version: String, version: u32, expires: String, snapshot: metadata::MetadataDescription, @@ -129,6 +139,7 @@ impl TimestampMetadata { pub fn from(metadata: &metadata::TimestampMetadata) -> Result { Ok(TimestampMetadata { typ: metadata::Role::Timestamp, + spec_version: SPEC_VERSION.to_string(), version: metadata.version(), expires: format_datetime(metadata.expires()), snapshot: metadata.snapshot().clone(), @@ -143,6 +154,11 @@ impl TimestampMetadata { ))); } + if self.spec_version != SPEC_VERSION { + return Err(Error::Encoding(format!( + "Unknown spec version {}", self.spec_version))); + } + metadata::TimestampMetadata::new( self.version, parse_datetime(&self.expires)?, @@ -155,6 +171,7 @@ impl TimestampMetadata { pub struct SnapshotMetadata { #[serde(rename = "_type")] typ: metadata::Role, + spec_version: String, version: u32, expires: String, meta: BTreeMap, @@ -164,6 +181,7 @@ impl SnapshotMetadata { pub fn from(metadata: &metadata::SnapshotMetadata) -> Result { Ok(SnapshotMetadata { typ: metadata::Role::Snapshot, + spec_version: SPEC_VERSION.to_string(), version: metadata.version(), expires: format_datetime(&metadata.expires()), meta: metadata.meta().iter().map(|(p, d)| (p.clone(), d.clone())).collect(), @@ -178,6 +196,11 @@ impl SnapshotMetadata { ))); } + if self.spec_version != SPEC_VERSION { + return Err(Error::Encoding(format!( + "Unknown spec version {}", self.spec_version))); + } + metadata::SnapshotMetadata::new( self.version, parse_datetime(&self.expires)?, @@ -190,6 +213,7 @@ impl SnapshotMetadata { pub struct TargetsMetadata { #[serde(rename = "_type")] typ: metadata::Role, + spec_version: String, version: u32, expires: String, targets: BTreeMap, @@ -201,6 +225,7 @@ impl TargetsMetadata { pub fn from(metadata: &metadata::TargetsMetadata) -> Result { Ok(TargetsMetadata { typ: metadata::Role::Targets, + spec_version: SPEC_VERSION.to_string(), version: metadata.version(), expires: format_datetime(&metadata.expires()), targets: metadata.targets().iter().map(|(p, d)| (p.clone(), d.clone())).collect(), @@ -216,6 +241,11 @@ impl TargetsMetadata { ))); } + if self.spec_version != SPEC_VERSION { + return Err(Error::Encoding(format!( + "Unknown spec version {}", self.spec_version))); + } + metadata::TargetsMetadata::new( self.version, parse_datetime(&self.expires)?,