crypto: Allow users to be signed as well.
parent
61a5293af5
commit
e757d605f5
|
@ -62,7 +62,7 @@ pub struct ReadOnlyDevice {
|
|||
device_id: Arc<Box<DeviceId>>,
|
||||
algorithms: Arc<Vec<EventEncryptionAlgorithm>>,
|
||||
keys: Arc<BTreeMap<DeviceKeyId, String>>,
|
||||
signatures: Arc<BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>>,
|
||||
pub(crate) signatures: Arc<BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>>,
|
||||
display_name: Arc<Option<String>>,
|
||||
deleted: Arc<AtomicBool>,
|
||||
trust_state: Arc<Atomic<LocalTrust>>,
|
||||
|
@ -438,6 +438,18 @@ impl ReadOnlyDevice {
|
|||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn as_device_keys(&self) -> DeviceKeys {
|
||||
DeviceKeys {
|
||||
user_id: self.user_id().clone(),
|
||||
device_id: self.device_id().into(),
|
||||
keys: self.keys().clone(),
|
||||
algorithms: self.algorithms().to_vec(),
|
||||
signatures: self.signatures().to_owned(),
|
||||
unsigned: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_signature_message(&self) -> Value {
|
||||
json!({
|
||||
"user_id": &*self.user_id,
|
||||
|
|
|
@ -29,6 +29,8 @@ use matrix_sdk_common::{
|
|||
identifiers::{DeviceKeyId, UserId},
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::olm::PrivateCrossSigningIdentity;
|
||||
use crate::{error::SignatureError, olm::Utility, ReadOnlyDevice};
|
||||
|
||||
/// Wrapper for a cross signing key marking it as the master key.
|
||||
|
@ -278,7 +280,10 @@ impl UserSigningPubkey {
|
|||
///
|
||||
/// 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> {
|
||||
pub(crate) fn verify_master_key(
|
||||
&self,
|
||||
master_key: &MasterPubkey,
|
||||
) -> Result<(), SignatureError> {
|
||||
let (key_id, key) = self
|
||||
.0
|
||||
.keys
|
||||
|
@ -326,7 +331,7 @@ impl SelfSigningPubkey {
|
|||
///
|
||||
/// 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> {
|
||||
pub(crate) fn verify_device(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> {
|
||||
let (key_id, key) = self
|
||||
.0
|
||||
.keys
|
||||
|
@ -443,7 +448,7 @@ impl PartialEq for UserIdentities {
|
|||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct UserIdentity {
|
||||
user_id: Arc<UserId>,
|
||||
master_key: MasterPubkey,
|
||||
pub(crate) master_key: MasterPubkey,
|
||||
self_signing_key: SelfSigningPubkey,
|
||||
}
|
||||
|
||||
|
@ -471,6 +476,32 @@ impl UserIdentity {
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub async fn from_private(identity: &PrivateCrossSigningIdentity) -> Self {
|
||||
let master_key = identity
|
||||
.master_key
|
||||
.lock()
|
||||
.await
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.public_key
|
||||
.clone();
|
||||
let self_signing_key = identity
|
||||
.self_signing_key
|
||||
.lock()
|
||||
.await
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.public_key
|
||||
.clone();
|
||||
|
||||
Self {
|
||||
user_id: Arc::new(identity.user_id().clone()),
|
||||
master_key,
|
||||
self_signing_key,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the user id of this identity.
|
||||
pub fn user_id(&self) -> &UserId {
|
||||
&self.user_id
|
||||
|
|
|
@ -12,13 +12,11 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#![allow(dead_code, missing_docs)]
|
||||
|
||||
mod pk_signing;
|
||||
|
||||
use matrix_sdk_common::encryption::DeviceKeys;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Error as JsonError;
|
||||
use serde_json::{Error as JsonError, Value};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
sync::{
|
||||
|
@ -33,25 +31,40 @@ use matrix_sdk_common::{
|
|||
locks::Mutex,
|
||||
};
|
||||
|
||||
use crate::{error::SignatureError, requests::UploadSigningKeysRequest};
|
||||
|
||||
use crate::ReadOnlyAccount;
|
||||
use crate::{
|
||||
error::SignatureError, requests::UploadSigningKeysRequest, ReadOnlyAccount, UserIdentity,
|
||||
};
|
||||
|
||||
use pk_signing::{MasterSigning, PickledSignings, SelfSigning, Signing, SigningError, UserSigning};
|
||||
|
||||
/// Private cross signing identity.
|
||||
///
|
||||
/// This object holds the private and public ed25519 key triplet that is used
|
||||
/// for cross signing.
|
||||
///
|
||||
/// The object might be comletely empty or have only some of the key pairs
|
||||
/// available.
|
||||
///
|
||||
/// It can be used to sign devices or other identities.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PrivateCrossSigningIdentity {
|
||||
user_id: Arc<UserId>,
|
||||
shared: Arc<AtomicBool>,
|
||||
master_key: Arc<Mutex<Option<MasterSigning>>>,
|
||||
user_signing_key: Arc<Mutex<Option<UserSigning>>>,
|
||||
self_signing_key: Arc<Mutex<Option<SelfSigning>>>,
|
||||
pub(crate) master_key: Arc<Mutex<Option<MasterSigning>>>,
|
||||
pub(crate) user_signing_key: Arc<Mutex<Option<UserSigning>>>,
|
||||
pub(crate) self_signing_key: Arc<Mutex<Option<SelfSigning>>>,
|
||||
}
|
||||
|
||||
/// The pickled version of a `PrivateCrossSigningIdentity`.
|
||||
///
|
||||
/// Can be used to store the identity.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PickledCrossSigningIdentity {
|
||||
/// The user id of the identity owner.
|
||||
pub user_id: UserId,
|
||||
/// Have the public keys of the identity been shared.
|
||||
pub shared: bool,
|
||||
/// The encrypted pickle of the identity.
|
||||
pub pickle: String,
|
||||
}
|
||||
|
||||
|
@ -89,6 +102,21 @@ impl PrivateCrossSigningIdentity {
|
|||
}
|
||||
}
|
||||
|
||||
/// Sign the given public user identity with this private identity.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) async fn sign_user(
|
||||
&self,
|
||||
user_identity: &UserIdentity,
|
||||
) -> Result<BTreeMap<UserId, BTreeMap<String, Value>>, SignatureError> {
|
||||
self.user_signing_key
|
||||
.lock()
|
||||
.await
|
||||
.as_ref()
|
||||
.ok_or(SignatureError::MissingSigningKey)?
|
||||
.sign_user(&user_identity)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Sign the given device keys with this identity.
|
||||
pub(crate) async fn sign_device(
|
||||
&self,
|
||||
|
@ -193,6 +221,7 @@ impl PrivateCrossSigningIdentity {
|
|||
|
||||
/// Create a new cross signing identity without signing the device that
|
||||
/// created it.
|
||||
#[cfg(test)]
|
||||
pub(crate) async fn new(user_id: UserId) -> Self {
|
||||
let master = Signing::new();
|
||||
|
||||
|
@ -340,11 +369,18 @@ impl PrivateCrossSigningIdentity {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::olm::ReadOnlyAccount;
|
||||
use crate::{
|
||||
identities::{ReadOnlyDevice, UserIdentity},
|
||||
olm::ReadOnlyAccount,
|
||||
};
|
||||
use std::{collections::BTreeMap, sync::Arc};
|
||||
|
||||
use super::{PrivateCrossSigningIdentity, Signing};
|
||||
|
||||
use matrix_sdk_common::identifiers::{user_id, UserId};
|
||||
use matrix_sdk_common::{
|
||||
api::r0::keys::CrossSigningKey,
|
||||
identifiers::{user_id, UserId},
|
||||
};
|
||||
use matrix_sdk_test::async_test;
|
||||
|
||||
fn user_id() -> UserId {
|
||||
|
@ -449,4 +485,60 @@ mod test {
|
|||
|
||||
assert!(!master.public_key.signatures().is_empty());
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
async fn sign_device() {
|
||||
let account = ReadOnlyAccount::new(&user_id(), "DEVICEID".into());
|
||||
let (identity, _, _) = PrivateCrossSigningIdentity::new_with_account(&account).await;
|
||||
|
||||
let mut device = ReadOnlyDevice::from_account(&account).await;
|
||||
let self_signing = identity.self_signing_key.lock().await;
|
||||
let self_signing = self_signing.as_ref().unwrap();
|
||||
|
||||
let mut device_keys = device.as_device_keys();
|
||||
self_signing.sign_device(&mut device_keys).await.unwrap();
|
||||
device.signatures = Arc::new(device_keys.signatures);
|
||||
|
||||
let public_key = &self_signing.public_key;
|
||||
public_key.verify_device(&device).unwrap()
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
async fn sign_user_identity() {
|
||||
let account = ReadOnlyAccount::new(&user_id(), "DEVICEID".into());
|
||||
let (identity, _, _) = PrivateCrossSigningIdentity::new_with_account(&account).await;
|
||||
|
||||
let bob_account = ReadOnlyAccount::new(&user_id!("@bob:localhost"), "DEVICEID".into());
|
||||
let (bob_private, _, _) = PrivateCrossSigningIdentity::new_with_account(&bob_account).await;
|
||||
let mut bob_public = UserIdentity::from_private(&bob_private).await;
|
||||
|
||||
let user_signing = identity.user_signing_key.lock().await;
|
||||
let user_signing = user_signing.as_ref().unwrap();
|
||||
|
||||
let signatures = user_signing.sign_user(&bob_public).await.unwrap();
|
||||
|
||||
let (key_id, signature) = signatures
|
||||
.iter()
|
||||
.next()
|
||||
.unwrap()
|
||||
.1
|
||||
.iter()
|
||||
.next()
|
||||
.map(|(k, s)| (k.to_string(), serde_json::from_value(s.to_owned()).unwrap()))
|
||||
.unwrap();
|
||||
|
||||
let mut master: CrossSigningKey = bob_public.master_key.as_ref().clone();
|
||||
master
|
||||
.signatures
|
||||
.entry(identity.user_id().to_owned())
|
||||
.or_insert_with(BTreeMap::new)
|
||||
.insert(key_id, signature);
|
||||
|
||||
bob_public.master_key = master.into();
|
||||
|
||||
user_signing
|
||||
.public_key
|
||||
.verify_master_key(bob_public.master_key())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,10 @@ use std::{collections::BTreeMap, sync::Arc};
|
|||
use thiserror::Error;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use olm_rs::{errors::OlmUtilityError, pk::OlmPkSigning, utility::OlmUtility};
|
||||
use olm_rs::pk::OlmPkSigning;
|
||||
|
||||
#[cfg(test)]
|
||||
use olm_rs::{errors::OlmUtilityError, utility::OlmUtility};
|
||||
|
||||
use matrix_sdk_common::{
|
||||
api::r0::keys::{CrossSigningKey, KeyUsage},
|
||||
|
@ -121,6 +124,7 @@ pub struct PickledSelfSigning {
|
|||
}
|
||||
|
||||
impl Signature {
|
||||
#[cfg(test)]
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
|
@ -183,7 +187,11 @@ impl MasterSigning {
|
|||
.entry(self.public_key.user_id().to_owned())
|
||||
.or_insert_with(BTreeMap::new)
|
||||
.insert(
|
||||
format!("ed25519:{}", self.inner.public_key().as_str()),
|
||||
DeviceKeyId::from_parts(
|
||||
DeviceKeyAlgorithm::Ed25519,
|
||||
self.inner.public_key().as_str().into(),
|
||||
)
|
||||
.to_string(),
|
||||
signature.0,
|
||||
);
|
||||
}
|
||||
|
@ -196,8 +204,32 @@ impl UserSigning {
|
|||
PickledUserSigning { pickle, public_key }
|
||||
}
|
||||
|
||||
pub async fn sign_user(&self, _: &UserIdentity) -> BTreeMap<UserId, BTreeMap<String, Value>> {
|
||||
todo!();
|
||||
#[allow(dead_code)]
|
||||
pub async fn sign_user(
|
||||
&self,
|
||||
user: &UserIdentity,
|
||||
) -> Result<BTreeMap<UserId, BTreeMap<String, Value>>, SignatureError> {
|
||||
let user_master: &CrossSigningKey = user.master_key().as_ref();
|
||||
let signature = self
|
||||
.inner
|
||||
.sign_json(serde_json::to_value(user_master)?)
|
||||
.await?;
|
||||
|
||||
let mut signatures = BTreeMap::new();
|
||||
|
||||
signatures
|
||||
.entry(self.public_key.user_id().to_owned())
|
||||
.or_insert_with(BTreeMap::new)
|
||||
.insert(
|
||||
DeviceKeyId::from_parts(
|
||||
DeviceKeyAlgorithm::Ed25519,
|
||||
self.inner.public_key.as_str().into(),
|
||||
)
|
||||
.to_string(),
|
||||
serde_json::to_value(signature.0)?,
|
||||
);
|
||||
|
||||
Ok(signatures)
|
||||
}
|
||||
|
||||
pub fn from_pickle(
|
||||
|
@ -220,13 +252,13 @@ impl SelfSigning {
|
|||
PickledSelfSigning { pickle, public_key }
|
||||
}
|
||||
|
||||
pub async fn sign_device_raw(&self, value: Value) -> Result<Signature, SignatureError> {
|
||||
pub async fn sign_device_helper(&self, value: Value) -> Result<Signature, SignatureError> {
|
||||
self.inner.sign_json(value).await
|
||||
}
|
||||
|
||||
pub async fn sign_device(&self, device_keys: &mut DeviceKeys) -> Result<(), SignatureError> {
|
||||
let json_device = serde_json::to_value(&device_keys)?;
|
||||
let signature = self.sign_device_raw(json_device).await?;
|
||||
let signature = self.sign_device_helper(json_device).await?;
|
||||
|
||||
device_keys
|
||||
.signatures
|
||||
|
@ -346,7 +378,11 @@ impl Signing {
|
|||
let mut keys = BTreeMap::new();
|
||||
|
||||
keys.insert(
|
||||
format!("ed25519:{}", self.public_key().as_str()),
|
||||
DeviceKeyId::from_parts(
|
||||
DeviceKeyAlgorithm::Ed25519,
|
||||
self.public_key().as_str().into(),
|
||||
)
|
||||
.to_string(),
|
||||
self.public_key().to_string(),
|
||||
);
|
||||
|
||||
|
@ -358,6 +394,7 @@ impl Signing {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub async fn verify(
|
||||
&self,
|
||||
message: &str,
|
||||
|
|
Loading…
Reference in New Issue