group-call.struct.yml 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. # Meta information
  2. meta:
  3. # Document name and ID
  4. id: group-call
  5. name: Group Call Protocol
  6. # Virtual namespace, just containing the below docstring
  7. index: &index
  8. _doc: |-
  9. # Group Call Protocol (Supplementary)
  10. This is a supplementary section to the corresponding protobuf section with
  11. messages that use structbuf instead of protobuf. All defined messages here
  12. follow the same logic.
  13. # Real-Time media end-to-end encryption
  14. e2e: &e2e
  15. frame:
  16. _doc: |-
  17. And end-to-end encrypted audio/video frame.
  18. Steps to extract the unencrypted header from frame data (encrypted or
  19. unencrypted):
  20. 1. Let `data` be the given encrypted or unencrypted frame data.
  21. 2. Let `offset` be `0`.
  22. 3. If the codec for this frame is Opus, there is no unencrypted header.
  23. Leave `offset` at `0`.
  24. 4. If the codec for this frame is VP8:
  25. 1. If the LSB of the first byte is `1`, set `offset` to `10` and abort
  26. these sub-steps.
  27. 2. Set `offset` to 3.
  28. 5. Return a tuple of:
  29. - unencrypted-header: A view of all bytes until `offset`
  30. (i.e. `data[0..offset]`).
  31. - payload: A view of all bytes from `offset` (i.e. `data[offset..]`).
  32. When creating a media frame:
  33. 1. Let `data` be the given frame data.
  34. 2. If `data` is greater than `65536 - 16 - 6` bytes, log a warning and
  35. abort these steps.
  36. 3. Let `unencrypted-header` and `payload` be the result of the above
  37. described header extraction steps by applying it on `data.
  38. 4. Let `frame-mfsn` be a copy of the current MFSN. Then, immediately
  39. increase MFSN by 1.
  40. IMPORTANT: The MFSN **must** be guarded by a mutex if multithreading
  41. is involved. It is critical to prevent nonce reuse!
  42. 5. Let `nonce` be the byte concatenation of the following items in this
  43. order:
  44. - `u32-le(frame-mfsn)`
  45. - 8 zero bytes
  46. 6. Let `pcmk` be the current PCMK with the associated context.
  47. 7. Let `ad` be the byte concatenation of the following items in this
  48. order:
  49. - `u8(pcmk.epoch)`
  50. - `u8(pcmk.ratchet-counter)`
  51. - `u32-le(frame-mfsn)`
  52. - `unencrypted-header`
  53. 8. Encrypt the media frame and let `encrypted-payload` be the result:
  54. AES-256-GCM(
  55. key=pcmk.pcmfk,
  56. nonce=nonce,
  57. auth-tag-length=16 (bytes),
  58. auth-tag-position=append,
  59. data=payload,
  60. additional-data=ad,
  61. )
  62. 9. Encode the `frame` struct:
  63. - `data`: The byte concatenation of `unencrypted-header`,
  64. `encrypted-payload` (including the AES GCM authentication tag).
  65. - `footer.key-epoch`: `pcmk.epoch`
  66. - `footer.key-ratchet-counter`: `pcmk-ratchet-counter`
  67. - `footer.mfsn`: `frame-mfsn`
  68. 10. Increase MFSN by `1`.
  69. 11. Send the encoded `frame` struct.
  70. When receiving a media frame:
  71. 1. Let `frame` be the received struct.
  72. 2. If `frame.data` is greater than `65536` bytes, log a warning and abort
  73. these steps.
  74. 3. Let `unencrypted-header` and `payload` be the result of the above
  75. described header extraction steps by applying it on `frame.data`.
  76. 4. Let `pcmk` be the current PCMK with the associated context for the
  77. participant that sent this frame.
  78. 5. If `frame.epoch` is greater than `pcmk.epoch` or wrapped back to `0`,
  79. seek through all successors until a media key with the same `epoch`
  80. could be determined.
  81. 1. If no key could be determined, discard the media frame and abort
  82. these steps.
  83. 2. Replace `pcmk` with the succeeding media key that matched `epoch`.
  84. Note: An implementation **must** ensure that only succeeding keys
  85. are being used. Rolling back to a preceeding media key is
  86. forbidden.
  87. 6. If `frame.ratchet-counter` is less than `pcmk.ratchet-counter`, discard
  88. the media frame and abort these steps.
  89. 7. If `frame.ratchet-counter` is greater than `pcmk.ratchet-counter`,
  90. apply the necessary amount of ratchet rounds to `pcmk` so the counters
  91. are equal.
  92. 8. Let `nonce` be the byte concatenation of the following items in this
  93. order:
  94. - `u32-le(frame.footer.mfsn)`
  95. - 8 zero bytes
  96. 9. Let `ad` be the byte concatenation of the following items in this
  97. order:
  98. - `u8(pcmk.epoch)`
  99. - `u8(pcmk.ratchet-counter)`
  100. - `u32-le(frame.footer.mfsn)`
  101. - `unencrypted-header`
  102. 10. Decrypt the media frame and let `decrypted-payload` be the result:
  103. AES-256-GCM(
  104. key=pcmk.pcmfk,
  105. nonce=nonce,
  106. auth-tag-length=16 (bytes),
  107. auth-tag-position=append,
  108. data=payload,
  109. additional-data=ad,
  110. )
  111. 11. If decryption failed, discard the media frame and abort these steps.
  112. 12. Let `data` be the byte concatenation of `unencrypted-header` and
  113. `decrypted-payload`.
  114. 13. Forward `data` to the media pipeline.
  115. Note: There is limited replay mitigation. The SFU is able to replay old
  116. frames that were recorded in this media key epoch and ratchet iteration.
  117. fields:
  118. - _doc: |-
  119. This contains the following data (in this order):
  120. - Unencrypted frame header (if any, 0 to 10 bytes)
  121. - Encrypted audio/video frame
  122. - AES GCM authentication tag (16 bytes)
  123. - The `footer` struct
  124. name: data
  125. type: b*
  126. footer:
  127. _doc: |-
  128. Footer of an end-to-end encrypted audio/video frame.
  129. fields:
  130. - _doc: |-
  131. Media key epoch. This is the same value as in
  132. `group-call.MediaKey.epoch`.
  133. name: key-epoch
  134. type: u8
  135. - _doc: |-
  136. Media key ratchet counter. This is the same value as in
  137. `MediaKey.ratchet_counter`.
  138. name: key-ratchet-counter
  139. type: u8
  140. - _doc: |-
  141. Sequence number of the media frame (MFSN).
  142. Note: Like the epoch and the ratchet counter, the MFSN is shared
  143. across different media types.
  144. name: mfsn
  145. type: u32-le
  146. # Parsed struct namespaces (mapped into separate files)
  147. namespaces:
  148. index: *index
  149. e2e: *e2e