crypto: Document the user identities.
parent
74dd0a00d3
commit
a57f63d614
|
@ -30,12 +30,15 @@ use matrix_sdk_common::{
|
||||||
|
|
||||||
use crate::{error::SignatureError, verify_json, ReadOnlyDevice};
|
use crate::{error::SignatureError, verify_json, ReadOnlyDevice};
|
||||||
|
|
||||||
|
/// Wrapper for a cross signing key marking it as the master key.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MasterPubkey(Arc<CrossSigningKey>);
|
pub struct MasterPubkey(Arc<CrossSigningKey>);
|
||||||
|
|
||||||
|
/// Wrapper for a cross signing key marking it as a self signing key.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SelfSigningPubkey(Arc<CrossSigningKey>);
|
pub struct SelfSigningPubkey(Arc<CrossSigningKey>);
|
||||||
|
|
||||||
|
/// Wrapper for a cross signing key marking it as a user signing key.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct UserSigningPubkey(Arc<CrossSigningKey>);
|
pub struct UserSigningPubkey(Arc<CrossSigningKey>);
|
||||||
|
|
||||||
|
@ -69,12 +72,24 @@ impl<'a> From<&'a UserSigningPubkey> for CrossSigningSubKeys<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enum over the cross signing sub-keys.
|
||||||
enum CrossSigningSubKeys<'a> {
|
enum CrossSigningSubKeys<'a> {
|
||||||
|
/// The self signing subkey.
|
||||||
SelfSigning(&'a SelfSigningPubkey),
|
SelfSigning(&'a SelfSigningPubkey),
|
||||||
|
/// The user signing subkey.
|
||||||
UserSigning(&'a UserSigningPubkey),
|
UserSigning(&'a UserSigningPubkey),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CrossSigningSubKeys<'a> {
|
impl<'a> CrossSigningSubKeys<'a> {
|
||||||
|
/// Get the id of the user that owns this cross signing subkey.
|
||||||
|
fn user_id(&self) -> &UserId {
|
||||||
|
match self {
|
||||||
|
CrossSigningSubKeys::SelfSigning(key) => &key.0.user_id,
|
||||||
|
CrossSigningSubKeys::UserSigning(key) => &key.0.user_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `CrossSigningKey` from an sub-keys enum
|
||||||
fn cross_signing_key(&self) -> &CrossSigningKey {
|
fn cross_signing_key(&self) -> &CrossSigningKey {
|
||||||
match self {
|
match self {
|
||||||
CrossSigningSubKeys::SelfSigning(key) => &key.0,
|
CrossSigningSubKeys::SelfSigning(key) => &key.0,
|
||||||
|
@ -84,6 +99,23 @@ impl<'a> CrossSigningSubKeys<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MasterPubkey {
|
impl MasterPubkey {
|
||||||
|
/// Get the master key with the given key id.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `key_id` - The id of the key that should be fetched.
|
||||||
|
pub fn get_key(&self, key_id: &DeviceKeyId) -> Option<&str> {
|
||||||
|
self.0.keys.get(key_id.as_str()).map(|k| k.as_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the given cross signing sub-key is signed by the master key.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `subkey` - The subkey that should be checked for a valid signature.
|
||||||
|
///
|
||||||
|
/// Returns an empty result if the signature check succeeded, otherwise a
|
||||||
|
/// SignatureError indicating why the check failed.
|
||||||
fn verify_subkey<'a>(
|
fn verify_subkey<'a>(
|
||||||
&self,
|
&self,
|
||||||
subkey: impl Into<CrossSigningSubKeys<'a>>,
|
subkey: impl Into<CrossSigningSubKeys<'a>>,
|
||||||
|
@ -112,6 +144,15 @@ impl MasterPubkey {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserSigningPubkey {
|
impl UserSigningPubkey {
|
||||||
|
/// Check if the given master key is signed by this user signing key.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `master_key` - The master key that should be checked for a valid
|
||||||
|
/// signature.
|
||||||
|
///
|
||||||
|
/// Returns an empty result if the signature check succeeded, otherwise a
|
||||||
|
/// SignatureError indicating why the check failed.
|
||||||
fn verify_master_key(&self, master_key: &MasterPubkey) -> Result<(), SignatureError> {
|
fn verify_master_key(&self, master_key: &MasterPubkey) -> Result<(), SignatureError> {
|
||||||
let (key_id, key) = self
|
let (key_id, key) = self
|
||||||
.0
|
.0
|
||||||
|
@ -132,6 +173,14 @@ impl UserSigningPubkey {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelfSigningPubkey {
|
impl SelfSigningPubkey {
|
||||||
|
/// Check if the given device is signed by this self signing key.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `device` - The device that should be checked for a valid signature.
|
||||||
|
///
|
||||||
|
/// Returns an empty result if the signature check succeeded, otherwise a
|
||||||
|
/// SignatureError indicating why the check failed.
|
||||||
fn verify_device(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> {
|
fn verify_device(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> {
|
||||||
let (key_id, key) = self
|
let (key_id, key) = self
|
||||||
.0
|
.0
|
||||||
|
@ -151,13 +200,17 @@ impl SelfSigningPubkey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enum over the different user identity types we can have.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum UserIdentities {
|
pub enum UserIdentities {
|
||||||
|
/// Our own user identity.
|
||||||
Own(OwnUserIdentity),
|
Own(OwnUserIdentity),
|
||||||
|
/// Identities of other users.
|
||||||
Other(UserIdentity),
|
Other(UserIdentity),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserIdentities {
|
impl UserIdentities {
|
||||||
|
/// The unique user id of this identity.
|
||||||
pub fn user_id(&self) -> &UserId {
|
pub fn user_id(&self) -> &UserId {
|
||||||
match self {
|
match self {
|
||||||
UserIdentities::Own(i) => i.user_id(),
|
UserIdentities::Own(i) => i.user_id(),
|
||||||
|
@ -172,6 +225,8 @@ impl UserIdentities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Destructure the enum into an `OwnUserIdentity` if it's of the correct
|
||||||
|
/// type.
|
||||||
pub fn own(&self) -> Option<&OwnUserIdentity> {
|
pub fn own(&self) -> Option<&OwnUserIdentity> {
|
||||||
match self {
|
match self {
|
||||||
UserIdentities::Own(i) => Some(i),
|
UserIdentities::Own(i) => Some(i),
|
||||||
|
@ -193,6 +248,11 @@ impl PartialEq for UserIdentities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Struct representing a cross signing identity of a user.
|
||||||
|
///
|
||||||
|
/// This is the user identity of a user that isn't our own. Other users will
|
||||||
|
/// only contain a master key and a self signing key, meaning that only device
|
||||||
|
/// signatures can be checked with this identity.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct UserIdentity {
|
pub struct UserIdentity {
|
||||||
user_id: Arc<UserId>,
|
user_id: Arc<UserId>,
|
||||||
|
@ -201,6 +261,16 @@ pub struct UserIdentity {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserIdentity {
|
impl UserIdentity {
|
||||||
|
/// Create a new user identity with the given master and self signing key.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `master_key` - The master key of the user identity.
|
||||||
|
///
|
||||||
|
/// * `self signing key` - The self signing key of user identity.
|
||||||
|
///
|
||||||
|
/// Returns a `SignatureError` if the self signing key fails to be correctly
|
||||||
|
/// verified by the given master key.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
master_key: MasterPubkey,
|
master_key: MasterPubkey,
|
||||||
self_signing_key: SelfSigningPubkey,
|
self_signing_key: SelfSigningPubkey,
|
||||||
|
@ -214,6 +284,7 @@ impl UserIdentity {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the user id of this identity.
|
||||||
pub fn user_id(&self) -> &UserId {
|
pub fn user_id(&self) -> &UserId {
|
||||||
&self.user_id
|
&self.user_id
|
||||||
}
|
}
|
||||||
|
@ -222,6 +293,15 @@ impl UserIdentity {
|
||||||
&self.master_key.0.keys
|
&self.master_key.0.keys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update the identity with a new master key and self signing key.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `master_key` - The new master key of the user identity.
|
||||||
|
///
|
||||||
|
/// * `self_signing_key` - The new self signing key of user identity.
|
||||||
|
///
|
||||||
|
/// Returns a `SignatureError` if we failed to update the identity.
|
||||||
pub fn update(
|
pub fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
master_key: MasterPubkey,
|
master_key: MasterPubkey,
|
||||||
|
@ -235,6 +315,18 @@ impl UserIdentity {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the given device has been signed by this identity.
|
||||||
|
///
|
||||||
|
/// The user_id of the user identity and the user_id of the device need to
|
||||||
|
/// match for the signature check to succeed as we don't trust users to sign
|
||||||
|
/// devices of other users.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `device` - The device that should be checked for a valid signature.
|
||||||
|
///
|
||||||
|
/// Returns an empty result if the signature check succeeded, otherwise a
|
||||||
|
/// SignatureError indicating why the check failed.
|
||||||
pub fn is_device_signed(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> {
|
pub fn is_device_signed(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> {
|
||||||
self.self_signing_key.verify_device(device)
|
self.self_signing_key.verify_device(device)
|
||||||
}
|
}
|
||||||
|
@ -250,6 +342,19 @@ pub struct OwnUserIdentity {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OwnUserIdentity {
|
impl OwnUserIdentity {
|
||||||
|
/// Create a new own user identity with the given master, self signing, and
|
||||||
|
/// user signing key.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `master_key` - The master key of the user identity.
|
||||||
|
///
|
||||||
|
/// * `self_signing_key` - The self signing key of user identity.
|
||||||
|
///
|
||||||
|
/// * `user_signing_key` - The user signing key of user identity.
|
||||||
|
///
|
||||||
|
/// Returns a `SignatureError` if the self signing key fails to be correctly
|
||||||
|
/// verified by the given master key.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
master_key: MasterPubkey,
|
master_key: MasterPubkey,
|
||||||
self_signing_key: SelfSigningPubkey,
|
self_signing_key: SelfSigningPubkey,
|
||||||
|
@ -267,10 +372,68 @@ impl OwnUserIdentity {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the user id of this identity.
|
||||||
pub fn user_id(&self) -> &UserId {
|
pub fn user_id(&self) -> &UserId {
|
||||||
&self.user_id
|
&self.user_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn master_key(&self) -> &BTreeMap<String, String> {
|
||||||
|
&self.master_key.0.keys
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the given identity has been signed by this identity.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `identity` - The identity of another user that we want to check if
|
||||||
|
/// it's has been signed.
|
||||||
|
///
|
||||||
|
/// Returns an empty result if the signature check succeeded, otherwise a
|
||||||
|
/// SignatureError indicating why the check failed.
|
||||||
|
pub fn is_identity_signed(&self, identity: &UserIdentity) -> Result<(), SignatureError> {
|
||||||
|
self.user_signing_key
|
||||||
|
.verify_master_key(&identity.master_key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the given device has been signed by this identity.
|
||||||
|
///
|
||||||
|
/// Only devices of our own user should be checked with this method, if a
|
||||||
|
/// device of a different user is given the signature check will always fail
|
||||||
|
/// even if a valid signature exists.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `device` - The device that should be checked for a valid signature.
|
||||||
|
///
|
||||||
|
/// Returns an empty result if the signature check succeeded, otherwise a
|
||||||
|
/// SignatureError indicating why the check failed.
|
||||||
|
pub fn is_device_signed(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> {
|
||||||
|
self.self_signing_key.verify_device(device)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark our identity as verified.
|
||||||
|
pub fn mark_as_verified(&self) {
|
||||||
|
self.verified.store(true, Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if our identity is verified.
|
||||||
|
pub fn is_verified(&self) -> bool {
|
||||||
|
self.verified.load(Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update the identity with a new master key and self signing key.
|
||||||
|
///
|
||||||
|
/// Note: This will reset the verification state if the master keys differ.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `master_key` - The new master key of the user identity.
|
||||||
|
///
|
||||||
|
/// * `self_signing_key` - The new self signing key of user identity.
|
||||||
|
///
|
||||||
|
/// * `user_signing_key` - The new user signing key of user identity.
|
||||||
|
///
|
||||||
|
/// Returns a `SignatureError` if we failed to update the identity.
|
||||||
pub fn update(
|
pub fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
master_key: MasterPubkey,
|
master_key: MasterPubkey,
|
||||||
|
@ -285,31 +448,8 @@ impl OwnUserIdentity {
|
||||||
|
|
||||||
self.master_key = master_key;
|
self.master_key = master_key;
|
||||||
|
|
||||||
// FIXME reset the verification state if the master key changed.
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn master_key(&self) -> &BTreeMap<String, String> {
|
|
||||||
&self.master_key.0.keys
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_identity_signed(&self, identity: &UserIdentity) -> Result<(), SignatureError> {
|
|
||||||
self.user_signing_key
|
|
||||||
.verify_master_key(&identity.master_key)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_device_signed(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> {
|
|
||||||
self.self_signing_key.verify_device(device)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mark_as_verified(&self) {
|
|
||||||
self.verified.store(true, Ordering::SeqCst)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_verified(&self) -> bool {
|
|
||||||
self.verified.load(Ordering::SeqCst)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue