Skip to content

Commit

Permalink
feat!: 'decrypt_message' returns the sender client id
Browse files Browse the repository at this point in the history
  • Loading branch information
beltram committed Aug 30, 2022
1 parent 4a1f3d5 commit 7665f9d
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 13 deletions.
18 changes: 14 additions & 4 deletions crypto-ffi/bindings/js/CoreCrypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,17 @@ export interface ConversationConfiguration {
}

/**
* Alias for convesation IDs.
* Alias for conversation IDs.
* This is a freeform, uninspected buffer.
*/
export type ConversationId = Uint8Array;

/**
* Alias for client identifier.
* This is a freeform, uninspected buffer.
*/
export type ClientId = Uint8Array;

/**
* Alias for proposal reference. It is a byte array of size 16.
*/
Expand Down Expand Up @@ -95,7 +101,7 @@ export interface Invitee {
/**
* Client ID as a byte array
*/
id: Uint8Array;
id: ClientId;
/**
* MLS KeyPackage belonging to the aforementioned client
*/
Expand Down Expand Up @@ -185,6 +191,10 @@ export interface DecryptedMessage {
* Commit delay hint (in milliseconds) to prevent clients from hammering the server with epoch changes
*/
commitDelay?: number;
/**
* Client identifier of the sender of the message being decrypted. Only present for application messages.
*/
senderClientId?: ClientId;
}

/**
Expand Down Expand Up @@ -250,7 +260,7 @@ export interface RemoveProposalArgs extends ProposalArgs {
/**
* Client ID to be removed from the conversation
*/
clientId: Uint8Array;
clientId: ClientId;
}

/**
Expand Down Expand Up @@ -571,7 +581,7 @@ export class CoreCrypto {
*/
async removeClientsFromConversation(
conversationId: ConversationId,
clientIds: Uint8Array[]
clientIds: ClientId[]
): Promise<CommitBundle> {
const ffiRet: CoreCryptoFfiTypes.CommitBundle = await this.#cc.remove_clients_from_conversation(
conversationId,
Expand Down
21 changes: 13 additions & 8 deletions crypto-ffi/bindings/swift/Sources/CoreCrypto/CoreCrypto.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,17 @@ extension CoreCryptoSwift.ProposalBundle {
}
}

/// Alias for convesation IDs.
/// Alias for conversation IDs.
/// This is a freeform, uninspected buffer.
public typealias ConversationId = [UInt8]

/// Alias for ClientId within a conversation.
public typealias MemberId = [UInt8]

/// Conversation ciphersuite variants
public enum CiphersuiteName: ConvertToInner {
typealias Inner = CoreCryptoSwift.CiphersuiteName

case mls128Dhkemx25519Aes128gcmSha256Ed25519
case mls128Dhkemp256Aes128gcmSha256P256
case mls128Dhkemx25519Chacha20poly1305Sha256Ed25519
Expand Down Expand Up @@ -100,7 +102,7 @@ public struct ConversationConfiguration: ConvertToInner {
func convert() -> Inner {
return CoreCryptoSwift.ConversationConfiguration(admins: self.admins, ciphersuite: self.ciphersuite?.convert(), keyRotationSpan: self.keyRotationSpan, externalSenders: self.externalSenders)
}

/// List of client IDs with administrative permissions
public var admins: [MemberId]
/// Conversation ciphersuite
Expand Down Expand Up @@ -131,7 +133,7 @@ public struct Invitee: ConvertToInner {
self.id = id
self.kp = kp
}

func convert() -> Inner {
return CoreCryptoSwift.Invitee(id: self.id, kp: self.kp)
}
Expand All @@ -152,7 +154,7 @@ public struct MemberAddedMessages: ConvertToInner {
self.welcome = welcome
self.publicGroupState = publicGroupState
}

func convert() -> Inner {
return CoreCryptoSwift.MemberAddedMessages(commit: self.commit, welcome: self.welcome, publicGroupState: self.publicGroupState)
}
Expand All @@ -173,18 +175,21 @@ public struct DecryptedMessage: ConvertToInner {
public var isActive: Bool
/// delay time in seconds to feed caller timer for committing
public var commitDelay: UInt64?
/// Client identifier of the sender of the message being decrypted. Only present for application messages.
public var senderClientId: ClientId?

public init(message: [UInt8]?, proposals: [ProposalBundle], isActive: Bool, commitDelay: UInt64?) {
public init(message: [UInt8]?, proposals: [ProposalBundle], isActive: Bool, commitDelay: UInt64?, senderClientId: ClientId?) {
self.message = message
self.proposals = proposals
self.isActive = isActive
self.commitDelay = commitDelay
self.senderClientId = senderClientId
}

func convert() -> Inner {
return CoreCryptoSwift.DecryptedMessage(message: self.message, proposals: self.proposals.map({ (bundle) -> CoreCryptoSwift.ProposalBundle in
bundle.convert()
}), isActive: self.isActive, commitDelay: self.commitDelay)
}), isActive: self.isActive, commitDelay: self.commitDelay, senderClientId: self.senderClientId)
}
}

