crypto: Add a method to check it the SAS flow supports emoji

master
Damir Jelić 2021-05-12 14:30:36 +02:00
parent 9863bc4a1c
commit 4f7902d6f0
4 changed files with 155 additions and 69 deletions

View File

@ -121,6 +121,12 @@ impl Sas {
self.inner.decimals() self.inner.decimals()
} }
/// Does this verification flow support emoji for the short authentication
/// string.
pub fn supports_emoji(&self) -> bool {
self.inner.supports_emoji()
}
/// Is the verification process done. /// Is the verification process done.
pub fn is_done(&self) -> bool { pub fn is_done(&self) -> bool {
self.inner.is_done() self.inner.is_done()

View File

@ -18,7 +18,10 @@ use std::time::Instant;
use std::sync::Arc; use std::sync::Arc;
use matrix_sdk_common::{ use matrix_sdk_common::{
events::{key::verification::cancel::CancelCode, AnyMessageEvent, AnyToDeviceEvent}, events::{
key::verification::{cancel::CancelCode, ShortAuthenticationString},
AnyMessageEvent, AnyToDeviceEvent,
},
identifiers::{EventId, RoomId}, identifiers::{EventId, RoomId},
}; };
@ -61,6 +64,37 @@ impl InnerSas {
(InnerSas::Created(sas), content) (InnerSas::Created(sas), content)
} }
pub fn supports_emoji(&self) -> bool {
match self {
InnerSas::Created(_) => false,
InnerSas::Started(s) => s
.state
.accepted_protocols
.short_auth_string
.contains(&ShortAuthenticationString::Emoji),
InnerSas::Accepted(s) => s
.state
.accepted_protocols
.short_auth_string
.contains(&ShortAuthenticationString::Emoji),
InnerSas::KeyRecieved(s) => s
.state
.accepted_protocols
.short_auth_string
.contains(&ShortAuthenticationString::Emoji),
InnerSas::Confirmed(_) => false,
InnerSas::MacReceived(s) => s
.state
.accepted_protocols
.short_auth_string
.contains(&ShortAuthenticationString::Emoji),
InnerSas::WaitingForDone(_) => false,
InnerSas::WaitingForDoneUnconfirmed(_) => false,
InnerSas::Done(_) => false,
InnerSas::Canceled(_) => false,
}
}
pub fn start_in_room( pub fn start_in_room(
event_id: EventId, event_id: EventId,
room_id: RoomId, room_id: RoomId,

View File

@ -110,6 +110,12 @@ impl Sas {
&self.flow_id &self.flow_id
} }
/// Does this verification flow support displaying emoji for the short
/// authentication string.
pub fn supports_emoji(&self) -> bool {
self.inner.lock().unwrap().supports_emoji()
}
#[cfg(test)] #[cfg(test)]
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) fn set_creation_time(&self, time: Instant) { pub(crate) fn set_creation_time(&self, time: Instant) {

View File

@ -98,12 +98,12 @@ impl FlowId {
/// Struct containing the protocols that were agreed to be used for the SAS /// Struct containing the protocols that were agreed to be used for the SAS
/// flow. /// flow.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct AcceptedProtocols { pub struct AcceptedProtocols {
method: VerificationMethod, pub method: VerificationMethod,
key_agreement_protocol: KeyAgreementProtocol, pub key_agreement_protocol: KeyAgreementProtocol,
hash: HashAlgorithm, pub hash: HashAlgorithm,
message_auth_code: MessageAuthenticationCode, pub message_auth_code: MessageAuthenticationCode,
short_auth_string: Vec<ShortAuthenticationString>, pub short_auth_string: Vec<ShortAuthenticationString>,
} }
impl TryFrom<AcceptV1Content> for AcceptedProtocols { impl TryFrom<AcceptV1Content> for AcceptedProtocols {
@ -133,6 +133,53 @@ impl TryFrom<AcceptV1Content> for AcceptedProtocols {
} }
} }
impl TryFrom<&MSasV1Content> for AcceptedProtocols {
type Error = CancelCode;
fn try_from(method_content: &MSasV1Content) -> Result<Self, Self::Error> {
if !method_content
.key_agreement_protocols
.contains(&KeyAgreementProtocol::Curve25519HkdfSha256)
|| !method_content
.message_authentication_codes
.contains(&MessageAuthenticationCode::HkdfHmacSha256)
|| !method_content.hashes.contains(&HashAlgorithm::Sha256)
|| (!method_content
.short_authentication_string
.contains(&ShortAuthenticationString::Decimal)
&& !method_content
.short_authentication_string
.contains(&ShortAuthenticationString::Emoji))
{
Err(CancelCode::UnknownMethod)
} else {
let mut short_auth_string = vec![];
if method_content
.short_authentication_string
.contains(&ShortAuthenticationString::Decimal)
{
short_auth_string.push(ShortAuthenticationString::Decimal)
}
if method_content
.short_authentication_string
.contains(&ShortAuthenticationString::Emoji)
{
short_auth_string.push(ShortAuthenticationString::Emoji);
}
Ok(Self {
method: VerificationMethod::MSasV1,
hash: HashAlgorithm::Sha256,
key_agreement_protocol: KeyAgreementProtocol::Curve25519HkdfSha256,
message_auth_code: MessageAuthenticationCode::HkdfHmacSha256,
short_auth_string,
})
}
}
}
#[cfg(not(tarpaulin_include))] #[cfg(not(tarpaulin_include))]
impl Default for AcceptedProtocols { impl Default for AcceptedProtocols {
fn default() -> Self { fn default() -> Self {
@ -176,7 +223,7 @@ pub struct SasState<S: Clone> {
pub verification_flow_id: Arc<FlowId>, pub verification_flow_id: Arc<FlowId>,
/// The SAS state we're in. /// The SAS state we're in.
state: Arc<S>, pub state: Arc<S>,
} }
#[cfg(not(tarpaulin_include))] #[cfg(not(tarpaulin_include))]
@ -200,14 +247,14 @@ pub struct Created {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Started { pub struct Started {
commitment: String, commitment: String,
protocol_definitions: MSasV1Content, pub accepted_protocols: Arc<AcceptedProtocols>,
} }
/// The SAS state we're going to be in after the other side accepted our /// The SAS state we're going to be in after the other side accepted our
/// verification start event. /// verification start event.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Accepted { pub struct Accepted {
accepted_protocols: Arc<AcceptedProtocols>, pub accepted_protocols: Arc<AcceptedProtocols>,
start_content: Arc<StartContent>, start_content: Arc<StartContent>,
commitment: String, commitment: String,
} }
@ -220,7 +267,7 @@ pub struct Accepted {
pub struct KeyReceived { pub struct KeyReceived {
their_pubkey: String, their_pubkey: String,
we_started: bool, we_started: bool,
accepted_protocols: Arc<AcceptedProtocols>, pub accepted_protocols: Arc<AcceptedProtocols>,
} }
/// The SAS state we're going to be in after the user has confirmed that the /// The SAS state we're going to be in after the user has confirmed that the
@ -228,7 +275,7 @@ pub struct KeyReceived {
/// other side. /// other side.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Confirmed { pub struct Confirmed {
accepted_protocols: Arc<AcceptedProtocols>, pub accepted_protocols: Arc<AcceptedProtocols>,
} }
/// The SAS state we're going to be in after we receive a MAC event from the /// The SAS state we're going to be in after we receive a MAC event from the
@ -240,6 +287,7 @@ pub struct MacReceived {
their_pubkey: String, their_pubkey: String,
verified_devices: Arc<[ReadOnlyDevice]>, verified_devices: Arc<[ReadOnlyDevice]>,
verified_master_keys: Arc<[UserIdentities]>, verified_master_keys: Arc<[UserIdentities]>,
pub accepted_protocols: Arc<AcceptedProtocols>,
} }
/// The SAS state we're going to be in after we receive a MAC event in a DM. DMs /// The SAS state we're going to be in after we receive a MAC event in a DM. DMs
@ -490,6 +538,22 @@ impl SasState<Started> {
other_identity: Option<UserIdentities>, other_identity: Option<UserIdentities>,
content: &StartContent, content: &StartContent,
) -> Result<SasState<Started>, SasState<Canceled>> { ) -> Result<SasState<Started>, SasState<Canceled>> {
let canceled = || SasState {
inner: Arc::new(Mutex::new(OlmSas::new())),
creation_time: Arc::new(Instant::now()),
last_event_time: Arc::new(Instant::now()),
ids: SasIds {
account: account.clone(),
other_device: other_device.clone(),
other_identity: other_identity.clone(),
},
verification_flow_id: content.flow_id().into(),
state: Arc::new(Canceled::new(CancelCode::UnknownMethod)),
};
if let StartMethod::MSasV1(method_content) = content.method() { if let StartMethod::MSasV1(method_content) = content.method() {
let sas = OlmSas::new(); let sas = OlmSas::new();
@ -501,60 +565,31 @@ impl SasState<Started> {
pubkey, content, commitment pubkey, content, commitment
); );
let sas = SasState { if let Ok(accepted_protocols) = AcceptedProtocols::try_from(method_content) {
inner: Arc::new(Mutex::new(sas)), Ok(SasState {
inner: Arc::new(Mutex::new(sas)),
ids: SasIds { ids: SasIds {
account, account,
other_device, other_device,
other_identity, other_identity,
}, },
creation_time: Arc::new(Instant::now()), creation_time: Arc::new(Instant::now()),
last_event_time: Arc::new(Instant::now()), last_event_time: Arc::new(Instant::now()),
verification_flow_id: content.flow_id().into(), verification_flow_id: content.flow_id().into(),
state: Arc::new(Started { state: Arc::new(Started {
protocol_definitions: method_content.clone(), accepted_protocols: accepted_protocols.into(),
commitment, commitment,
}), }),
}; })
if !method_content
.key_agreement_protocols
.contains(&KeyAgreementProtocol::Curve25519HkdfSha256)
|| !method_content
.message_authentication_codes
.contains(&MessageAuthenticationCode::HkdfHmacSha256)
|| !method_content.hashes.contains(&HashAlgorithm::Sha256)
|| (!method_content
.short_authentication_string
.contains(&ShortAuthenticationString::Decimal)
&& !method_content
.short_authentication_string
.contains(&ShortAuthenticationString::Emoji))
{
Err(sas.cancel(CancelCode::UnknownMethod))
} else { } else {
Ok(sas) Err(canceled())
} }
} else { } else {
Err(SasState { Err(canceled())
inner: Arc::new(Mutex::new(OlmSas::new())),
creation_time: Arc::new(Instant::now()),
last_event_time: Arc::new(Instant::now()),
ids: SasIds {
account,
other_device,
other_identity,
},
verification_flow_id: content.flow_id().into(),
state: Arc::new(Canceled::new(CancelCode::UnknownMethod)),
})
} }
} }
@ -566,18 +601,24 @@ impl SasState<Started> {
/// been started because of a /// been started because of a
/// m.key.verification.request -> m.key.verification.ready flow. /// m.key.verification.request -> m.key.verification.ready flow.
pub fn as_content(&self) -> AcceptContent { pub fn as_content(&self) -> AcceptContent {
let accepted_protocols = AcceptedProtocols::default();
let method = AcceptMethod::MSasV1( let method = AcceptMethod::MSasV1(
AcceptV1ContentInit { AcceptV1ContentInit {
commitment: self.state.commitment.clone(), commitment: self.state.commitment.clone(),
hash: accepted_protocols.hash, hash: self.state.accepted_protocols.hash.clone(),
key_agreement_protocol: accepted_protocols.key_agreement_protocol, key_agreement_protocol: self
message_authentication_code: accepted_protocols.message_auth_code, .state
.accepted_protocols
.key_agreement_protocol
.clone(),
message_authentication_code: self
.state
.accepted_protocols
.message_auth_code
.clone(),
short_authentication_string: self short_authentication_string: self
.state .state
.protocol_definitions .accepted_protocols
.short_authentication_string .short_auth_string
.clone(), .clone(),
} }
.into(), .into(),
@ -620,8 +661,6 @@ impl SasState<Started> {
self.check_event(&sender, &content.flow_id().as_str()) self.check_event(&sender, &content.flow_id().as_str())
.map_err(|c| self.clone().cancel(c))?; .map_err(|c| self.clone().cancel(c))?;
let accepted_protocols = AcceptedProtocols::default();
let their_pubkey = content.public_key().to_owned(); let their_pubkey = content.public_key().to_owned();
self.inner self.inner
@ -639,7 +678,7 @@ impl SasState<Started> {
state: Arc::new(KeyReceived { state: Arc::new(KeyReceived {
we_started: false, we_started: false,
their_pubkey, their_pubkey,
accepted_protocols: Arc::new(accepted_protocols), accepted_protocols: self.state.accepted_protocols.clone(),
}), }),
}) })
} }
@ -823,6 +862,7 @@ impl SasState<KeyReceived> {
their_pubkey: self.state.their_pubkey.clone(), their_pubkey: self.state.their_pubkey.clone(),
verified_devices: devices.into(), verified_devices: devices.into(),
verified_master_keys: master_keys.into(), verified_master_keys: master_keys.into(),
accepted_protocols: self.state.accepted_protocols.clone(),
}), }),
}) })
} }