Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions crates/xmtp_configuration/src/common/mls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ pub const MLS_PROTOCOL_VERSION: ProtocolVersion = ProtocolVersion::Mls10;

pub const WELCOME_HPKE_LABEL: &str = "MLS_WELCOME";

/// HPKE domain-separation label for external-invite GroupInfo payloads
/// wrapped via [`payload_encryption::wrap_payload_hpke`]. Distinct from
/// [`WELCOME_HPKE_LABEL`] to prevent cross-protocol oracle attacks.
///
/// The v1 external-invite flow uses symmetric AEAD encryption only (see
/// `xmtp_mls_common::invite::encrypted_group_info`), but the label is
/// reserved here so a future HPKE-based external-invite path can adopt it
/// without churning the public API.
///
/// [`payload_encryption::wrap_payload_hpke`]: https://docs.rs/xmtp_mls_common/latest/xmtp_mls_common/mls_ext/payload_encryption/fn.wrap_payload_hpke.html
pub const XMTP_EXTERNAL_INVITE_LABEL: &str = "XMTP_EXTERNAL_INVITE";

pub const MAX_GROUP_SYNC_RETRIES: usize = 3;

pub const MAX_INTENT_PUBLISH_ATTEMPTS: usize = 3;
Expand Down
24 changes: 12 additions & 12 deletions crates/xmtp_mls/src/groups/mls_ext/decrypted_welcome.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,18 @@ impl DecryptedWelcome {
}
};

let decrypted_welcome_data = unwrap_payload_symmetric(
v1.data.as_slice(),
aead_type,
&decrypted_welcome_pointer.encryption_key,
&decrypted_welcome_pointer.data_nonce,
)?;
let decrypted_welcome_metadata = unwrap_payload_symmetric(
v1.welcome_metadata.as_slice(),
aead_type,
&decrypted_welcome_pointer.encryption_key,
&decrypted_welcome_pointer.welcome_metadata_nonce,
)?;
let decrypted_welcome_data = unwrap_payload_symmetric()
.data(v1.data.as_slice())
.aead_type(aead_type)
.symmetric_key(&decrypted_welcome_pointer.encryption_key)
.nonce(&decrypted_welcome_pointer.data_nonce)
.call()?;
let decrypted_welcome_metadata = unwrap_payload_symmetric()
.data(v1.welcome_metadata.as_slice())
.aead_type(aead_type)
.symmetric_key(&decrypted_welcome_pointer.encryption_key)
.nonce(&decrypted_welcome_pointer.welcome_metadata_nonce)
.call()?;
let welcome = deserialize_welcome(&decrypted_welcome_data)?;
let welcome_metadata = Some(decrypted_welcome_metadata.as_slice())
.filter(|data| !data.is_empty())
Expand Down
24 changes: 12 additions & 12 deletions crates/xmtp_mls/src/groups/mls_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4066,18 +4066,18 @@ where
}

let aead_type = crate::groups::mls_ext::WelcomePointersExtension::preferred_type();
let data = wrap_payload_symmetric(
&action.welcome_message,
aead_type,
symmetric_key.as_ref(),
data_nonce.as_ref(),
)?;
let welcome_metadata = wrap_payload_symmetric(
&welcome_metadata_bytes,
aead_type,
symmetric_key.as_ref(),
welcome_metadata_nonce.as_ref(),
)?;
let data = wrap_payload_symmetric()
.data(&action.welcome_message)
.aead_type(aead_type)
.symmetric_key(symmetric_key.as_ref())
.nonce(data_nonce.as_ref())
.call()?;
let welcome_metadata = wrap_payload_symmetric()
.data(&welcome_metadata_bytes)
.aead_type(aead_type)
.symmetric_key(symmetric_key.as_ref())
.nonce(welcome_metadata_nonce.as_ref())
.call()?;

