crypto: More verification canceling.

master
Damir Jelić 2020-07-27 13:18:00 +02:00
parent da3734ffc7
commit 623f91733e
1 changed files with 91 additions and 50 deletions

View File

@ -196,12 +196,12 @@ impl InnerSas {
match self { match self {
InnerSas::KeyRecieved(s) => { InnerSas::KeyRecieved(s) => {
let sas = s.confirm(); let sas = s.confirm();
let content = sas.get_mac_event_content(); let content = sas.as_content();
(InnerSas::Confirmed(sas), Some(content)) (InnerSas::Confirmed(sas), Some(content))
} }
InnerSas::MacReceived(s) => { InnerSas::MacReceived(s) => {
let sas = s.confirm(); let sas = s.confirm();
let content = sas.get_mac_event_content(); let content = sas.as_content();
(InnerSas::Done(sas), Some(content)) (InnerSas::Done(sas), Some(content))
} }
_ => (self, None), _ => (self, None),
@ -215,21 +215,32 @@ impl InnerSas {
match event { match event {
AnyToDeviceEvent::KeyVerificationAccept(e) => { AnyToDeviceEvent::KeyVerificationAccept(e) => {
if let InnerSas::Created(s) = self { if let InnerSas::Created(s) = self {
let sas = s.into_accepted(e); match s.into_accepted(e) {
let content = sas.get_key_content(); Ok(s) => {
( let content = s.as_content();
InnerSas::Accepted(sas), (
Some(AnyToDeviceEventContent::KeyVerificationKey(content)), InnerSas::Accepted(s),
) Some(AnyToDeviceEventContent::KeyVerificationKey(content)),
)
}
Err(s) => {
let content =
AnyToDeviceEventContent::KeyVerificationCancel(s.as_content());
(InnerSas::Canceled(s), Some(content))
}
}
} else { } else {
(self, None) (self, None)
} }
} }
AnyToDeviceEvent::KeyVerificationKey(e) => match self { AnyToDeviceEvent::KeyVerificationKey(e) => match self {
InnerSas::Accepted(s) => (InnerSas::KeyRecieved(s.into_key_received(e)), None), InnerSas::Accepted(s) => match s.into_key_received(e) {
Ok(s) => (InnerSas::KeyRecieved(s), None),
Err(s) => (InnerSas::Canceled(s), None),
},
InnerSas::Started(s) => { InnerSas::Started(s) => {
let sas = s.into_key_received(e); let sas = s.into_key_received(e);
let content = sas.get_key_content(); let content = sas.as_content();
( (
InnerSas::KeyRecieved(sas), InnerSas::KeyRecieved(sas),
Some(AnyToDeviceEventContent::KeyVerificationKey(content)), Some(AnyToDeviceEventContent::KeyVerificationKey(content)),
@ -369,6 +380,7 @@ struct Started {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct Accepted { struct Accepted {
accepted_protocols: Arc<AcceptedProtocols>, accepted_protocols: Arc<AcceptedProtocols>,
json_start_content: String,
commitment: String, commitment: String,
} }
@ -490,19 +502,39 @@ impl SasState<Created> {
/// ///
/// * `event` - The m.key.verification.accept event that was sent to us by /// * `event` - The m.key.verification.accept event that was sent to us by
/// the other side. /// the other side.
fn into_accepted(self, event: &ToDeviceEvent<AcceptEventContent>) -> SasState<Accepted> { fn into_accepted(
self,
event: &ToDeviceEvent<AcceptEventContent>,
) -> Result<SasState<Accepted>, SasState<Canceled>> {
let content = &event.content; let content = &event.content;
// TODO check that we support the agreed upon protocols, cancel if not. if !Sas::KEY_AGREEMENT_PROTOCOLS.contains(&event.content.key_agreement_protocol)
|| !Sas::HASHES.contains(&event.content.hash)
|| !Sas::MACS.contains(&event.content.message_authentication_code)
|| (!event
.content
.short_authentication_string
.contains(&ShortAuthenticationString::Emoji)
&& !event
.content
.short_authentication_string
.contains(&ShortAuthenticationString::Decimal))
{
Err(self.cancel(CancelCode::UnknownMethod))
} else {
let json_start_content = cjson::to_string(&self.as_content())
.expect("Can't deserialize start event content");
SasState { Ok(SasState {
inner: self.inner, inner: self.inner,
ids: self.ids, ids: self.ids,
verification_flow_id: self.verification_flow_id, verification_flow_id: self.verification_flow_id,
state: Arc::new(Accepted { state: Arc::new(Accepted {
commitment: content.commitment.clone(), json_start_content,
accepted_protocols: Arc::new(content.clone().into()), commitment: content.commitment.clone(),
}), accepted_protocols: Arc::new(content.clone().into()),
}),
})
} }
} }
} }
@ -652,29 +684,38 @@ impl SasState<Accepted> {
fn into_key_received( fn into_key_received(
self, self,
event: &mut ToDeviceEvent<KeyEventContent>, event: &mut ToDeviceEvent<KeyEventContent>,
) -> SasState<KeyReceived> { ) -> Result<SasState<KeyReceived>, SasState<Canceled>> {
// TODO check the commitment here since we started the SAS dance. let utility = OlmUtility::new();
self.inner let commitment = utility.sha256_utf8_msg(&format!(
.lock() "{}{}",
.unwrap() event.content.key, self.state.json_start_content
.set_their_public_key(&mem::take(&mut event.content.key)) ));
.expect("Can't set public key");
SasState { if self.state.commitment != commitment {
inner: self.inner, Err(self.cancel(CancelCode::InvalidMessage))
ids: self.ids, } else {
verification_flow_id: self.verification_flow_id, self.inner
state: Arc::new(KeyReceived { .lock()
we_started: true, .unwrap()
accepted_protocols: self.state.accepted_protocols.clone(), .set_their_public_key(&mem::take(&mut event.content.key))
}), .expect("Can't set public key");
Ok(SasState {
inner: self.inner,
ids: self.ids,
verification_flow_id: self.verification_flow_id,
state: Arc::new(KeyReceived {
we_started: true,
accepted_protocols: self.state.accepted_protocols.clone(),
}),
})
} }
} }
/// Get the content for the key event. /// Get the content for the key event.
/// ///
/// The content needs to be automatically sent to the other side. /// The content needs to be automatically sent to the other side.
fn get_key_content(&self) -> KeyEventContent { fn as_content(&self) -> KeyEventContent {
KeyEventContent { KeyEventContent {
transaction_id: self.verification_flow_id.to_string(), transaction_id: self.verification_flow_id.to_string(),
key: self.inner.lock().unwrap().public_key(), key: self.inner.lock().unwrap().public_key(),
@ -687,7 +728,7 @@ impl SasState<KeyReceived> {
/// ///
/// The content needs to be automatically sent to the other side if and only /// The content needs to be automatically sent to the other side if and only
/// if we_started is false. /// if we_started is false.
fn get_key_content(&self) -> KeyEventContent { fn as_content(&self) -> KeyEventContent {
KeyEventContent { KeyEventContent {
transaction_id: self.verification_flow_id.to_string(), transaction_id: self.verification_flow_id.to_string(),
key: self.inner.lock().unwrap().public_key(), key: self.inner.lock().unwrap().public_key(),
@ -793,7 +834,7 @@ impl SasState<Confirmed> {
/// Get the content for the mac event. /// Get the content for the mac event.
/// ///
/// The content needs to be automatically sent to the other side. /// The content needs to be automatically sent to the other side.
fn get_mac_event_content(&self) -> MacEventContent { fn as_content(&self) -> MacEventContent {
get_mac_content( get_mac_content(
&self.inner.lock().unwrap(), &self.inner.lock().unwrap(),
&self.ids, &self.ids,
@ -851,7 +892,7 @@ impl SasState<Done> {
/// ///
/// The content needs to be automatically sent to the other side if it /// The content needs to be automatically sent to the other side if it
/// wasn't already sent. /// wasn't already sent.
fn get_mac_event_content(&self) -> MacEventContent { fn as_content(&self) -> MacEventContent {
get_mac_content( get_mac_content(
&self.inner.lock().unwrap(), &self.inner.lock().unwrap(),
&self.ids, &self.ids,
@ -986,7 +1027,7 @@ mod test {
let event = wrap_to_device_event(bob.user_id(), bob.as_content()); let event = wrap_to_device_event(bob.user_id(), bob.as_content());
alice.into_accepted(&event); alice.into_accepted(&event).unwrap();
} }
#[tokio::test] #[tokio::test]
@ -995,14 +1036,14 @@ mod test {
let event = wrap_to_device_event(bob.user_id(), bob.as_content()); let event = wrap_to_device_event(bob.user_id(), bob.as_content());
let alice: SasState<Accepted> = alice.into_accepted(&event); let alice: SasState<Accepted> = alice.into_accepted(&event).unwrap();
let mut event = wrap_to_device_event(alice.user_id(), alice.get_key_content()); let mut event = wrap_to_device_event(alice.user_id(), alice.as_content());
let bob = bob.into_key_received(&mut event); let bob = bob.into_key_received(&mut event);
let mut event = wrap_to_device_event(bob.user_id(), bob.get_key_content()); let mut event = wrap_to_device_event(bob.user_id(), bob.as_content());
let alice = alice.into_key_received(&mut event); let alice = alice.into_key_received(&mut event).unwrap();
assert_eq!(alice.get_decimal(), bob.get_decimal()); assert_eq!(alice.get_decimal(), bob.get_decimal());
assert_eq!(alice.get_emoji(), bob.get_emoji()); assert_eq!(alice.get_emoji(), bob.get_emoji());
@ -1014,27 +1055,27 @@ mod test {
let event = wrap_to_device_event(bob.user_id(), bob.as_content()); let event = wrap_to_device_event(bob.user_id(), bob.as_content());
let alice: SasState<Accepted> = alice.into_accepted(&event); let alice: SasState<Accepted> = alice.into_accepted(&event).unwrap();
let mut event = wrap_to_device_event(alice.user_id(), alice.get_key_content()); let mut event = wrap_to_device_event(alice.user_id(), alice.as_content());
let bob = bob.into_key_received(&mut event); let bob = bob.into_key_received(&mut event);
let mut event = wrap_to_device_event(bob.user_id(), bob.get_key_content()); let mut event = wrap_to_device_event(bob.user_id(), bob.as_content());
let alice = alice.into_key_received(&mut event); let alice = alice.into_key_received(&mut event).unwrap();
assert_eq!(alice.get_decimal(), bob.get_decimal()); assert_eq!(alice.get_decimal(), bob.get_decimal());
assert_eq!(alice.get_emoji(), bob.get_emoji()); assert_eq!(alice.get_emoji(), bob.get_emoji());
let bob = bob.confirm(); let bob = bob.confirm();
let event = wrap_to_device_event(bob.user_id(), bob.get_mac_event_content()); let event = wrap_to_device_event(bob.user_id(), bob.as_content());
let alice = alice.into_mac_received(&event); let alice = alice.into_mac_received(&event);
assert!(!alice.get_emoji().is_empty()); assert!(!alice.get_emoji().is_empty());
let alice = alice.confirm(); let alice = alice.confirm();
let event = wrap_to_device_event(alice.user_id(), alice.get_mac_event_content()); let event = wrap_to_device_event(alice.user_id(), alice.as_content());
let bob = bob.into_done(&event); let bob = bob.into_done(&event);
assert!(bob.verified_devices().contains(&alice.device_id().into())); assert!(bob.verified_devices().contains(&alice.device_id().into()));