Draft: draft-omara-sframe

Commentary: This PR attempts to capture the spirit of the original key management provisions with a little more clarity about assumptions . It also adds a more more explicit construction for connecting SFrame to MLS .
Each SFrame KID value identifies a "base\_key", and thus both the
"sframe\_secret" and "sframe\_salt" values to be used for encryption
and decryption.
Each SFrame encryption or decryption operation is premised on a
single secret "base\_key", which is labeled with an integer KID value
signaled in the SFrame header.
The sender and receivers need to agree on which key should be used
for a given KID.  The process for provisioning keys and their KID
values is beyond the scope of this specification, but its security
properties will bound the assurances that SFrame provides.  For
example, if SFrame is used to provide E2E security against
intermediary media nodes, then SFrame keys MUST be negotiated in a
way that does not make them accessible to these intermediaries.
For each known KID value, the client stores the corresponding
symmetric key "base\_key".  For keys that can be used for encryption,
the client also stores the next counter value CTR to be used when
encrypting (initially 0).
When encrypting a frame, the application specifies which KID is to be
used, and the counter is incremented after successful encryption.
When decrypting, the "base\_key" for decryption is selected from the
available keys using the KID value in the SFrame Header.
A given key MUST NOT be used for encryption by multiple senders.
Such reuse would result in multiple encrypted frames being generated
with the same (key, nonce) pair, which harms the protections provided
by many AEAD algorithms.  Implementations SHOULD mark each key as
usable for encryption or decryption, never both.
Note that the set of available keys might change over the lifetime of
a real-time session.  In such cases, the client will need to manage
key usage to avoid media loss due to a key being used to encrypt
before all receivers are able to use it to decrypt.  For example, an
application may make decryption-only keys available immediately, but
delay the use of encryption-only keys until (a) all receivers have
acknowledged receipt of the new key or (b) a timeout expires.
The hash function used for HKDF is determined by the ciphersuite in
use.
The receiving clients buffer all packets that belongs to the same
frame using the frame beginning and ending marks in the generic RTP
frame header extension, and once all packets are available, it passes
it to SFrame for decryption.  SFrame maintains multiple decryptor
objects, one for each client in the call.  Initially the client might
not have the mapping between the incoming streams the user's keys, in
this case SFrame tries all unmapped keys until it finds one that
passes the authentication verification and use it to decrypt the
frame.  If the client has the mapping ready, it can push it down to
SFrame later.
The KeyId field in the SFrame header is used to find the right key
for that user, which is incremented by the sender when they switch to
a new key.
For frames that are failed to decrypt because there is not key
available yet, SFrame will buffer them and retries to decrypt them
once a key is received.
The receiving clients buffer all packets that belongs to the same
frame using the frame beginning and ending marks in the generic RTP
frame header extension, and once all packets are available, it passes
it to SFrame for decryption.  The KID field in the SFrame header is
used to find the right key for the encrypted frame.
For frames that are failed to decrypt because there is key available
for the KID in the SFrame header, the client MAY buffer the frame and
retry decryption once a key with that KID is received.
When SFrame decryptor fails to decrypt one of the frames, it
automatically ratchets the key forward and retries again until one
ratchet succeed or it reaches the maximum allowed ratcheting window.
If a new ratchet passed the decryption, all previous ratchets are
deleted.
SFrame will set the key immediately on the decrypts when it is
received and destroys the old key material, so if the key manager
sends a new key during the call, it is recommended not to start using
it immediately and wait for a short time to make sure it is delivered
to all other clients before using it to decrease the number of
decryption failure.  It is up to the application and the key manager
to define how long this period is.
SFrame must be integrated with an E2EE key management framework to
exchange and rotate the encryption keys.  This framework will
maintain a group of participant endpoints who are in the call.  At
call setup time, each endpoint will create a fresh key material and
optionally signing key pair for that call and encrypt the key
material and the public signing key to every other endpoints.  They
encrypted keys are delivered by the messaging delivery server using a
reliable channel.
The KMS will monitor the group changes, and exchange new keys when
necessary.  It is up to the application to define this group, for
example one application could have ephemeral group for every call and
keep rotating key when end points joins or leave the call, while
another application could have a persisted group that can be used for
multiple calls and exchange keys with all group endpoints for every
call.
When a new key material is created during the call, we recommend not
to start using it immediately in SFrame to give time for the new keys
to be delivered.  If the application supports delivery receipts, it
can be used to track if the key is delivered to all other endpoints
on the call before using it.
Keys must have a sequential id starting from 0 and incremented eery
time a new key is generated for this endpoint.  The key id will be
added in the SFrame header during encryption, so the recipient know
which key to use for the decryption.
While any other E2EE KMS can be used with SFrame, there is a big
advantage if it is used with I-D.ietf-mls-architecture which natively
supports very large groups efficiently.  When I-D.ietf-mls-protocol
is used, the endpoints keys (AKA Application secret) can be used
directly for SFrame without the need to exchange separate key
material.  The application secret is rotated automatically by I-
D.ietf-mls-protocol when group membership changes.
It is up to the application to define a rotation schedule for keys.
For example, one application might have an ephemeral group for every
call and keep rotating key when end points joins or leave the call,
while another application could have a persistent group that can be
used for multiple calls and simply derives ephemeral symmetric keys
for a specific call.
If the participants in a call have a pre-existing E2E-secure channel,
they can use it to distribute SFrame keys.  Each client participating
in a call generates a fresh encryption key and optionally a signing
key pair.  The client then uses the E2E-secure channel to send their
encryption key and signing public key to the other participants.
The sender signals such an update by incrementing their KID value.  A
receiver who receives from a sender with a new KID computes the new
key as above.  The old key may be kept for some time to allow for
out-of-order delivery, but should be deleted promptly.
If a new participant joins mid-call, they will need to receive from
each sender (a) the current sender key for that sender, (b) the
signing key for the sender, if used, and (c) the current KID value
for the sender.  Evicting a participant requires each sender to send
a fresh sender key to all receivers.
The Messaging Layer Security (MLS) protocol provides group
authenticated key exchange I-D.ietf-mls-architecture I-D.ietf-mls-
protocol.  In principle, it could be used to instantiate the sender
key scheme above, but it can also be used more efficiently directly.
MLS creates a linear sequence of keys, each of which is shared among
the members of a group at a given point in time.  When a member joins
or leaves the group, a new key is produced that is known only to the
augmented or reduced group.  Each step in the lifetime of the group
is know as an "epoch", and each member of the group is assigned an
"index" that is constant for the time they are in the group.
In SFrame, we derive per-sender "base\_key" values from the group
secret for an epoch, and use the KID field to signal the epoch and
sender index.  First, we use the MLS exporter to compute a shared
SFrame secret for the epoch.
Once an SFrame stack has been provisioned with the
"sframe_epoch_secret" for an epoch, it can compute the required KIDs
and "sender_base_key" values on demand, as it needs to encrypt/
decrypt for a given member.
MLS also provides an authenticated signing key pair for each
participant.  When SFrame uses signatures, these are the keys used to
generate SFrame signatures.