fix(e2ee): fix SET_MEDIA_ENCRYPTION_KEY pipeline and add participantId support#17351
Open
encedo wants to merge 10 commits intojitsi:masterfrom
Open
fix(e2ee): fix SET_MEDIA_ENCRYPTION_KEY pipeline and add participantId support#17351encedo wants to merge 10 commits intojitsi:masterfrom
encedo wants to merge 10 commits intojitsi:masterfrom
Conversation
…d support Two issues in the externally-managed key path: 1. middleware.ts imported the raw key bytes as an AES-GCM CryptoKey before passing them to the conference. The E2EE worker's Context.setKey() expects raw bytes so it can run its own importKey() + deriveKeys() (HKDF-SHA-256 → AES-GCM-128) derivation. Importing as AES-GCM bypassed this step and produced a key the worker could not use. The importKey call is removed; raw Uint8Array bytes are forwarded directly. 2. Neither middleware.ts nor the External API method propagated a participantId field. Without it, ExternallyManagedKeyHandler cannot select the correct per-sender E2EEContext, and the worker receives an undefined participantId which it rejects. participantId is now extracted from action.keyInfo and forwarded to conference.setMediaEncryptionKey(), and the External API setMediaEncryptionKey() method accepts and serialises it alongside the key. External API callers that want per-sender key asymmetry (one unique key per sender, as opposed to a shared group key) should pass participantId in the keyInfo object. The field is optional; omitting it keeps the existing behaviour where the local participant's ID is used by the handler.
|
Hi, thanks for your contribution! |
Author
Done, signed. |
added 8 commits
April 28, 2026 13:37
…nal API event Exposes the OLM custom-message channel (added in lib-jitsi-meet companion commit) through the JitsiMeetExternalAPI so that the host-app can use OLM as a secure E2EE transport for ML-KEM key exchange and HSM attestation. API.js: - 'send-olm-message' command: forwards (participantId, type, JSON payload) to JitsiConference.sendOlmMessage(), which encrypts the message over the established OLM session. Empty participantId broadcasts to all sessions. - notifyOlmMessageReceived(from, type, payload): fires the external event when an OLM custom message is received from a remote participant. external_api.js: - Register 'olm-message-received' → 'olmMessageReceived' in the public event map so that embedding pages can subscribe with addListener(). middleware.ts: - Listen to JitsiConferenceEvents.OLM_MESSAGE_RECEIVED (emitted by ExternallyManagedKeyHandler when OLM decrypts a custom message) and forward it to APP.API.notifyOlmMessageReceived.
…dKey is set When e2ee.externallyManagedKey is true in the Jitsi config, dispatch toggleE2EE(true) immediately on CONFERENCE_JOINED so that media is encrypted from the first frame without requiring a manual UI toggle or an External API command from the host-app.
- app.js: import @matrix-org/olm with window.Olm assignment; load olm-options.js first
- olm-options.js: set OLM_OPTIONS.locateFile so Emscripten finds olm.wasm under libs/
- index.html: add <script src="libs/olm.js"> for production HTML
- external_api.js: add sendOlmMessage to External API commands map
- API.js: fix notifyOlmMessageReceived — spread fields at top level instead of nesting
under data: (external_api.js destructures {name, ...rest}, so nested fields were
invisible to the outer-page listener, causing silent handshake failure)
- webpack.config.js: alias lib-jitsi-meet to ../lib-jitsi-meet; ignore node_modules
in webpack-dev-server watch to prevent reload storms
- Makefile: point LIBJITSIMEET_DIR at ../lib-jitsi-meet
Show a visible warning banner at the top of the chat panel when E2EE is active, so users are not misled into thinking chat messages are protected by the same end-to-end encryption as media.
…ly in Jitsi UI When E2EE is enabled, SEND_MESSAGE dispatches via conference.sendOlmMessage instead of sendTextMessage, and own message is added to Redux store directly (OLM messages don't echo back). Incoming encedo:chat OLM messages are injected into the native chat UI via _handleReceivedMessage. Falls back to plain XMPP when E2EE is off — fully backwards-compatible.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Companion to jitsi/lib-jitsi-meet#3028.
Issue 1 — incorrect key type in middleware
middleware.tsimported raw key bytes as anAES-GCMCryptoKey beforeforwarding them to
conference.setMediaEncryptionKey(). However,ExternallyManagedKeyHandlerultimately passes the value to the E2EE worker'sContext.setKey(key: Uint8Array | ArrayBuffer), which calls:An already-derived AES-GCM key cannot serve as HKDF input. The fix removes
the intermediate
importKeycall; rawUint8Arraybytes are passed directlyso the worker can perform the derivation itself.
Issue 2 — participantId not propagated
The
SET_MEDIA_ENCRYPTION_KEYRedux action and the External APIsetMediaEncryptionKey()method did not read or serialise aparticipantIdfield. This made per-sender key selection (enabled by
e2ee.externallyManagedSharedKey: falsein lib-jitsi-meet) unreachable throughthe public API.
participantIdis now an optional field throughout the chain;omitting it preserves the existing behaviour.
Testing
Unit tests are in the companion lib-jitsi-meet PR. Manual verification:
e2ee: { externallyManagedKey: true, externallyManagedSharedKey: false }api.setMediaEncryptionKey({ key, index, participantId })setKeyis called with the correctparticipantIdand non-empty key bytes.