Add PublicKey{Map,Set} and make the Signature versions private.
This commit is contained in:
parent
593d0e469b
commit
daf160324c
@ -7,7 +7,7 @@ use ring::digest::{digest, SHA256};
|
||||
use serde_json::{from_str, from_value, map::Map, to_string, to_value, Value};
|
||||
|
||||
use crate::{
|
||||
keys::KeyPair,
|
||||
keys::{KeyPair, PublicKeyMap},
|
||||
signatures::SignatureMap,
|
||||
split_id,
|
||||
verification::{Ed25519Verifier, Verified, Verifier},
|
||||
@ -95,7 +95,7 @@ static REFERENCE_HASH_FIELDS_TO_REMOVE: &[&str] = &["age_ts", "signatures", "uns
|
||||
/// let mut value = serde_json::from_str("{}").unwrap();
|
||||
///
|
||||
/// // Sign the JSON with the key pair.
|
||||
/// assert!(ruma_signatures::sign_json("example.com", &key_pair, &mut value).is_ok());
|
||||
/// assert!(ruma_signatures::sign_json("domain", &key_pair, &mut value).is_ok());
|
||||
/// ```
|
||||
///
|
||||
/// This will modify the JSON from an empty object to a structure like this:
|
||||
@ -103,7 +103,7 @@ static REFERENCE_HASH_FIELDS_TO_REMOVE: &[&str] = &["age_ts", "signatures", "uns
|
||||
/// ```json
|
||||
/// {
|
||||
/// "signatures": {
|
||||
/// "example.com": {
|
||||
/// "domain": {
|
||||
/// "ed25519:1": "K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ"
|
||||
/// }
|
||||
/// }
|
||||
@ -209,23 +209,23 @@ pub fn canonical_json(value: &Value) -> Result<String, Error> {
|
||||
/// let value = serde_json::from_str(
|
||||
/// r#"{
|
||||
/// "signatures": {
|
||||
/// "example.com": {
|
||||
/// "domain": {
|
||||
/// "ed25519:1": "K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ"
|
||||
/// }
|
||||
/// }
|
||||
/// }"#
|
||||
/// ).unwrap();
|
||||
///
|
||||
/// // Create the `SignatureMap` that will inform `verify_json` which signatures to verify.
|
||||
/// let mut signature_set = HashMap::new();
|
||||
/// signature_set.insert("ed25519:1".to_string(), PUBLIC_KEY.to_string());
|
||||
/// // Create the `PublicKeyMap` that will inform `verify_json` which signatures to verify.
|
||||
/// let mut public_key_set = HashMap::new();
|
||||
/// public_key_set.insert("ed25519:1".to_string(), PUBLIC_KEY.to_string());
|
||||
/// let mut public_key_map = HashMap::new();
|
||||
/// public_key_map.insert("example.com".to_string(), signature_set);
|
||||
/// public_key_map.insert("domain".to_string(), public_key_set);
|
||||
///
|
||||
/// // Verify at least one signature for each entity in `public_key_map`.
|
||||
/// assert!(ruma_signatures::verify_json(&public_key_map, &value).is_ok());
|
||||
/// ```
|
||||
pub fn verify_json(public_key_map: &SignatureMap, value: &Value) -> Result<(), Error> {
|
||||
pub fn verify_json(public_key_map: &PublicKeyMap, value: &Value) -> Result<(), Error> {
|
||||
let map = match value {
|
||||
Value::Object(ref map) => map,
|
||||
_ => return Err(Error::new("JSON value must be a JSON object")),
|
||||
@ -431,7 +431,7 @@ pub fn reference_hash(value: &Value) -> Result<String, Error> {
|
||||
/// ).unwrap();
|
||||
///
|
||||
/// // Hash and sign the JSON with the key pair.
|
||||
/// assert!(ruma_signatures::hash_and_sign_event("example.com", &key_pair, &mut value).is_ok());
|
||||
/// assert!(ruma_signatures::hash_and_sign_event("domain", &key_pair, &mut value).is_ok());
|
||||
/// ```
|
||||
///
|
||||
/// This will modify the JSON from the structure shown to a structure like this:
|
||||
@ -549,18 +549,16 @@ where
|
||||
/// }"#
|
||||
/// ).unwrap();
|
||||
///
|
||||
/// // Create a map from key ID to public key.
|
||||
/// let mut example_server_keys = HashMap::new();
|
||||
/// example_server_keys.insert("ed25519:1".to_string(), PUBLIC_KEY.to_string());
|
||||
///
|
||||
/// // Insert the public keys into a map keyed by entity ID.
|
||||
/// // Create the `PublicKeyMap` that will inform `verify_json` which signatures to verify.
|
||||
/// let mut public_key_set = HashMap::new();
|
||||
/// public_key_set.insert("ed25519:1".to_string(), PUBLIC_KEY.to_string());
|
||||
/// let mut public_key_map = HashMap::new();
|
||||
/// public_key_map.insert("domain".to_string(), example_server_keys);
|
||||
/// public_key_map.insert("domain".to_string(), public_key_set);
|
||||
///
|
||||
/// // Verify at least one signature for each entity in `public_key_map`.
|
||||
/// assert!(ruma_signatures::verify_event(&public_key_map, &value).is_ok());
|
||||
/// ```
|
||||
pub fn verify_event(public_key_map: &SignatureMap, value: &Value) -> Result<Verified, Error> {
|
||||
pub fn verify_event(public_key_map: &PublicKeyMap, value: &Value) -> Result<Verified, Error> {
|
||||
let redacted = redact(value)?;
|
||||
|
||||
let map = match redacted {
|
||||
|
15
src/keys.rs
15
src/keys.rs
@ -1,6 +1,9 @@
|
||||
//! Public and private key pairs.
|
||||
|
||||
use std::fmt::{Debug, Formatter, Result as FmtResult};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::{Debug, Formatter, Result as FmtResult},
|
||||
};
|
||||
|
||||
use ring::signature::Ed25519KeyPair as RingEd25519KeyPair;
|
||||
use untrusted::Input;
|
||||
@ -87,3 +90,13 @@ impl Debug for Ed25519KeyPair {
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A map from entity names to sets of public keys for that entity.
|
||||
///
|
||||
/// "Entity" is generally a homeserver, e.g. "example.com".
|
||||
pub type PublicKeyMap = HashMap<String, PublicKeySet>;
|
||||
|
||||
/// A set of public keys for a single homeserver.
|
||||
///
|
||||
/// This is represented as a map from key ID to Base64-encoded signature.
|
||||
pub type PublicKeySet = HashMap<String, String>;
|
||||
|
30
src/lib.rs
30
src/lib.rs
@ -104,8 +104,8 @@ pub use functions::{
|
||||
canonical_json, content_hash, hash_and_sign_event, redact, reference_hash, sign_json,
|
||||
verify_event, verify_json,
|
||||
};
|
||||
pub use keys::{Ed25519KeyPair, KeyPair};
|
||||
pub use signatures::{Signature, SignatureMap, SignatureSet};
|
||||
pub use keys::{Ed25519KeyPair, KeyPair, PublicKeyMap, PublicKeySet};
|
||||
pub use signatures::Signature;
|
||||
|
||||
mod functions;
|
||||
mod keys;
|
||||
@ -350,23 +350,23 @@ mod test {
|
||||
|
||||
let mut value = from_str("{}").unwrap();
|
||||
|
||||
sign_json("example.com", &key_pair, &mut value).unwrap();
|
||||
sign_json("domain", &key_pair, &mut value).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
to_string(&value).unwrap(),
|
||||
r#"{"signatures":{"example.com":{"ed25519:1":"K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ"}}}"#
|
||||
r#"{"signatures":{"domain":{"ed25519:1":"K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ"}}}"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_empty_json() {
|
||||
let value = from_str(r#"{"signatures":{"example.com":{"ed25519:1":"K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ"}}}"#).unwrap();
|
||||
let value = from_str(r#"{"signatures":{"domain":{"ed25519:1":"K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ"}}}"#).unwrap();
|
||||
|
||||
let mut signature_set = HashMap::new();
|
||||
signature_set.insert("ed25519:1".to_string(), PUBLIC_KEY.to_string());
|
||||
|
||||
let mut public_key_map = HashMap::new();
|
||||
public_key_map.insert("example.com".to_string(), signature_set);
|
||||
public_key_map.insert("domain".to_string(), signature_set);
|
||||
|
||||
assert!(verify_json(&public_key_map, &value).is_ok());
|
||||
}
|
||||
@ -407,39 +407,39 @@ mod test {
|
||||
};
|
||||
|
||||
let mut alpha_value = to_value(alpha).expect("alpha should serialize");
|
||||
sign_json("example.com", &key_pair, &mut alpha_value).unwrap();
|
||||
sign_json("domain", &key_pair, &mut alpha_value).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
to_string(&alpha_value).unwrap(),
|
||||
r#"{"one":1,"signatures":{"example.com":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw"}},"two":"Two"}"#
|
||||
r#"{"one":1,"signatures":{"domain":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw"}},"two":"Two"}"#
|
||||
);
|
||||
|
||||
let mut reverse_alpha_value =
|
||||
to_value(reverse_alpha).expect("reverse_alpha should serialize");
|
||||
sign_json("example.com", &key_pair, &mut reverse_alpha_value).unwrap();
|
||||
sign_json("domain", &key_pair, &mut reverse_alpha_value).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
to_string(&reverse_alpha_value).unwrap(),
|
||||
r#"{"one":1,"signatures":{"example.com":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw"}},"two":"Two"}"#
|
||||
r#"{"one":1,"signatures":{"domain":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw"}},"two":"Two"}"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_minimal_json() {
|
||||
let value = from_str(
|
||||
r#"{"one":1,"signatures":{"example.com":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw"}},"two":"Two"}"#
|
||||
r#"{"one":1,"signatures":{"domain":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw"}},"two":"Two"}"#
|
||||
).unwrap();
|
||||
|
||||
let mut signature_set = HashMap::new();
|
||||
signature_set.insert("ed25519:1".to_string(), PUBLIC_KEY.to_string());
|
||||
|
||||
let mut public_key_map = HashMap::new();
|
||||
public_key_map.insert("example.com".to_string(), signature_set);
|
||||
public_key_map.insert("domain".to_string(), signature_set);
|
||||
|
||||
assert!(verify_json(&public_key_map, &value).is_ok());
|
||||
|
||||
let reverse_value = from_str(
|
||||
r#"{"two":"Two","signatures":{"example.com":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw"}},"one":1}"#
|
||||
r#"{"two":"Two","signatures":{"domain":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw"}},"one":1}"#
|
||||
).unwrap();
|
||||
|
||||
assert!(verify_json(&public_key_map, &reverse_value).is_ok());
|
||||
@ -447,13 +447,13 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn fail_verify_json() {
|
||||
let value = from_str(r#"{"not":"empty","signatures":{"example.com":"K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ"}}"#).unwrap();
|
||||
let value = from_str(r#"{"not":"empty","signatures":{"domain":"K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ"}}"#).unwrap();
|
||||
|
||||
let mut signature_set = HashMap::new();
|
||||
signature_set.insert("ed25519:1".to_string(), PUBLIC_KEY.to_string());
|
||||
|
||||
let mut public_key_map = HashMap::new();
|
||||
public_key_map.insert("example.com".to_string(), signature_set);
|
||||
public_key_map.insert("domain".to_string(), signature_set);
|
||||
|
||||
assert!(verify_json(&public_key_map, &value).is_err());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user