Crate ruma_signatures
source ·Expand description
Crate ruma_signatures implements digital signatures according to the Matrix specification.
Digital signatures are used by Matrix homeservers to verify the authenticity of events in the Matrix system, as well as requests between homeservers for federation. Each homeserver has one or more signing key pairs which it uses to sign all events and federation requests. Matrix clients and other Matrix homeservers can ask the homeserver for its public keys and use those keys to verify the signed data.
Each signing key pair has an identifier, which consists of the name of the digital signature algorithm it uses and a “version” string, separated by a colon. The version is an arbitrary identifier used to distinguish key pairs using the same algorithm from the same homeserver.
Signing JSON
A homeserver signs JSON with a key pair:
// Create an Ed25519 key pair.
let key_pair = ruma_signatures::Ed25519KeyPair::new(
&public_key, // &[u8]
&private_key, // &[u8]
"1".to_string(), // The "version" of the key.
).expect("the provided keys should be suitable for Ed25519");
let value = serde_json::from_str("{}").expect("an empty JSON object should deserialize");
ruma_signatures::sign_json(&key_pair, &value).expect("value is a a JSON object"); // `Signature`
Signing Matrix events
Signing an event uses a more involved process than signing arbitrary JSON. Event signing is not yet implemented by ruma_signatures.
Verifying signatures
A client application or another homeserver can verify a signature on arbitrary JSON:
let signature = ruma_signatures::Signature::new("ed25519:1", &signature_bytes).expect(
"key identifier should be valid"
);
let value = serde_json::from_str("{}").expect("an empty JSON object should deserialize");
let verifier = ruma_signatures::Ed25519Verifier::new();
assert!(ruma_signatures::verify_json(&verifier, &public_key, &signature, &value).is_ok());
Verifying signatures of Matrix events is not yet implemented by ruma_signatures.
Signature sets
Signatures that a homeserver has added to an event are stored in a JSON object under the “signatures” key in the event’s JSON representation:
{
"content": {},
"event_type": "not.a.real.event",
"signatures": {
"example.com": {
"ed25519:1": "K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ"
}
}
}
The keys inside the “signatures” object are the hostnames of homeservers that have added signatures. Within each of those objects are a set of signatures, keyed by the signing key pair’s identifier.
This inner object can be created by serializing a SignatureSet
:
let signature = ruma_signatures::Signature::new("ed25519:1", &signature_bytes).expect(
"key identifier should be valid"
);
let mut signature_set = ruma_signatures::SignatureSet::new();
signature_set.insert(signature);
serde_json::to_string(&signature_set).expect("signature_set should serialize");
This code produces the object under the “example.com” key in the preceeding JSON. Similarly,
a SignatureSet
can be produced by deserializing JSON that follows this form.
The outer object (the map of server names to signature sets) is a Signatures
value and
created like this:
let signature = ruma_signatures::Signature::new("ed25519:1", &signature_bytes).expect(
"key identifier should be valid"
);
let mut signature_set = ruma_signatures::SignatureSet::new();
signature_set.insert(signature);
let mut signatures = ruma_signatures::Signatures::new();
signatures.insert("example.com", signature_set).expect("example.com is a valid server name");
serde_json::to_string(&signatures).expect("signatures should serialize");
Just like the SignatureSet
itself, the Signatures
value can also be deserialized from JSON.