Skip to content

Commit ca6003c

Browse files
committed
feat: add additional information about who had duplicate signatures
1 parent 9a26240 commit ca6003c

File tree

2 files changed

+46
-4
lines changed

2 files changed

+46
-4
lines changed

crypto/src/mls/conversation/conversation_guard/commit.rs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
//! The methods in this module all produce or handle commits.
22
3-
use std::borrow::Borrow;
3+
use std::{borrow::Borrow, collections::HashMap};
44

55
use openmls::prelude::KeyPackageIn;
66
use wire_e2e_identity::NewCrlDistributionPoints;
77

88
use super::history_sharing::HistoryClientUpdateOutcome;
99
use crate::{
10-
ClientIdRef, CredentialRef, LeafError, MlsError, MlsGroupInfoBundle, MlsTransportResponse, RecursiveError,
10+
ClientId, ClientIdRef, CredentialRef, LeafError, MlsError, MlsGroupInfoBundle, MlsTransportResponse,
11+
RecursiveError,
1112
mls::{
1213
conversation::{
1314
Conversation as _, ConversationGuard, ConversationWithMls as _, Error, Result, commit::MlsCommitBundle,
@@ -130,9 +131,16 @@ impl ConversationGuard {
130131

131132
let (commit, welcome, group_info) = conversation
132133
.group
133-
.add_members(&backend, signer, key_packages)
134+
.add_members(&backend, signer, key_packages.clone())
134135
.await
135-
.map_err(MlsError::wrap("group add members"))?;
136+
.map_err(|err| {
137+
if Self::has_duplicate_signature_key(&err) {
138+
let affected_clients = Self::clients_with_duplicate_signature_keys(key_packages);
139+
Error::DuplicateSignature { affected_clients }
140+
} else {
141+
MlsError::wrap("group add members")(err).into()
142+
}
143+
})?;
136144

137145
// commit requires an optional welcome
138146
let welcome = Some(welcome);
@@ -150,6 +158,36 @@ impl ConversationGuard {
150158
Ok((crl_new_distribution_points, commit))
151159
}
152160

161+
fn has_duplicate_signature_key(
162+
err: &openmls::prelude::AddMembersError<core_crypto_keystore::CryptoKeystoreError>,
163+
) -> bool {
164+
matches!(
165+
err,
166+
openmls::prelude::AddMembersError::CreateCommitError(
167+
openmls::prelude::CreateCommitError::ProposalValidationError(
168+
openmls::prelude::ProposalValidationError::DuplicateSignatureKey
169+
)
170+
)
171+
)
172+
}
173+
174+
fn clients_with_duplicate_signature_keys(key_packages: Vec<KeyPackageIn>) -> Vec<(ClientId, ClientId)> {
175+
let mut seen_signature_keys = HashMap::new();
176+
let mut duplicate_pairs = Vec::new();
177+
178+
for key_package in key_packages {
179+
let signature_key = key_package.unverified_credential().signature_key.as_slice().to_vec();
180+
181+
let client_id: ClientId = key_package.credential().identity().to_vec().into();
182+
183+
if let Some(previous_client_id) = seen_signature_keys.insert(signature_key, client_id.clone()) {
184+
duplicate_pairs.push((previous_client_id, client_id));
185+
}
186+
}
187+
188+
duplicate_pairs
189+
}
190+
153191
/// Removes clients from the group/conversation.
154192
///
155193
/// # Arguments

crypto/src/mls/conversation/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ pub enum Error {
8484
"Although this Welcome seems valid, the local KeyPackage it references has already been deleted locally. Join this group with an external commit"
8585
)]
8686
OrphanWelcome,
87+
#[error("Operation couldn't be performed due to duplicate signature for clients: {affected_clients:?}")]
88+
DuplicateSignature {
89+
affected_clients: Vec<(crate::ClientId, crate::ClientId)>,
90+
},
8791
#[error("Serializing {item} for TLS")]
8892
TlsSerialize {
8993
item: &'static str,

0 commit comments

Comments
 (0)