Add hash_and_sign_event function.

This commit is contained in:
Jimmy Cuadra 2019-07-09 00:05:01 -07:00
parent 202b3ed402
commit 47c6de7a1b
2 changed files with 66 additions and 3 deletions

View File

@ -4,9 +4,14 @@ use std::error::Error as _;
use base64::{encode_config, STANDARD_NO_PAD};
use ring::digest::{digest, SHA256};
use serde_json::{to_string, Value};
use serde_json::{json, to_string, to_value, Value};
use crate::{keys::KeyPair, signatures::Signature, verification::Verifier, Error};
use crate::{
keys::KeyPair,
signatures::{Signature, SignatureMap, SignatureSet},
verification::Verifier,
Error,
};
/// The fields that are allowed to remain in an event during redaction.
static ALLOWED_KEYS: &[&str] = &[
@ -133,6 +138,62 @@ pub fn reference_hash(value: &Value) -> Result<String, Error> {
Ok(encode_config(&hash, STANDARD_NO_PAD))
}
/// Hashes and signs the JSON representation of an event.
///
/// # Parameters
///
/// * server_name: The hostname or IP of the homeserver, e.g. `example.com`.
/// * key_pair: A cryptographic key pair used to sign the event.
/// * value: A JSON object to be hashed and signed according to the Matrix specification.
pub fn hash_and_sign_event<K>(
server_name: &str,
key_pair: &K,
value: &Value,
) -> Result<Value, Error>
where
K: KeyPair,
{
let hash = content_hash(value)?;
if !value.is_object() {
return Err(Error::new("JSON value must be a JSON object"));
}
let mut owned_value = value.clone();
// Limit the scope of the mutable borrow so `owned_value` can be passed immutably to `redact`
// below.
{
let object = owned_value
.as_object_mut()
.expect("safe since we checked above");
let hashes = json!({ "sha256": hash });
object.insert("hashes".to_string(), hashes);
}
let redacted = redact(&owned_value)?;
let signature = sign_json(key_pair, &redacted)?;
let mut signature_set = SignatureSet::with_capacity(1);
signature_set.insert(signature);
let mut signature_map = SignatureMap::with_capacity(1);
signature_map.insert(server_name, signature_set)?;
let signature_map_value =
to_value(signature_map).map_err(|error| Error::new(error.to_string()))?;
let object = owned_value
.as_object_mut()
.expect("safe since we checked above");
object.insert("signatures".to_string(), signature_map_value);
Ok(owned_value)
}
/// Internal implementation detail of the canonical JSON algorithm. Allows customization of the
/// fields that will be removed before serializing.
fn to_canonical_json_with_fields_to_remove(

View File

@ -150,7 +150,9 @@ use std::{
pub use url::Host;
pub use functions::{content_hash, reference_hash, sign_json, to_canonical_json, verify_json};
pub use functions::{
content_hash, hash_and_sign_event, reference_hash, sign_json, to_canonical_json, verify_json,
};
pub use keys::{Ed25519KeyPair, KeyPair};
pub use signatures::{Signature, SignatureMap, SignatureSet};
pub use verification::{Ed25519Verifier, Verifier};