signatures: Fix canonical json functions to now return Result

signatures: Fix canonical json functions to now return Result
This commit is contained in:
Devin Ragotzy 2021-07-01 12:32:33 -07:00 committed by Jonas Platte
parent db755f994e
commit 96567a295e
No known key found for this signature in database
GPG Key ID: CC154DE0E30B7C67
3 changed files with 18 additions and 14 deletions

View File

@ -5,6 +5,7 @@
Breaking changes: Breaking changes:
* Replace `ring` dependency with `ed25519-dalek` and `pkcs8` * Replace `ring` dependency with `ed25519-dalek` and `pkcs8`
* `canonical_json` and `content_hash` now return `Error` when JSON is not canonical
# 0.7.2 # 0.7.2

View File

@ -194,11 +194,11 @@ where
/// }"#; /// }"#;
/// ///
/// let object = serde_json::from_str(input).unwrap(); /// let object = serde_json::from_str(input).unwrap();
/// let canonical = ruma_signatures::canonical_json(&object); /// let canonical = ruma_signatures::canonical_json(&object).unwrap();
/// ///
/// assert_eq!(canonical, r#"{"日":1,"本":2}"#); /// assert_eq!(canonical, r#"{"日":1,"本":2}"#);
/// ``` /// ```
pub fn canonical_json(object: &CanonicalJsonObject) -> String { pub fn canonical_json(object: &CanonicalJsonObject) -> Result<String, Error> {
canonical_json_with_fields_to_remove(object, CANONICAL_JSON_FIELDS_TO_REMOVE) canonical_json_with_fields_to_remove(object, CANONICAL_JSON_FIELDS_TO_REMOVE)
} }
@ -321,7 +321,7 @@ fn verify_json_with<V>(
where where
V: Verifier, V: Verifier,
{ {
verifier.verify_json(public_key, signature, canonical_json(object).as_bytes()) verifier.verify_json(public_key, signature, canonical_json(object)?.as_bytes())
} }
/// Creates a *content hash* for an event. /// Creates a *content hash* for an event.
@ -334,11 +334,11 @@ where
/// # Parameters /// # Parameters
/// ///
/// object: A JSON object to generate a content hash for. /// object: A JSON object to generate a content hash for.
pub fn content_hash(object: &CanonicalJsonObject) -> String { pub fn content_hash(object: &CanonicalJsonObject) -> Result<String, Error> {
let json = canonical_json_with_fields_to_remove(object, CONTENT_HASH_FIELDS_TO_REMOVE); let json = canonical_json_with_fields_to_remove(object, CONTENT_HASH_FIELDS_TO_REMOVE)?;
let hash = Sha256::digest(json.as_bytes()); let hash = Sha256::digest(json.as_bytes());
encode_config(&hash, STANDARD_NO_PAD) Ok(encode_config(&hash, STANDARD_NO_PAD))
} }
/// Creates a *reference hash* for an event. /// Creates a *reference hash* for an event.
@ -363,7 +363,7 @@ pub fn reference_hash(
let redacted_value = redact(value, version)?; let redacted_value = redact(value, version)?;
let json = let json =
canonical_json_with_fields_to_remove(&redacted_value, REFERENCE_HASH_FIELDS_TO_REMOVE); canonical_json_with_fields_to_remove(&redacted_value, REFERENCE_HASH_FIELDS_TO_REMOVE)?;
let hash = Sha256::digest(json.as_bytes()); let hash = Sha256::digest(json.as_bytes());
@ -481,7 +481,7 @@ pub fn hash_and_sign_event<K>(
where where
K: KeyPair, K: KeyPair,
{ {
let hash = content_hash(object); let hash = content_hash(object)?;
let hashes_value = object let hashes_value = object
.entry("hashes".to_owned()) .entry("hashes".to_owned())
@ -598,7 +598,7 @@ pub fn verify_event(
}; };
let servers_to_check = servers_to_check_signatures(object, version)?; let servers_to_check = servers_to_check_signatures(object, version)?;
let canonical_json = from_json_str(&canonical_json(&redacted)).map_err(JsonError::from)?; let canonical_json = from_json_str(&canonical_json(&redacted)?).map_err(JsonError::from)?;
for entity_id in servers_to_check { for entity_id in servers_to_check {
let signature_set = match signature_map.get(entity_id.as_str()) { let signature_set = match signature_map.get(entity_id.as_str()) {
@ -657,7 +657,7 @@ pub fn verify_event(
verify(STANDARD_NO_PAD)?; verify(STANDARD_NO_PAD)?;
} }
let calculated_hash = content_hash(object); let calculated_hash = content_hash(object)?;
if *hash == calculated_hash { if *hash == calculated_hash {
Ok(Verified::All) Ok(Verified::All)
@ -673,14 +673,17 @@ struct SignatureAndPubkey<'a> {
/// Internal implementation detail of the canonical JSON algorithm. Allows customization of the /// Internal implementation detail of the canonical JSON algorithm. Allows customization of the
/// fields that will be removed before serializing. /// fields that will be removed before serializing.
fn canonical_json_with_fields_to_remove(object: &CanonicalJsonObject, fields: &[&str]) -> String { fn canonical_json_with_fields_to_remove(
object: &CanonicalJsonObject,
fields: &[&str],
) -> Result<String, Error> {
let mut owned_object = object.clone(); let mut owned_object = object.clone();
for field in fields { for field in fields {
owned_object.remove(*field); owned_object.remove(*field);
} }
to_canonical_json_string(&owned_object).expect("JSON object serialization to succeed") to_canonical_json_string(&owned_object).map_err(|e| Error::Json(e.into()))
} }
/// Redacts an event using the rules specified in the Matrix client-server specification. /// Redacts an event using the rules specified in the Matrix client-server specification.
@ -879,7 +882,7 @@ mod tests {
_ => unreachable!(), _ => unreachable!(),
}; };
assert_eq!(canonical_json(&object), canonical); assert_eq!(canonical_json(&object).unwrap(), canonical);
} }
#[test] #[test]

View File

@ -132,7 +132,7 @@ mod tests {
/// Convenience for converting a string of JSON into its canonical form. /// Convenience for converting a string of JSON into its canonical form.
fn test_canonical_json(input: &str) -> String { fn test_canonical_json(input: &str) -> String {
let object = from_json_str(input).unwrap(); let object = from_json_str(input).unwrap();
canonical_json(&object) canonical_json(&object).unwrap()
} }
#[test] #[test]