diff --git a/crates/matrix-sdk/src/authentication/oauth/qrcode/rendezvous_channel/mod.rs b/crates/matrix-sdk/src/authentication/oauth/qrcode/rendezvous_channel/mod.rs index e7d682b76..e9640aa92 100644 --- a/crates/matrix-sdk/src/authentication/oauth/qrcode/rendezvous_channel/mod.rs +++ b/crates/matrix-sdk/src/authentication/oauth/qrcode/rendezvous_channel/mod.rs @@ -140,4 +140,28 @@ impl RendezvousChannel { RendezvousChannel::Msc4388(channel) => Ok(channel.receive().await?), } } + + /// Get additional authenticated data which should be used by the crypto + /// channel to bind individual messages to this specific rendezvous + /// channel run. + /// + /// This is only used in MSC4388, as such only the HPKE crypto channel will + /// use this. + pub(super) fn additional_authenticated_data(&self) -> Option> { + match self { + RendezvousChannel::Msc4108(_) => None, + RendezvousChannel::Msc4388(channel) => { + let msc_4388::Channel { base_url, rendezvous_id, sequence_token, .. } = channel; + + Some( + [ + base_url.as_str().as_bytes(), + rendezvous_id.as_bytes(), + sequence_token.as_bytes(), + ] + .concat(), + ) + } + } + } } diff --git a/crates/matrix-sdk/src/authentication/oauth/qrcode/rendezvous_channel/msc_4388.rs b/crates/matrix-sdk/src/authentication/oauth/qrcode/rendezvous_channel/msc_4388.rs index 25e977826..91448e069 100644 --- a/crates/matrix-sdk/src/authentication/oauth/qrcode/rendezvous_channel/msc_4388.rs +++ b/crates/matrix-sdk/src/authentication/oauth/qrcode/rendezvous_channel/msc_4388.rs @@ -52,9 +52,11 @@ struct RendezvousMessage { pub(crate) struct Channel { client: HttpClient, - base_url: Url, - rendezvous_id: String, - sequence_token: String, + pub(super) base_url: Url, + /// The ID of the rendezvous session we're using to exchange messages + /// through the channel. + pub(super) rendezvous_id: String, + pub(super) sequence_token: String, } fn response_to_error(status: StatusCode, data: String) -> HttpError { diff --git a/crates/matrix-sdk/src/authentication/oauth/qrcode/secure_channel/crypto_channel.rs b/crates/matrix-sdk/src/authentication/oauth/qrcode/secure_channel/crypto_channel.rs index 01ed8a6af..dd2554460 100644 --- a/crates/matrix-sdk/src/authentication/oauth/qrcode/secure_channel/crypto_channel.rs +++ b/crates/matrix-sdk/src/authentication/oauth/qrcode/secure_channel/crypto_channel.rs @@ -67,6 +67,7 @@ impl CryptoChannel { pub(super) fn establish_inbound_channel( self, message: &str, + aad: &[u8], ) -> Result { match self { CryptoChannel::Ecies(ecies) => { @@ -79,7 +80,7 @@ impl CryptoChannel { let message = hpke::InitialMessage::decode(message).map_err(MessageDecodeError::from)?; Ok(CryptoChannelCreationResult::Hpke( - hpke.establish_channel(&message, &[]).map_err(DecryptionError::from)?, + hpke.establish_channel(&message, aad).map_err(DecryptionError::from)?, )) } } diff --git a/crates/matrix-sdk/src/authentication/oauth/qrcode/secure_channel/mod.rs b/crates/matrix-sdk/src/authentication/oauth/qrcode/secure_channel/mod.rs index 124a7794c..19c3b4df6 100644 --- a/crates/matrix-sdk/src/authentication/oauth/qrcode/secure_channel/mod.rs +++ b/crates/matrix-sdk/src/authentication/oauth/qrcode/secure_channel/mod.rs @@ -70,7 +70,7 @@ impl SecureChannel { (crypto_channel, qr_code_data) } - RendezvousInfo::Msc4388 { rendezvous_id } => { + RendezvousInfo::Msc4388 { rendezvous_id, .. } => { let crypto_channel = CryptoChannel::new_hpke(); let qr_code_data = QrCodeData::new_msc4388( @@ -106,7 +106,7 @@ impl SecureChannel { mode_data, ); } - RendezvousInfo::Msc4388 { rendezvous_id } => { + RendezvousInfo::Msc4388 { rendezvous_id, .. } => { channel.qr_code_data = QrCodeData::new_msc4388( channel.crypto_channel.public_key(), rendezvous_id.to_owned(), @@ -127,8 +127,9 @@ impl SecureChannel { pub(super) async fn connect(mut self) -> Result { trace!("Trying to connect the secure channel."); + let aad = self.channel.additional_authenticated_data().unwrap_or_default(); let message = self.channel.receive().await?; - let result = self.crypto_channel.establish_inbound_channel(&message)?; + let result = self.crypto_channel.establish_inbound_channel(&message, &aad)?; let message = std::str::from_utf8(result.plaintext()).map_err(MessageDecodeError::from)?; @@ -148,8 +149,10 @@ impl SecureChannel { secure_channel } CryptoChannelCreationResult::Hpke(RecipientCreationResult { channel, .. }) => { + let aad = self.channel.additional_authenticated_data().unwrap_or_default(); let BidirectionalCreationResult { channel, message } = - channel.establish_bidirectional_channel(LOGIN_OK_MESSAGE.as_bytes(), &[]); + channel.establish_bidirectional_channel(LOGIN_OK_MESSAGE.as_bytes(), &aad); + self.channel.send(message.encode()).await?; let crypto_channel = EstablishedCryptoChannel::Hpke(channel); @@ -213,7 +216,25 @@ impl EstablishedSecureChannel { let client = HttpClient::new(client, RequestConfig::short_retry()); - // Let's establish an outbound ECIES channel, the other side won't know that + // The other side has crated a rendezvous channel, we're going to connect to it + // and send this initial encrypted message through it. The initial message on + // the rendezvous channel will have an empty body, so we can just + // drop it. + let mut channel = match qr_code_data.intent_data() { + QrCodeIntentData::Msc4108 { rendezvous_url, .. } => { + let InboundChannelCreationResult { channel, .. } = + RendezvousChannel::create_inbound(client, rendezvous_url).await?; + channel + } + QrCodeIntentData::Msc4388 { rendezvous_id, base_url } => { + let InboundChannelCreationResult { channel, .. } = + RendezvousChannel::create_inbound_msc4388(client, base_url, rendezvous_id) + .await?; + channel + } + }; + + // Let's establish an outbound crypto channel, the other side won't know that // it's talking to us, the device that scanned the QR code, until it // receives and successfully decrypts the initial message. We're here encrypting // the `LOGIN_INITIATE_MESSAGE`. @@ -230,35 +251,18 @@ impl EstablishedSecureChannel { (ChannelType::Ecies(ecies), message.encode()) } QrCodeIntentData::Msc4388 { .. } => { + let aad = channel.additional_authenticated_data().unwrap_or_default(); + let SenderCreationResult { channel, message } = HpkeSenderChannel::new() .establish_channel( qr_code_data.public_key(), LOGIN_INITIATE_MESSAGE.as_bytes(), - // TODO: Do we want to include some additional authenticated data here? - &[], + &aad, ); (ChannelType::Hpke(channel), message.encode()) } }; - // The other side has crated a rendezvous channel, we're going to connect to it - // and send this initial encrypted message through it. The initial message on - // the rendezvous channel will have an empty body, so we can just - // drop it. - let mut channel = match qr_code_data.intent_data() { - QrCodeIntentData::Msc4108 { rendezvous_url, .. } => { - let InboundChannelCreationResult { channel, .. } = - RendezvousChannel::create_inbound(client, rendezvous_url).await?; - channel - } - QrCodeIntentData::Msc4388 { rendezvous_id, base_url } => { - let InboundChannelCreationResult { channel, .. } = - RendezvousChannel::create_inbound_msc4388(client, base_url, rendezvous_id) - .await?; - channel - } - }; - trace!( "Received the initial message from the rendezvous channel, sending the LOGIN \ INITIATE message" @@ -281,13 +285,14 @@ impl EstablishedSecureChannel { (response, channel) } ChannelType::Hpke(crypto_channel) => { + let aad = channel.additional_authenticated_data().unwrap_or_default(); let response = channel.receive().await?; let response = InitialResponse::decode(&response).map_err(MessageDecodeError::from)?; let BidirectionalCreationResult { channel: crypto_channel, message } = crypto_channel - .establish_bidirectional_channel(&response, &[]) + .establish_bidirectional_channel(&response, &aad) .map_err(DecryptionError::from)?; let response = String::from_utf8(message) .map_err(|e| MessageDecodeError::from(e.utf8_error()))?; @@ -339,13 +344,19 @@ impl EstablishedSecureChannel { } async fn send(&mut self, message: &str) -> Result<(), Error> { - let message = self.crypto_channel.seal(message, &[]); + let aad = self.channel.additional_authenticated_data().unwrap_or_default(); + + let message = self.crypto_channel.seal(message, &aad); Ok(self.channel.send(message).await?) } async fn receive(&mut self) -> Result { + let aad = self.channel.additional_authenticated_data().unwrap_or_default(); + let message = self.channel.receive().await?; - self.crypto_channel.open(&message, &[]) + let decrypted = self.crypto_channel.open(&message, &aad)?; + + Ok(decrypted) } }