From 89efcee337443cd446e99f40b9ccf69edb16715e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 4 Sep 2020 13:14:01 +0200 Subject: [PATCH] crypto: Move the signature verification method under an Utility struct. --- matrix_sdk_crypto/src/identities/device.rs | 7 +- matrix_sdk_crypto/src/identities/user.rs | 11 ++- matrix_sdk_crypto/src/lib.rs | 71 ---------------- matrix_sdk_crypto/src/machine.rs | 18 ++-- matrix_sdk_crypto/src/olm/mod.rs | 2 + matrix_sdk_crypto/src/olm/utility.rs | 98 ++++++++++++++++++++++ 6 files changed, 124 insertions(+), 83 deletions(-) create mode 100644 matrix_sdk_crypto/src/olm/utility.rs diff --git a/matrix_sdk_crypto/src/identities/device.rs b/matrix_sdk_crypto/src/identities/device.rs index 55fe5594..039e9c87 100644 --- a/matrix_sdk_crypto/src/identities/device.rs +++ b/matrix_sdk_crypto/src/identities/device.rs @@ -39,9 +39,10 @@ use crate::{Account, OlmMachine}; use crate::{ error::{EventError, OlmError, OlmResult, SignatureError}, identities::{OwnUserIdentity, UserIdentities}, + olm::Utility, store::{caches::ReadOnlyUserDevices, Result as StoreResult}, verification::VerificationMachine, - verify_json, Sas, ToDeviceRequest, + Sas, ToDeviceRequest, }; /// A read-only version of a `Device`. @@ -362,7 +363,9 @@ impl ReadOnlyDevice { .get_key(DeviceKeyAlgorithm::Ed25519) .ok_or(SignatureError::MissingSigningKey)?; - verify_json( + let utility = Utility::new(); + + utility.verify_json( &self.user_id, &DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()), signing_key, diff --git a/matrix_sdk_crypto/src/identities/user.rs b/matrix_sdk_crypto/src/identities/user.rs index 7d7acfad..1444e7ac 100644 --- a/matrix_sdk_crypto/src/identities/user.rs +++ b/matrix_sdk_crypto/src/identities/user.rs @@ -28,7 +28,7 @@ use matrix_sdk_common::{ identifiers::{DeviceKeyId, UserId}, }; -use crate::{error::SignatureError, verify_json, ReadOnlyDevice}; +use crate::{error::SignatureError, olm::Utility, ReadOnlyDevice}; /// Wrapper for a cross signing key marking it as the master key. /// @@ -157,7 +157,8 @@ impl MasterPubkey { return Err(SignatureError::UserIdMissmatch); } - verify_json( + let utility = Utility::new(); + utility.verify_json( &self.0.user_id, &key_id, key, @@ -191,7 +192,8 @@ impl UserSigningPubkey { // TODO check that the usage is OK. - verify_json( + let utility = Utility::new(); + utility.verify_json( &self.0.user_id, &DeviceKeyId::try_from(key_id.as_str())?, key, @@ -224,7 +226,8 @@ impl SelfSigningPubkey { // TODO check that the usage is OK. - verify_json( + let utility = Utility::new(); + utility.verify_json( &self.0.user_id, &DeviceKeyId::try_from(key_id.as_str())?, key, diff --git a/matrix_sdk_crypto/src/lib.rs b/matrix_sdk_crypto/src/lib.rs index 1ede88bb..959ffe97 100644 --- a/matrix_sdk_crypto/src/lib.rs +++ b/matrix_sdk_crypto/src/lib.rs @@ -44,74 +44,3 @@ pub(crate) use olm::Account; pub use olm::EncryptionSettings; pub use requests::{IncomingResponse, OutgoingRequest, OutgoingRequests, ToDeviceRequest}; pub use verification::Sas; - -use error::SignatureError; -use matrix_sdk_common::identifiers::{DeviceKeyAlgorithm, DeviceKeyId, UserId}; -use olm_rs::utility::OlmUtility; -use serde_json::Value; - -/// Verify a signed JSON object. -/// -/// The object must have a signatures key associated with an object of the -/// form `user_id: {key_id: signature}`. -/// -/// Returns Ok if the signature was successfully verified, otherwise an -/// SignatureError. -/// -/// # Arguments -/// -/// * `user_id` - The user who signed the JSON object. -/// -/// * `key_id` - The id of the key that signed the JSON object. -/// -/// * `signing_key` - The public ed25519 key which was used to sign the JSON -/// object. -/// -/// * `json` - The JSON object that should be verified. -pub(crate) fn verify_json( - user_id: &UserId, - key_id: &DeviceKeyId, - signing_key: &str, - json: &mut Value, -) -> Result<(), SignatureError> { - if key_id.algorithm() != DeviceKeyAlgorithm::Ed25519 { - return Err(SignatureError::UnsupportedAlgorithm); - } - - let json_object = json.as_object_mut().ok_or(SignatureError::NotAnObject)?; - let unsigned = json_object.remove("unsigned"); - let signatures = json_object.remove("signatures"); - - let canonical_json = cjson::to_string(json_object)?; - - if let Some(u) = unsigned { - json_object.insert("unsigned".to_string(), u); - } - - let signatures = signatures.ok_or(SignatureError::NoSignatureFound)?; - let signature_object = signatures - .as_object() - .ok_or(SignatureError::NoSignatureFound)?; - let signature = signature_object - .get(user_id.as_str()) - .ok_or(SignatureError::NoSignatureFound)?; - let signature = signature - .get(key_id.to_string()) - .ok_or(SignatureError::NoSignatureFound)?; - let signature = signature.as_str().ok_or(SignatureError::NoSignatureFound)?; - - let utility = OlmUtility::new(); - - let ret = if utility - .ed25519_verify(signing_key, &canonical_json, signature) - .is_ok() - { - Ok(()) - } else { - Err(SignatureError::VerificationError) - }; - - json_object.insert("signatures".to_string(), signatures); - - ret -} diff --git a/matrix_sdk_crypto/src/machine.rs b/matrix_sdk_crypto/src/machine.rs index 6a06acbe..a0935c27 100644 --- a/matrix_sdk_crypto/src/machine.rs +++ b/matrix_sdk_crypto/src/machine.rs @@ -1548,8 +1548,9 @@ pub(crate) mod test { use crate::{ machine::OlmMachine, + olm::Utility, verification::test::{outgoing_request_to_event, request_to_event}, - verify_json, EncryptionSettings, ReadOnlyDevice, ToDeviceRequest, + EncryptionSettings, ReadOnlyDevice, ToDeviceRequest, }; use matrix_sdk_common::{ @@ -1784,7 +1785,8 @@ pub(crate) mod test { let identity_keys = machine.account.identity_keys(); let ed25519_key = identity_keys.ed25519(); - let ret = verify_json( + let utility = Utility::new(); + let ret = utility.verify_json( &machine.user_id, &DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()), ed25519_key, @@ -1815,7 +1817,8 @@ pub(crate) mod test { let mut device_keys = machine.account.device_keys().await; - let ret = verify_json( + let utility = Utility::new(); + let ret = utility.verify_json( &machine.user_id, &DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()), "fake_key", @@ -1835,7 +1838,8 @@ pub(crate) mod test { let mut one_time_key = one_time_keys.values_mut().next().unwrap(); - let ret = verify_json( + let utility = Utility::new(); + let ret = utility.verify_json( &machine.user_id, &DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()), ed25519_key, @@ -1857,7 +1861,8 @@ pub(crate) mod test { .await .expect("Can't prepare initial key upload"); - let ret = verify_json( + let utility = Utility::new(); + let ret = utility.verify_json( &machine.user_id, &DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()), ed25519_key, @@ -1865,7 +1870,8 @@ pub(crate) mod test { ); assert!(ret.is_ok()); - let ret = verify_json( + let utility = Utility::new(); + let ret = utility.verify_json( &machine.user_id, &DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()), ed25519_key, diff --git a/matrix_sdk_crypto/src/olm/mod.rs b/matrix_sdk_crypto/src/olm/mod.rs index 3694b7c8..c69293c5 100644 --- a/matrix_sdk_crypto/src/olm/mod.rs +++ b/matrix_sdk_crypto/src/olm/mod.rs @@ -20,6 +20,7 @@ mod account; mod group_sessions; mod session; +mod utility; pub use account::{Account, AccountPickle, IdentityKeys, PickledAccount}; pub use group_sessions::{ @@ -29,6 +30,7 @@ pub(crate) use group_sessions::{GroupSessionKey, OutboundGroupSession}; pub use olm_rs::PicklingMode; pub(crate) use session::OlmMessage; pub use session::{PickledSession, Session, SessionPickle}; +pub(crate) use utility::Utility; #[cfg(test)] pub(crate) mod test { diff --git a/matrix_sdk_crypto/src/olm/utility.rs b/matrix_sdk_crypto/src/olm/utility.rs new file mode 100644 index 00000000..afa73a6b --- /dev/null +++ b/matrix_sdk_crypto/src/olm/utility.rs @@ -0,0 +1,98 @@ +// Copyright 2020 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use olm_rs::utility::OlmUtility; +use serde_json::Value; + +use matrix_sdk_common::identifiers::{DeviceKeyAlgorithm, DeviceKeyId, UserId}; + +use crate::error::SignatureError; + +pub(crate) struct Utility { + inner: OlmUtility, +} + +impl Utility { + pub fn new() -> Self { + Self { + inner: OlmUtility::new(), + } + } + + /// Verify a signed JSON object. + /// + /// The object must have a signatures key associated with an object of the + /// form `user_id: {key_id: signature}`. + /// + /// Returns Ok if the signature was successfully verified, otherwise an + /// SignatureError. + /// + /// # Arguments + /// + /// * `user_id` - The user who signed the JSON object. + /// + /// * `key_id` - The id of the key that signed the JSON object. + /// + /// * `signing_key` - The public ed25519 key which was used to sign the JSON + /// object. + /// + /// * `json` - The JSON object that should be verified. + pub(crate) fn verify_json( + &self, + user_id: &UserId, + key_id: &DeviceKeyId, + signing_key: &str, + json: &mut Value, + ) -> Result<(), SignatureError> { + if key_id.algorithm() != DeviceKeyAlgorithm::Ed25519 { + return Err(SignatureError::UnsupportedAlgorithm); + } + + let json_object = json.as_object_mut().ok_or(SignatureError::NotAnObject)?; + let unsigned = json_object.remove("unsigned"); + let signatures = json_object.remove("signatures"); + + let canonical_json = cjson::to_string(json_object)?; + + if let Some(u) = unsigned { + json_object.insert("unsigned".to_string(), u); + } + + let signatures = signatures.ok_or(SignatureError::NoSignatureFound)?; + let signature_object = signatures + .as_object() + .ok_or(SignatureError::NoSignatureFound)?; + let signature = signature_object + .get(user_id.as_str()) + .ok_or(SignatureError::NoSignatureFound)?; + let signature = signature + .get(key_id.to_string()) + .ok_or(SignatureError::NoSignatureFound)?; + let signature = signature.as_str().ok_or(SignatureError::NoSignatureFound)?; + + let ret = if self + .inner + .ed25519_verify(signing_key, &canonical_json, signature) + .is_ok() + { + Ok(()) + } else { + Err(SignatureError::VerificationError) + }; + + json_object.insert("signatures".to_string(), signatures); + + ret + } +}