Expand All @@ -200,7 +205,7 @@ public struct ProposalBundle: ConvertToInner {
self.proposal = proposal
self.proposalRef = proposalRef
}

func convert() -> Inner {
return CoreCryptoSwift.ProposalBundle(proposal: self.proposal, proposalRef: self.proposalRef)
}
Expand Down
1 change: 1 addition & 0 deletions crypto-ffi/src/CoreCrypto.udl
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ dictionary DecryptedMessage {
sequence<ProposalBundle> proposals;
boolean is_active;
u64? commit_delay;
ClientId? sender_client_id;
};

dictionary MemberAddedMessages {
Expand Down
2 changes: 2 additions & 0 deletions crypto-ffi/src/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ pub struct DecryptedMessage {
pub proposals: Vec<ProposalBundle>,
pub is_active: bool,
pub commit_delay: Option<u64>,
pub sender_client_id: Option<ClientId>,
}

impl TryFrom<MlsConversationDecryptMessage> for DecryptedMessage {
Expand All @@ -130,6 +131,7 @@ impl TryFrom<MlsConversationDecryptMessage> for DecryptedMessage {
proposals,
is_active: from.is_active,
commit_delay: from.delay,
sender_client_id: from.sender_client_id,
})
}
}
Expand Down
2 changes: 2 additions & 0 deletions crypto-ffi/src/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ pub struct DecryptedMessage {
proposals: Vec<ProposalBundle>,
is_active: bool,
commit_delay: Option<u32>,
sender_client_id: Option<FfiClientId>,
}

impl TryFrom<MlsConversationDecryptMessage> for DecryptedMessage {
Expand All @@ -267,6 +268,7 @@ impl TryFrom<MlsConversationDecryptMessage> for DecryptedMessage {
proposals,
is_active: from.is_active,
commit_delay,
sender_client_id: from.sender_client_id.map(ClientId::into),
})
}
}
Expand Down
6 changes: 6 additions & 0 deletions crypto/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ impl From<Box<[u8]>> for ClientId {
}
}

impl From<ClientId> for Box<[u8]> {
fn from(value: ClientId) -> Self {
value.0.into_boxed_slice()
}
}