let welcome_pointee = WelcomeMessageInput {
version: Some(WelcomeMessageInputVersion::V1(WelcomeMessageInputV1 {
Expand Down
85 changes: 46 additions & 39 deletions crates/xmtp_mls/src/groups/tests/test_welcome_pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,34 +277,39 @@ fn test_welcome_pointer_encryption_round_trip() {
let aead_type = available_types.supported_aead_types.first().unwrap();

// Test encryption
let encrypted_welcome_data =
wrap_payload_symmetric(&welcome_data, *aead_type, &symmetric_key, &data_nonce).unwrap();
let encrypted_welcome_metadata = wrap_payload_symmetric(
&welcome_metadata_bytes,
*aead_type,
&symmetric_key,
&metadata_nonce,
)
.unwrap();
let encrypted_welcome_data = wrap_payload_symmetric()
.data(&welcome_data)
.aead_type(*aead_type)
.symmetric_key(&symmetric_key)
.nonce(&data_nonce)
.call()
.unwrap();
let encrypted_welcome_metadata = wrap_payload_symmetric()
.data(&welcome_metadata_bytes)
.aead_type(*aead_type)
.symmetric_key(&symmetric_key)
.nonce(&metadata_nonce)
.call()
.unwrap();
// Verify encryption worked (data should be different)
assert_ne!(encrypted_welcome_data, welcome_data);
assert_ne!(encrypted_welcome_metadata, welcome_metadata_bytes);

// Test decryption
let decrypted_welcome_data = unwrap_payload_symmetric(
&encrypted_welcome_data,
*aead_type,
&symmetric_key,
&data_nonce,
)
.unwrap();
let decrypted_welcome_metadata = unwrap_payload_symmetric(
&encrypted_welcome_metadata,
*aead_type,
&symmetric_key,
&metadata_nonce,
)
.unwrap();
let decrypted_welcome_data = unwrap_payload_symmetric()
.data(&encrypted_welcome_data)
.aead_type(*aead_type)
.symmetric_key(&symmetric_key)
.nonce(&data_nonce)
.call()
.unwrap();
let decrypted_welcome_metadata = unwrap_payload_symmetric()
.data(&encrypted_welcome_metadata)
.aead_type(*aead_type)
.symmetric_key(&symmetric_key)
.nonce(&metadata_nonce)
.call()
.unwrap();

// Verify decryption worked (data should match original)
assert_eq!(decrypted_welcome_data, welcome_data);
Expand Down Expand Up @@ -595,22 +600,24 @@ async fn test_welcome_pointer_task_retry_resolution() {
Ok::<_, crate::groups::GroupError>(action)
})
.await?;
let data = wrap_payload_symmetric(
&send_welcome_action.welcome_message,
WelcomePointersExtension::preferred_type(),
&welcome_pointer_v1.encryption_key,
&welcome_pointer_v1.data_nonce,
)
.unwrap();
let welcome_metadata = wrap_payload_symmetric(
WelcomeMetadata { message_cursor: 0 }
.encode_to_vec()
.as_slice(),
WelcomePointersExtension::preferred_type(),
&welcome_pointer_v1.encryption_key,
&welcome_pointer_v1.welcome_metadata_nonce,
)
.unwrap();
let data = wrap_payload_symmetric()
.data(&send_welcome_action.welcome_message)
.aead_type(WelcomePointersExtension::preferred_type())
.symmetric_key(&welcome_pointer_v1.encryption_key)
.nonce(&welcome_pointer_v1.data_nonce)
.call()
.unwrap();
let welcome_metadata = wrap_payload_symmetric()
.data(
WelcomeMetadata { message_cursor: 0 }
.encode_to_vec()
.as_slice(),
)
.aead_type(WelcomePointersExtension::preferred_type())
.symmetric_key(&welcome_pointer_v1.encryption_key)
.nonce(&welcome_pointer_v1.welcome_metadata_nonce)
.call()
.unwrap();

let welcome_data = xmtp_proto::xmtp::mls::api::v1::WelcomeMessageInput {
version: Some(
Expand Down
Loading
Loading