don't transmit precalculated key IDs
fixes #118
diff --git a/src/interchange/mod.rs b/src/interchange/mod.rs
index 470ad25..0f9a090 100644
--- a/src/interchange/mod.rs
+++ b/src/interchange/mod.rs
@@ -116,10 +116,7 @@
/// "type": "root",
/// "version": NATURAL_NUMBER,
/// "expires": EXPIRES,
-/// "keys": {
-/// KEY_ID: PUB_KEY,
-/// ...
-/// },
+/// "keys": [PUB_KEY, ...]
/// "root": ROLE_DESCRIPTION,
/// "snapshot": ROLE_DESCRIPTION,
/// "targets": ROLE_DESCRIPTION,
@@ -132,7 +129,7 @@
/// ```bash
/// {
/// "threshold": NATURAL_NUMBER,
-/// "key_ids": [KEY_ID]
+/// "key_ids": [KEY_ID, ...]
/// }
/// ```
///
@@ -189,8 +186,8 @@
/// "name": ROLE,
/// "threshold": NATURAL_NUMBER,
/// "terminating": BOOLEAN,
-/// "key_ids": [KEY_ID],
-/// "paths": [PATH]
+/// "key_ids": [KEY_ID, ...],
+/// "paths": [PATH, ...]
/// }
/// ```
///
diff --git a/src/metadata.rs b/src/metadata.rs
index eda6908..f0d9677 100644
--- a/src/metadata.rs
+++ b/src/metadata.rs
@@ -526,7 +526,12 @@
)));
}
+ let keys_len = keys.len();
let keys = HashMap::from_iter(keys.drain(..).map(|k| (k.key_id().clone(), k)));
+
+ if keys.len() != keys_len {
+ return Err(Error::IllegalArgument("Cannot have duplicate keys".into()));
+ }
Ok(RootMetadata {
version: version,
@@ -1593,45 +1598,43 @@
"version": 1,
"expires": "2017-01-01T00:00:00Z",
"consistent_snapshot": false,
- "keys": {
- "qfrfBrkB4lBBSDEBlZgaTGS_SrE6UfmON9kP4i3dJFY=": {
- "type": "ed25519",
- "public_key": "MCwwBwYDK2VwBQADIQDrisJrXJ7wJ5474-giYqk7zhb\
- -WO5CJQDTjK9GHGWjtg==",
- },
- "4hsyITLMQoWBg0ldCLKPlRZPIEf258cMg-xdAROsO6o=": {
- "type": "ed25519",
- "public_key": "MCwwBwYDK2VwBQADIQAWY3bJCn9xfQJwVicvNhwlL7BQ\
- vtGgZ_8giaAwL7q3PQ==",
- },
- "5WvZhiiSSUung_OhJVbPshKwD_ZNkgeg80i4oy2KAVs=": {
- "type": "ed25519",
- "public_key": "MCwwBwYDK2VwBQADIQBo2eyzhzcQBajrjmAQUwXDQ1ao_\
- NhZ1_7zzCKL8rKzsg==",
- },
- "C2hNB7qN99EAbHVGHPIJc5Hqa9RfEilnMqsCNJ5dGdw=": {
+ "keys": [
+ {
"type": "ed25519",
"public_key": "MCwwBwYDK2VwBQADIQAUEK4wU6pwu_qYQoqHnWTTACo1\
ePffquscsHZOhg9-Cw==",
},
+ {
+ "type": "ed25519",
+ "public_key": "MCwwBwYDK2VwBQADIQDrisJrXJ7wJ5474-giYqk7zhb\
+ -WO5CJQDTjK9GHGWjtg==",
+ },
+ {
+ "type": "ed25519",
+ "public_key": "MCwwBwYDK2VwBQADIQAWY3bJCn9xfQJwVicvNhwlL7BQ\
+ vtGgZ_8giaAwL7q3PQ==",
+ },
+ {
+ "type": "ed25519",
+ "public_key": "MCwwBwYDK2VwBQADIQBo2eyzhzcQBajrjmAQUwXDQ1ao_\
+ NhZ1_7zzCKL8rKzsg==",
+ },
+ ],
+ "root": {
+ "threshold": 1,
+ "key_ids": ["qfrfBrkB4lBBSDEBlZgaTGS_SrE6UfmON9kP4i3dJFY="],
},
- "roles": {
- "root": {
- "threshold": 1,
- "key_ids": ["qfrfBrkB4lBBSDEBlZgaTGS_SrE6UfmON9kP4i3dJFY="],
- },
- "snapshot": {
- "threshold": 1,
- "key_ids": ["5WvZhiiSSUung_OhJVbPshKwD_ZNkgeg80i4oy2KAVs="],
- },
- "targets": {
- "threshold": 1,
- "key_ids": ["4hsyITLMQoWBg0ldCLKPlRZPIEf258cMg-xdAROsO6o="],
- },
- "timestamp": {
- "threshold": 1,
- "key_ids": ["C2hNB7qN99EAbHVGHPIJc5Hqa9RfEilnMqsCNJ5dGdw="],
- },
+ "snapshot": {
+ "threshold": 1,
+ "key_ids": ["5WvZhiiSSUung_OhJVbPshKwD_ZNkgeg80i4oy2KAVs="],
+ },
+ "targets": {
+ "threshold": 1,
+ "key_ids": ["4hsyITLMQoWBg0ldCLKPlRZPIEf258cMg-xdAROsO6o="],
+ },
+ "timestamp": {
+ "threshold": 1,
+ "key_ids": ["C2hNB7qN99EAbHVGHPIJc5Hqa9RfEilnMqsCNJ5dGdw="],
},
});
@@ -1993,30 +1996,6 @@
assert!(json::from_value::<RootMetadata>(root_json).is_err());
}
- // Refuse to deserialize root metadata if any of the defined keys don't match their key ID
- #[test]
- fn deserialize_json_root_bad_key_ids() {
- let mut root_json = make_root();
- match root_json.as_object_mut() {
- Some(obj) => {
- match obj.get_mut("keys").unwrap().as_object_mut() {
- Some(keys) => {
- let key_id = keys.keys().next().unwrap().clone();
- let key = keys.get(&key_id).unwrap().clone();
- let mut bytes = BASE64URL.decode(key_id.as_bytes()).unwrap();
- bytes[0] ^= 0x01;
- let key_id = BASE64URL.encode(&bytes);
- let _ = keys.insert(key_id, key);
- }
- None => panic!(),
- }
- }
- None => panic!(),
- }
-
- assert!(json::from_value::<RootMetadata>(root_json).is_err());
- }
-
fn set_threshold(value: &mut json::Value, threshold: i32) {
match value.as_object_mut() {
Some(obj) => {
diff --git a/src/shims.rs b/src/shims.rs
index 6a9541d..52b4beb 100644
--- a/src/shims.rs
+++ b/src/shims.rs
@@ -15,29 +15,32 @@
version: u32,
consistent_snapshot: bool,
expires: DateTime<Utc>,
- keys: HashMap<crypto::KeyId, crypto::PublicKey>,
- roles: HashMap<metadata::Role, metadata::RoleDefinition>,
+ keys: Vec<crypto::PublicKey>,
+ root: metadata::RoleDefinition,
+ snapshot: metadata::RoleDefinition,
+ targets: metadata::RoleDefinition,
+ timestamp: metadata::RoleDefinition,
}
impl RootMetadata {
pub fn from(meta: &metadata::RootMetadata) -> Result<Self> {
- let mut roles = HashMap::new();
- let _ = roles.insert(metadata::Role::Root, meta.root().clone());
- let _ = roles.insert(metadata::Role::Snapshot, meta.snapshot().clone());
- let _ = roles.insert(metadata::Role::Targets, meta.targets().clone());
- let _ = roles.insert(metadata::Role::Timestamp, meta.timestamp().clone());
+ let mut keys = meta.keys().iter().map(|(_, v)| v.clone()).collect::<Vec<crypto::PublicKey>>();
+ keys.sort_by_key(|k| k.key_id().clone());
Ok(RootMetadata {
typ: metadata::Role::Root,
version: meta.version(),
expires: meta.expires().clone(),
consistent_snapshot: meta.consistent_snapshot(),
- keys: meta.keys().clone(),
- roles: roles,
+ keys: keys,
+ root: meta.root().clone(),
+ snapshot: meta.snapshot().clone(),
+ targets: meta.targets().clone(),
+ timestamp: meta.timestamp().clone(),
})
}
- pub fn try_into(mut self) -> Result<metadata::RootMetadata> {
+ pub fn try_into(self) -> Result<metadata::RootMetadata> {
if self.typ != metadata::Role::Root {
return Err(Error::Encoding(format!(
"Attempted to decode root metdata labeled as {:?}",
@@ -45,50 +48,15 @@
)));
}
- let mut keys = Vec::new();
- for (key_id, value) in self.keys.drain() {
- if &key_id != value.key_id() {
- return Err(Error::Encoding(format!(
- "Received key with ID {:?} but calculated it's value as {:?}. \
- Refusing to add it to the set of trusted keys.",
- key_id,
- value.key_id()
- )));
- } else {
- debug!(
- "Found key with good ID {:?}. Adding it to the set of trusted keys.",
- key_id
- );
- keys.push(value);
- }
- }
-
- let root = self.roles.remove(&metadata::Role::Root).ok_or_else(|| {
- Error::Encoding("Missing root role definition".into())
- })?;
- let snapshot = self.roles.remove(&metadata::Role::Snapshot).ok_or_else(
- || {
- Error::Encoding("Missing snapshot role definition".into())
- },
- )?;
- let targets = self.roles.remove(&metadata::Role::Targets).ok_or_else(|| {
- Error::Encoding("Missing targets role definition".into())
- })?;
- let timestamp = self.roles.remove(&metadata::Role::Timestamp).ok_or_else(
- || {
- Error::Encoding("Missing timestamp role definition".into())
- },
- )?;
-
metadata::RootMetadata::new(
self.version,
self.expires,
self.consistent_snapshot,
- keys,
- root,
- snapshot,
- targets,
- timestamp,
+ self.keys,
+ self.root,
+ self.snapshot,
+ self.targets,
+ self.timestamp,
)
}
}