#[cfg(test)]
impl From<&str> for ClientId {
fn from(value: &str) -> Self {
Expand Down
102 changes: 101 additions & 1 deletion crypto/src/conversation/decrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use openmls_traits::OpenMlsCryptoProvider;
use mls_crypto_provider::MlsCryptoProvider;

use crate::{
conversation::renew::Renew, prelude::MlsProposalBundle, ConversationId, CoreCryptoCallbacks, CryptoError,
conversation::renew::Renew, prelude::MlsProposalBundle, ClientId, ConversationId, CoreCryptoCallbacks, CryptoError,
CryptoResult, MlsCentral, MlsConversation, MlsError,
};

Expand All @@ -35,6 +35,8 @@ pub struct MlsConversationDecryptMessage {
pub is_active: bool,
/// delay time in seconds to feed caller timer for committing
pub delay: Option<u64>,
/// [ClientId] of the sender of the message being decrypted. Only present for application messages.
pub sender_client_id: Option<ClientId>,
}

/// Abstraction over a MLS group capable of decrypting a MLS message
Expand All @@ -51,6 +53,8 @@ impl MlsConversation {

let parsed_message = self.parse_message(backend, msg_in)?;

let sender_client_id = parsed_message.credential().map(|c| c.identity().into());

let message = self
.group
.process_unverified_message(parsed_message, None, backend)
Expand All @@ -63,6 +67,7 @@ impl MlsConversation {
proposals: vec![],
is_active: true,
delay: None,
sender_client_id,
},
ProcessedMessage::ProposalMessage(proposal) => {
self.validate_external_proposal(&proposal, callbacks, backend.crypto())?;
Expand All @@ -73,6 +78,7 @@ impl MlsConversation {
proposals: vec![],
is_active: true,
delay: self.compute_next_commit_delay(),
sender_client_id: None,
}
}
ProcessedMessage::StagedCommitMessage(staged_commit) => {
Expand All @@ -99,6 +105,7 @@ impl MlsConversation {
proposals,
is_active: self.group.is_active(),
delay: self.compute_next_commit_delay(),
sender_client_id: None,
}
}
};
Expand Down Expand Up @@ -520,6 +527,35 @@ pub mod tests {
)
.await
}

#[apply(all_credential_types)]
#[wasm_bindgen_test]
pub async fn should_not_return_sender_client_id(credential: CredentialSupplier) {
run_test_with_client_ids(
credential,
["alice", "bob"],
move |[mut alice_central, mut bob_central]| {
Box::pin(async move {
let id = conversation_id();
alice_central
.new_conversation(id.clone(), MlsConversationConfiguration::default())
.await
.unwrap();
alice_central.invite(&id, &mut bob_central).await.unwrap();

let commit = alice_central.update_keying_material(&id).await.unwrap().commit;

let sender_client_id = bob_central
.decrypt_message(&id, commit.to_bytes().unwrap())
.await
.unwrap()
.sender_client_id;
assert!(sender_client_id.is_none());
})
},
)
.await
}
}

pub mod decrypt_callback {
Expand Down Expand Up @@ -695,6 +731,39 @@ pub mod tests {
)
.await
}

#[apply(all_credential_types)]
#[wasm_bindgen_test]
pub async fn should_not_return_sender_client_id(credential: CredentialSupplier) {
run_test_with_client_ids(
credential,
["alice", "bob"],
move |[mut alice_central, mut bob_central]| {
Box::pin(async move {
let id = conversation_id();
alice_central
.new_conversation(id.clone(), MlsConversationConfiguration::default())
.await
.unwrap();
alice_central.invite(&id, &mut bob_central).await.unwrap();

let proposal = alice_central
.new_proposal(&id, MlsProposal::Update)
.await
.unwrap()
.proposal;

let sender_client_id = bob_central
.decrypt_message(&id, proposal.to_bytes().unwrap())
.await
.unwrap()
.sender_client_id;
assert!(sender_client_id.is_none());
})
},
)
.await
}
}

pub mod app_message {
Expand Down Expand Up @@ -799,5 +868,36 @@ pub mod tests {
)
.await
}

#[apply(all_credential_types)]
#[wasm_bindgen_test]
pub async fn returns_sender_client_id(credential: CredentialSupplier) {
run_test_with_client_ids(
credential,
["alice", "bob"],
move |[mut alice_central, mut bob_central]| {
Box::pin(async move {
let id = conversation_id();
alice_central
.new_conversation(id.clone(), MlsConversationConfiguration::default())
.await
.unwrap();
alice_central.invite(&id, &mut bob_central).await.unwrap();

let msg = b"Hello bob";
let encrypted = alice_central.encrypt_message(&id, msg).await.unwrap();
assert_ne!(&msg[..], &encrypted[..]);
let sender_client_id = bob_central
.decrypt_message(&id, encrypted)
.await
.unwrap()
.sender_client_id
.unwrap();
assert_eq!(sender_client_id, b"alice"[..].into());
})
},
)
.await
}
}
}

0 comments on commit 7665f9d

Please sign in to comment.