-
-
Notifications
You must be signed in to change notification settings - Fork 624
RTCEncryptionManager: Joiner key rotation grace period #4911
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
RTCEncryptionManager: Joiner key rotation grace period #4911
Conversation
cd3bde8
to
1e5efc3
Compare
1e5efc3
to
1d798cb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation looks very simple (In terms of: done in a way that is easy to follow along) and sane. I do have questions on the tests. So I need a bit of help (with comments) to understand what is supposed to happen.
const gracePeriod = 15_000; // 15 seconds | ||
// initial rollout | ||
encryptionManager.join(undefined); | ||
encryptionManager.join({ keyRotationGracePeriodMs: gracePeriod }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this we can just move into the join() method?
Since we use the object config the key is written out and the reason for the value is explained
const gracePeriod = 15_000; // 15 seconds | ||
// initial rollout | ||
encryptionManager.join(undefined); | ||
encryptionManager.join({ keyRotationGracePeriodMs: gracePeriod }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const gracePeriod = 15_000; // 15 seconds | |
// initial rollout | |
encryptionManager.join(undefined); | |
encryptionManager.join({ keyRotationGracePeriodMs: gracePeriod }); | |
encryptionManager.join({ keyRotationGracePeriodMs: 15_000 }); |
const gracePeriod = 3_000; // 15 seconds | ||
const useKeyDelay = 5_000; // 5 seconds | ||
// initial rollout | ||
encryptionManager.join({ | ||
useKeyDelay, | ||
keyRotationGracePeriodMs: gracePeriod, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const gracePeriod = 3_000; // 15 seconds | |
const useKeyDelay = 5_000; // 5 seconds | |
// initial rollout | |
encryptionManager.join({ | |
useKeyDelay, | |
keyRotationGracePeriodMs: gracePeriod, | |
}); | |
// initial rollout | |
encryptionManager.join({ | |
useKeyDelay: 3_000, // 3 seconds | |
keyRotationGracePeriodMs: 5_000, // 5 seconds | |
}); |
The comment seemed wrong (3 vs 15 s)
|
||
// A new member joins, that should trigger a key rotation. | ||
members.push(aCallMembership("@carl:example.org", "CARLDEVICE")); | ||
encryptionManager.onMembershipsUpdate([]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can we just pass []
as the old memberships here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am thinking of sth like:
const oldMembers = [...members];
members.push(aCallMembership("@carl:example.org", "CARLDEVICE"));
encryptionManager.onMembershipsUpdate(oldMembers);
Just to make sure the test env is more correct to the real world. Even if the curren impl also works with []
(also makes the test easier to read if we dont know exactly what the onMembershipsUpdate
param means)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might as well deprecate it? as it is not used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah in that case yes!
// A new member joins, within the grace period, but under the delay period | ||
members.push(aCallMembership("@david:example.org", "DAVDEVICE")); | ||
await jest.advanceTimersByTimeAsync(3_000); | ||
encryptionManager.onMembershipsUpdate([]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above.
Shouldn't the old memberships be the correct prev memberships, so the test more properly represents a real world scenario?
* Sometimes it is necessary to rotate the encryption key after a membership update. | ||
* For performance reasons we might not want to rotate the key immediately but allow future memberships to use the same key. | ||
* If 5 people join in a row in less than 5 seconds, we don't want to rotate the key for each of them. | ||
* If 5 people leave in a row in less than 5 seconds, we don't want to rotate the key for each of them. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* If 5 people leave in a row in less than 5 seconds, we don't want to rotate the key for each of them. | |
* If 5 people leave in a row in less than 5 seconds, we don't want to rotate the key for each of them. | |
* So we do share the key which was already used live for <5s to new joiners. This does result in a potential leak up to the configured time of call media. | |
* This has to be considered when choosing a value for this property. |
* | ||
* The higher this value is, the better it is for existing members as they will have a smoother experience. | ||
* But it impacts new joiners: They will always have to wait `useKeyDelay` before being able to decrypt the media | ||
* (as it will be encrypted with the new key after the delay only), even if the key is already arrived before the delay. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* (as it will be encrypted with the new key after the delay only), even if the key is already arrived before the delay. | |
* (as it will be encrypted with the new key after the delay only), even if the key has already arrived before the delay. |
/** | ||
* The time to wait before using the outbound session after it has been distributed. | ||
* This is to ensure that the key is delivered to all participants before it is used. | ||
* When creating the first key, this is set to 0, so that the key can be used immediately. | ||
*/ | ||
private delayRolloutTimeMillis = 1000; | ||
private delayRolloutTimeMillis = 5000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this the same as useKeyDelay
. If so we should rename one of them.
* If it is lower, the current key will always be older than the grace period. | ||
* @private | ||
*/ | ||
private skipRotationGracePeriod = 10_000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here keyRotationGracePeriodMs
this.delayRolloutTimeMillis = joinConfig?.useKeyDelay ?? 1000; | ||
this.skipRotationGracePeriod = joinConfig?.keyRotationGracePeriodMs ?? 10_000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should totally be:
this.delayRolloutTimeMillis = joinConfig?.useKeyDelay ?? 1000; | |
this.skipRotationGracePeriod = joinConfig?.keyRotationGracePeriodMs ?? 10_000; | |
this.useKeyDelay = joinConfig?.useKeyDelay ?? 1000; | |
this.keyRotationGracePeriodMs = joinConfig?.keyRotationGracePeriodMs ?? 10_000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or the other names from this class
Fixes https://github.com/element-hq/voip-internal/issues/371
Checklist
public
/exported
symbols have accurate TSDoc documentation.