-
-
Notifications
You must be signed in to change notification settings - Fork 129
fix: Rerun the full securejoin protocol if the address was outdated #8358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
a9d19bc
fdcfb20
3f2bb38
c9974d0
d8c70da
8fd602b
f4103c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,21 @@ | ||
| //! Bob's side of SecureJoin handling, the joiner-side. | ||
|
|
||
| use anyhow::{Context as _, Result}; | ||
| use pgp::composed::SignedPublicKey; | ||
|
|
||
| use super::HandshakeMessage; | ||
| use super::qrinvite::QrInvite; | ||
| use crate::chat::{self, ChatId, is_contact_in_chat}; | ||
| use crate::constants::{Blocked, Chattype}; | ||
| use crate::contact::{Contact, Origin}; | ||
| use crate::contact::Origin; | ||
| use crate::context::Context; | ||
| use crate::events::EventType; | ||
| use crate::key::self_fingerprint; | ||
| use crate::key::{DcKey as _, self_fingerprint}; | ||
| use crate::log::LogExt; | ||
| use crate::message::{self, Message, MsgId, Viewtype}; | ||
| use crate::mimeparser::{MimeMessage, SystemMessage}; | ||
| use crate::param::{Param, Params}; | ||
| use crate::pgp::addresses_from_public_key; | ||
| use crate::securejoin::{ | ||
| ContactId, encrypted_and_signed, insert_into_smtp, verify_sender_by_fingerprint, | ||
| }; | ||
|
|
@@ -58,14 +60,23 @@ pub(super) async fn start_protocol(context: &Context, invite: QrInvite) -> Resul | |
| QrInvite::Broadcast { .. } => {} | ||
| } | ||
|
|
||
| let has_key = context | ||
| let public_key_bytes: Option<Vec<_>> = context | ||
| .sql | ||
| .exists( | ||
| "SELECT COUNT(*) FROM public_keys WHERE fingerprint=?", | ||
| .query_get_value( | ||
| "SELECT public_key FROM public_keys WHERE fingerprint=?", | ||
| (invite.fingerprint().hex(),), | ||
| ) | ||
| .await?; | ||
|
|
||
| // The key is up to date iff it contains all the addresses from the QR code: | ||
| let has_up_to_date_key = if let Some(public_key_bytes) = public_key_bytes { | ||
| let public_key = SignedPublicKey::from_slice(&public_key_bytes)?; | ||
| let addrs_in_key = addresses_from_public_key(&public_key).unwrap_or_default(); | ||
| invite.addrs().iter().all(|a| addrs_in_key.contains(a)) | ||
| } else { | ||
| false | ||
| }; | ||
|
Comment on lines
+72
to
+78
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a bit unsure whether I prefer this PR here or #8355. For example, this logic here is somewhat hard to read. OTOH, the fix here is more "self-contained" in the securejoin logic, rather than needing logic changes elsewhere.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think it's readable enough. |
||
|
|
||
| // Now start the protocol and initialise the state. | ||
| { | ||
| // `joining_chat_id` is `Some` if group chat | ||
|
|
@@ -97,7 +108,7 @@ pub(super) async fn start_protocol(context: &Context, invite: QrInvite) -> Resul | |
| progress: JoinerProgress::Succeeded.into_u16(), | ||
| }); | ||
| return Ok(joining_chat_id); | ||
| } else if has_key | ||
| } else if has_up_to_date_key | ||
| && verify_sender_by_fingerprint(context, invite.fingerprint(), invite.contact_id()) | ||
| .await? | ||
| { | ||
|
|
@@ -154,7 +165,7 @@ pub(super) async fn start_protocol(context: &Context, invite: QrInvite) -> Resul | |
| QrInvite::Contact { .. } => { | ||
| // For setup-contact the BobState already ensured the 1:1 chat exists because it is | ||
| // used to send the handshake messages. | ||
| if !has_key { | ||
| if !has_up_to_date_key { | ||
| chat::add_info_msg_with_cmd( | ||
| context, | ||
| private_chat_id, | ||
|
|
@@ -310,8 +321,7 @@ pub(crate) async fn send_handshake_message( | |
| if invite.is_v3() && matches!(step, BobHandshakeMsg::Request) { | ||
| // Send a minimal symmetrically-encrypted vc-request-pubkey message | ||
| let rfc724_mid = create_outgoing_rfc724_mid(); | ||
| let contact = Contact::get_by_id(context, invite.contact_id()).await?; | ||
| let recipient = contact.get_addr(); | ||
| let recipients = invite.addrs().join(" "); | ||
| let alice_fp = invite.fingerprint().hex(); | ||
| let auth = invite.authcode(); | ||
| let shared_secret = format!("securejoin/{alice_fp}/{auth}"); | ||
|
|
@@ -327,7 +337,7 @@ pub(crate) async fn send_handshake_message( | |
| .await?; | ||
|
|
||
| let msg_id = message::insert_tombstone(context, &rfc724_mid).await?; | ||
| insert_into_smtp(context, &rfc724_mid, recipient, rendered_message, msg_id).await?; | ||
| insert_into_smtp(context, &rfc724_mid, &recipients, rendered_message, msg_id).await?; | ||
| context.scheduler.interrupt_smtp().await; | ||
| } else { | ||
| let mut msg = Message { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This
unwrap_or_default()hides a corner case when we have a key for a key-contact, but the key has no addresses (because it does not have the notation subpacket). In this case if the address of the key-contact (the one in the contacts table which is usually the last seen From address and the address we are going to send messages to) is the same the address in the invite, there is no need to request a new key.Can be fixed like this: