crypto: Move the signature verification method under an Utility struct.
parent
22daf0d81e
commit
89efcee337
|
@ -39,9 +39,10 @@ use crate::{Account, OlmMachine};
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{EventError, OlmError, OlmResult, SignatureError},
|
error::{EventError, OlmError, OlmResult, SignatureError},
|
||||||
identities::{OwnUserIdentity, UserIdentities},
|
identities::{OwnUserIdentity, UserIdentities},
|
||||||
|
olm::Utility,
|
||||||
store::{caches::ReadOnlyUserDevices, Result as StoreResult},
|
store::{caches::ReadOnlyUserDevices, Result as StoreResult},
|
||||||
verification::VerificationMachine,
|
verification::VerificationMachine,
|
||||||
verify_json, Sas, ToDeviceRequest,
|
Sas, ToDeviceRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A read-only version of a `Device`.
|
/// A read-only version of a `Device`.
|
||||||
|
@ -362,7 +363,9 @@ impl ReadOnlyDevice {
|
||||||
.get_key(DeviceKeyAlgorithm::Ed25519)
|
.get_key(DeviceKeyAlgorithm::Ed25519)
|
||||||
.ok_or(SignatureError::MissingSigningKey)?;
|
.ok_or(SignatureError::MissingSigningKey)?;
|
||||||
|
|
||||||
verify_json(
|
let utility = Utility::new();
|
||||||
|
|
||||||
|
utility.verify_json(
|
||||||
&self.user_id,
|
&self.user_id,
|
||||||
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
|
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
|
||||||
signing_key,
|
signing_key,
|
||||||
|
|
|
@ -28,7 +28,7 @@ use matrix_sdk_common::{
|
||||||
identifiers::{DeviceKeyId, UserId},
|
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.
|
/// Wrapper for a cross signing key marking it as the master key.
|
||||||
///
|
///
|
||||||
|
@ -157,7 +157,8 @@ impl MasterPubkey {
|
||||||
return Err(SignatureError::UserIdMissmatch);
|
return Err(SignatureError::UserIdMissmatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_json(
|
let utility = Utility::new();
|
||||||
|
utility.verify_json(
|
||||||
&self.0.user_id,
|
&self.0.user_id,
|
||||||
&key_id,
|
&key_id,
|
||||||
key,
|
key,
|
||||||
|
@ -191,7 +192,8 @@ impl UserSigningPubkey {
|
||||||
|
|
||||||
// TODO check that the usage is OK.
|
// TODO check that the usage is OK.
|
||||||
|
|
||||||
verify_json(
|
let utility = Utility::new();
|
||||||
|
utility.verify_json(
|
||||||
&self.0.user_id,
|
&self.0.user_id,
|
||||||
&DeviceKeyId::try_from(key_id.as_str())?,
|
&DeviceKeyId::try_from(key_id.as_str())?,
|
||||||
key,
|
key,
|
||||||
|
@ -224,7 +226,8 @@ impl SelfSigningPubkey {
|
||||||
|
|
||||||
// TODO check that the usage is OK.
|
// TODO check that the usage is OK.
|
||||||
|
|
||||||
verify_json(
|
let utility = Utility::new();
|
||||||
|
utility.verify_json(
|
||||||
&self.0.user_id,
|
&self.0.user_id,
|
||||||
&DeviceKeyId::try_from(key_id.as_str())?,
|
&DeviceKeyId::try_from(key_id.as_str())?,
|
||||||
key,
|
key,
|
||||||
|
|
|
@ -44,74 +44,3 @@ pub(crate) use olm::Account;
|
||||||
pub use olm::EncryptionSettings;
|
pub use olm::EncryptionSettings;
|
||||||
pub use requests::{IncomingResponse, OutgoingRequest, OutgoingRequests, ToDeviceRequest};
|
pub use requests::{IncomingResponse, OutgoingRequest, OutgoingRequests, ToDeviceRequest};
|
||||||
pub use verification::Sas;
|
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
|
|
||||||
}
|
|
||||||
|
|
|
@ -1548,8 +1548,9 @@ pub(crate) mod test {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
machine::OlmMachine,
|
machine::OlmMachine,
|
||||||
|
olm::Utility,
|
||||||
verification::test::{outgoing_request_to_event, request_to_event},
|
verification::test::{outgoing_request_to_event, request_to_event},
|
||||||
verify_json, EncryptionSettings, ReadOnlyDevice, ToDeviceRequest,
|
EncryptionSettings, ReadOnlyDevice, ToDeviceRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
|
@ -1784,7 +1785,8 @@ pub(crate) mod test {
|
||||||
let identity_keys = machine.account.identity_keys();
|
let identity_keys = machine.account.identity_keys();
|
||||||
let ed25519_key = identity_keys.ed25519();
|
let ed25519_key = identity_keys.ed25519();
|
||||||
|
|
||||||
let ret = verify_json(
|
let utility = Utility::new();
|
||||||
|
let ret = utility.verify_json(
|
||||||
&machine.user_id,
|
&machine.user_id,
|
||||||
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()),
|
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()),
|
||||||
ed25519_key,
|
ed25519_key,
|
||||||
|
@ -1815,7 +1817,8 @@ pub(crate) mod test {
|
||||||
|
|
||||||
let mut device_keys = machine.account.device_keys().await;
|
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,
|
&machine.user_id,
|
||||||
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()),
|
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()),
|
||||||
"fake_key",
|
"fake_key",
|
||||||
|
@ -1835,7 +1838,8 @@ pub(crate) mod test {
|
||||||
|
|
||||||
let mut one_time_key = one_time_keys.values_mut().next().unwrap();
|
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,
|
&machine.user_id,
|
||||||
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()),
|
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()),
|
||||||
ed25519_key,
|
ed25519_key,
|
||||||
|
@ -1857,7 +1861,8 @@ pub(crate) mod test {
|
||||||
.await
|
.await
|
||||||
.expect("Can't prepare initial key upload");
|
.expect("Can't prepare initial key upload");
|
||||||
|
|
||||||
let ret = verify_json(
|
let utility = Utility::new();
|
||||||
|
let ret = utility.verify_json(
|
||||||
&machine.user_id,
|
&machine.user_id,
|
||||||
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()),
|
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()),
|
||||||
ed25519_key,
|
ed25519_key,
|
||||||
|
@ -1865,7 +1870,8 @@ pub(crate) mod test {
|
||||||
);
|
);
|
||||||
assert!(ret.is_ok());
|
assert!(ret.is_ok());
|
||||||
|
|
||||||
let ret = verify_json(
|
let utility = Utility::new();
|
||||||
|
let ret = utility.verify_json(
|
||||||
&machine.user_id,
|
&machine.user_id,
|
||||||
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()),
|
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()),
|
||||||
ed25519_key,
|
ed25519_key,
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
mod account;
|
mod account;
|
||||||
mod group_sessions;
|
mod group_sessions;
|
||||||
mod session;
|
mod session;
|
||||||
|
mod utility;
|
||||||
|
|
||||||
pub use account::{Account, AccountPickle, IdentityKeys, PickledAccount};
|
pub use account::{Account, AccountPickle, IdentityKeys, PickledAccount};
|
||||||
pub use group_sessions::{
|
pub use group_sessions::{
|
||||||
|
@ -29,6 +30,7 @@ pub(crate) use group_sessions::{GroupSessionKey, OutboundGroupSession};
|
||||||
pub use olm_rs::PicklingMode;
|
pub use olm_rs::PicklingMode;
|
||||||
pub(crate) use session::OlmMessage;
|
pub(crate) use session::OlmMessage;
|
||||||
pub use session::{PickledSession, Session, SessionPickle};
|
pub use session::{PickledSession, Session, SessionPickle};
|
||||||
|
pub(crate) use utility::Utility;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod test {
|
pub(crate) mod test {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue