<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.6.39 (Ruby 3.2.2) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-robert-mimi-delivery-service-04" category="info" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.18.0 -->
  <front>
    <title abbrev="MIMI">MIMI Delivery Service</title>
    <seriesInfo name="Internet-Draft" value="draft-robert-mimi-delivery-service-04"/>
    <author initials="R." surname="Robert" fullname="Raphael Robert">
      <organization>Phoenix R&amp;D</organization>
      <address>
        <email>ietf@raphaelrobert.com</email>
      </address>
    </author>
    <author initials="K." surname="Kohbrok" fullname="Konrad Kohbrok">
      <organization>Phoenix R&amp;D</organization>
      <address>
        <email>konrad.kohbrok@datashrine.de</email>
      </address>
    </author>
    <date year="2023" month="September" day="21"/>
    <area>Security</area>
    <keyword>Internet-Draft</keyword>
    <abstract>
      <?line 24?>

<t>This document describes the MIMI Delivery Service.</t>
    </abstract>
  </front>
  <middle>
    <?line 28?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>The MLS protocol document specifies a protocol between two or more clients. The
MLS architecture document introduces an abstract concept of a "Delivery Service"
(DS) that is specifically responsible for ordering handshake messages and more
generally for delivering messages to the intended recipients.</t>
      <t>This document describes a Delivery Service that performs the mandated ordering
of handshake messages and uses MLS to implement a variety of other features:</t>
      <ul spacing="normal">
        <li>A protocol between clients and the Delivery Service that allows clients to
interact with the Delivery Service, including the specific wire format of the
messages. The protocol is specifically designed to be operated in a
decentralized, federated architecture but can be used in single instances as
well.</li>
        <li>Assistance for new joiners of a group: The Delivery Service can keep and
update state such as the public ratchet tree, group extensions, etc.</li>
        <li>Message validation: The Delivery Service can inspect and validate handshake
messages and reject malformed, invalid or malicious messages.</li>
        <li>Built-in authentication of group members and policy enforcement: The Delivery
Service can authenticate group members, reject messages from non-members and
enforce group administration policies. Additionally, the Delivery Service can
be linked to the Authentication Service to enforce more policies and
validation rules.</li>
        <li>Scalability: The protocol makes no assumption about whether the Delivery Service
runs as a single instance or as a cluster of instances.</li>
        <li>Network fluid: While the Delivery Service would typically run as a
server-side component, the only requirement is that it is accessible by all
clients.</li>
        <li>Transport agnostic: Messages between clients and the Delivery Service can be
sent via an arbitrary transport protocol. Additionally, in the federated
case, client messages to a guest Delivery Service can be forwarded by a
client's local instance of this service.</li>
        <li>Multi-device capable: The Delivery Service can be used by multiple devices
of the same users and supports adding and removing devices of a user.</li>
        <li>A Queueing Service subcomponent that can be used to implement a queueing
service for messages that are delivered asynchronously, particularly in
federated environments, as well as the protocol between the Delivery Service
and the Queueing Service.</li>
      </ul>
      <t>TODO: Make use of MUST/SHOULD, etc. throughout.</t>
    </section>
    <section anchor="terminology">
      <name>Terminology</name>
      <t>This document uses the terminology defined in <xref target="I-D.ietf-mls-protocol"/> with
the following additions:</t>
      <ul spacing="normal">
        <li>DS Domain: Fully qualified domain name as defined in RFC 2181 that represents
the DS. This does not necessarily have to be the domain under which the DS is
reachable on the network. Discovering that domain is the responsibility of the
MIMI transport protocol over which the MIMI DS protocol runs.
TODO: User/client/identifiers definitions are preliminary.</li>
        <li>User: An entity that operates zero or more clients.</li>
        <li>User identifier: An identifier that is unique in the scope of its DS and that
allows resolution to the providers DS domain.</li>
        <li>Participant: A user that is participating in a group. If the participant has a
client in the group, it is called an active participant.</li>
        <li>Client: An MLS client with a unique client identifier.</li>
        <li>Client identifier: An octet string that uniquely identifies the client. A
client identifier includes the identifier of its user or otherwise allows the
association between the client and its user.</li>
        <li>Connection: An agreement between two users, where each user authorizes the
other to send them messages and to add them to groups.</li>
        <li>Connection establishment: The process by which a connection between two users
is established. The process is manually initiated by one user and fetching the
key material of the other user. The other user must be able to authenticate
the initiator and manually authorize the response.</li>
        <li>Connection group: An MLS group consisting of the clients of two users. For
each pair of users, there can only be one connection group between them. A
connection group is created when one user requests a connection with another
user, followed by that user's consent.</li>
      </ul>
    </section>
    <section anchor="architecture-and-protocol-overview">
      <name>Architecture and protocol overview</name>
      <t>The MIMI DS protocol allows interoperability between a hub which hosts a
group conversation and one or more guest DSs which are home to one or more of
the conversation's group members. Underlying each group conversation is an MLS
group that facilitates end-to-end encryption and authentication between group
members.</t>
      <t>The main purpose of the MIMI DS protocol thus is to ensure that guest clients
can participate in the group. With MLS as the underlying protocol, this means
that the MIMI DS protocol is primarily concerned with the fan-out of MLS
messages (both from and to guest clients), as well the assistance of guest
clients in joining MLS groups.</t>
      <t>The MIMI DS protocol requires clients to send MLS messages as PublicMessages
(with the exception of messages with content type <tt>application</tt>). This allows
the hub to track the MLS group state in the same way as a client would,
enabling it to keep an up-to-date and fully authenticated list of members, as
well as provide the full MLS group state to joining group members, even for
those joining via external commit. In addition, the DS can verify messages and
enforce access control policies on group operations.</t>
      <section anchor="c2s">
        <name>Client to server and server to server protocol</name>
        <t>MLS being a protocol for end-to-end encryption, a subset of MIMI DS protocol
messages have to originate from the clients rather than the interoperating
delivery services.</t>
        <t>The MIMI DS protocol consists of two parts: A client-to-server part that allows
guest clients to interact with the hub of one of their groups and a
server-to-server protocol that allows a hub to fan out messages to guest
DSs, which can subsequently store and forward messages to their respective
clients.</t>
        <t>Note that the client-to-server part of the protocol can optionally be proxied
via the guest DS of the sending client.</t>
      </section>
      <section anchor="transport-for-the-mimi-ds-protocol">
        <name>Transport for the MIMI DS protocol</name>
        <t>The MIMI DS protocol requires a transport protocol that provides confidentiality
of messages and that allows the discovery of a DS based on the DS domain in a
user identifier.</t>
        <t>The client-to-server part of the MIMI DS protocol provide sender authentication.
Recipient authentication, as well as mutual server-to-server authentication is
left to the MIMI transport protocol.</t>
      </section>
      <section anchor="flow">
        <name>Flow</name>
        <figure anchor="full-sending-flow">
          <name>Architecture overview</name>
          <artset>
            <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="416" width="480" viewBox="0 0 480 416" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round">
                <path d="M 8,32 L 8,112" fill="none" stroke="black"/>
                <path d="M 120,32 L 120,112" fill="none" stroke="black"/>
                <path d="M 240,32 L 240,112" fill="none" stroke="black"/>
                <path d="M 240,176 L 240,256" fill="none" stroke="black"/>
                <path d="M 240,320 L 240,400" fill="none" stroke="black"/>
                <path d="M 264,112 L 264,168" fill="none" stroke="black"/>
                <path d="M 264,256 L 264,312" fill="none" stroke="black"/>
                <path d="M 336,120 L 336,176" fill="none" stroke="black"/>
                <path d="M 336,264 L 336,320" fill="none" stroke="black"/>
                <path d="M 360,32 L 360,112" fill="none" stroke="black"/>
                <path d="M 360,176 L 360,256" fill="none" stroke="black"/>
                <path d="M 360,320 L 360,400" fill="none" stroke="black"/>
                <path d="M 8,32 L 120,32" fill="none" stroke="black"/>
                <path d="M 240,32 L 360,32" fill="none" stroke="black"/>
                <path d="M 120,48 L 232,48" fill="none" stroke="black"/>
                <path d="M 128,96 L 240,96" fill="none" stroke="black"/>
                <path d="M 8,112 L 120,112" fill="none" stroke="black"/>
                <path d="M 240,112 L 360,112" fill="none" stroke="black"/>
                <path d="M 240,176 L 360,176" fill="none" stroke="black"/>
                <path d="M 240,256 L 360,256" fill="none" stroke="black"/>
                <path d="M 240,320 L 360,320" fill="none" stroke="black"/>
                <path d="M 240,400 L 360,400" fill="none" stroke="black"/>
                <polygon class="arrowhead" points="344,264 332,258.4 332,269.6" fill="black" transform="rotate(270,336,264)"/>
                <polygon class="arrowhead" points="344,120 332,114.4 332,125.6" fill="black" transform="rotate(270,336,120)"/>
                <polygon class="arrowhead" points="272,312 260,306.4 260,317.6" fill="black" transform="rotate(90,264,312)"/>
                <polygon class="arrowhead" points="272,168 260,162.4 260,173.6" fill="black" transform="rotate(90,264,168)"/>
                <polygon class="arrowhead" points="240,48 228,42.4 228,53.6" fill="black" transform="rotate(0,232,48)"/>
                <polygon class="arrowhead" points="136,96 124,90.4 124,101.6" fill="black" transform="rotate(180,128,96)"/>
                <g class="text">
                  <text x="48" y="68">Sending</text>
                  <text x="180" y="68">(proprietary</text>
                  <text x="272" y="68">Guest</text>
                  <text x="308" y="68">DS</text>
                  <text x="44" y="84">Client</text>
                  <text x="184" y="84">protocol)</text>
                  <text x="216" y="148">DSRequest</text>
                  <text x="388" y="148">DSResponse</text>
                  <text x="264" y="212">Hub</text>
                  <text x="192" y="292">DSFanoutRequest</text>
                  <text x="412" y="292">DSFanoutResponse</text>
                  <text x="272" y="356">Guest</text>
                  <text x="308" y="356">DS</text>
                </g>
              </svg>
            </artwork>
            <artwork type="ascii-art"><![CDATA[
+-------------+              +--------------+
|             +------------->+              |
| Sending     | (proprietary | Guest DS     |
| Client      |   protocol)  |              |
|             +<-------------+              |
+-------------+              +--+--------+--+
                                |        ^
                      DSRequest |        | DSResponse
                                v        |
                             +--+--------+--+
                             |              |
                             | Hub          |
                             |              |
                             |              |
                             +--+--------+--+
                                |        ^
                DSFanoutRequest |        | DSFanoutResponse
                                v        |
                             +--+--------+--+
                             |              |
                             | Guest DS     |
                             |              |
                             |              |
                             +--------------+
]]></artwork>
          </artset>
        </figure>
        <t><xref target="full-sending-flow"/> shows an example protocol flow, where a client sends a
request to its own guest DS, which in turn makes a request to the hub. The
hub then fans out a message to another guest DS.</t>
        <t>Both the message sending and the fanout parts of the protocol are designed in a
request/response pattern. In the first protocol part, the client sends a
DSRequest message to the Delivery Service and the Delivery Service responds with
a DSResponse message. This pattern can easily be used over e.g. RESTful APIs.</t>
        <figure>
          <name>Delivery Service Request/Response scheme</name>
          <artset>
            <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="160" width="168" viewBox="0 0 168 160" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round">
                <path d="M 8,48 L 8,144" fill="none" stroke="black"/>
                <path d="M 144,48 L 144,144" fill="none" stroke="black"/>
                <path d="M 8,80 L 136,80" fill="none" stroke="black"/>
                <path d="M 16,128 L 144,128" fill="none" stroke="black"/>
                <polygon class="arrowhead" points="144,80 132,74.4 132,85.6" fill="black" transform="rotate(0,136,80)"/>
                <polygon class="arrowhead" points="24,128 12,122.4 12,133.6" fill="black" transform="rotate(180,16,128)"/>
                <g class="text">
                  <text x="28" y="36">Client</text>
                  <text x="152" y="36">Hub</text>
                  <text x="56" y="68">DSRequest</text>
                  <text x="60" y="116">DSResponse</text>
                </g>
              </svg>
            </artwork>
            <artwork type="ascii-art"><![CDATA[
Client           Hub
|                |
| DSRequest      |
+--------------->|
|                |
| DSResponse     |
|<---------------+
|                |
]]></artwork>
          </artset>
        </figure>
        <t>For the second part of the protocol the Delivery Service sends a DSFanoutRequest
to each guest DS. This happens whenever a message needs to be fanned out to all
other members of a group as a result of an incoming DSRequest. The guest DS in
turn responds with a DSFanoutResponse.</t>
        <figure>
          <name>Client/Delivery Service communication with fanout</name>
          <artset>
            <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="240" width="592" viewBox="0 0 592 240" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round">
                <path d="M 8,48 L 8,224" fill="none" stroke="black"/>
                <path d="M 144,48 L 144,224" fill="none" stroke="black"/>
                <path d="M 416,48 L 416,224" fill="none" stroke="black"/>
                <path d="M 8,80 L 136,80" fill="none" stroke="black"/>
                <path d="M 16,128 L 144,128" fill="none" stroke="black"/>
                <path d="M 144,160 L 408,160" fill="none" stroke="black"/>
                <path d="M 152,208 L 416,208" fill="none" stroke="black"/>
                <polygon class="arrowhead" points="416,160 404,154.4 404,165.6" fill="black" transform="rotate(0,408,160)"/>
                <polygon class="arrowhead" points="160,208 148,202.4 148,213.6" fill="black" transform="rotate(180,152,208)"/>
                <polygon class="arrowhead" points="144,80 132,74.4 132,85.6" fill="black" transform="rotate(0,136,80)"/>
                <polygon class="arrowhead" points="24,128 12,122.4 12,133.6" fill="black" transform="rotate(180,16,128)"/>
                <g class="text">
                  <text x="28" y="36">Client</text>
                  <text x="152" y="36">Hub</text>
                  <text x="432" y="36">Guest</text>
                  <text x="492" y="36">Delivery</text>
                  <text x="560" y="36">Service</text>
                  <text x="56" y="68">DSRequest</text>
                  <text x="60" y="116">DSResponse</text>
                  <text x="216" y="148">DSFanoutRequest</text>
                  <text x="220" y="196">DSFanoutResponse</text>
                </g>
              </svg>
            </artwork>
            <artwork type="ascii-art"><![CDATA[
Client           Hub                               Guest Delivery Service
|                |                                 |
| DSRequest      |                                 |
+--------------->|                                 |
|                |                                 |
| DSResponse     |                                 |
|<---------------+                                 |
|                | DSFanoutRequest                 |
|                +-------------------------------->|
|                |                                 |
|                | DSFanoutResponse                |
|                |<--------------------------------+
|                |                                 |
]]></artwork>
          </artset>
        </figure>
      </section>
      <section anchor="supported-operations">
        <name>Supported operations</name>
        <t>The MIMI DS protocol allows guest clients to request a variety of operations for
example to manage group membership, join groups, or send messages.</t>
        <ul spacing="normal">
          <li>Group creation/deletion</li>
          <li>Join a group from a Welcome message as a new member</li>
          <li>Join a group through an External Commit message as a new member
or client of an existing member (e.g. Resync a client after state loss)</li>
          <li>Adding and removing users to/from a group</li>
          <li>Adding and removing clients to/from a member of the group</li>
          <li>Client updates (MLS leaf updates)</li>
          <li>Sending application messages</li>
          <li>Download of KeyPackages</li>
          <li>Enqueueing of a message fanned out from an hub</li>
          <li>Download of connection-specific KeyPackages</li>
        </ul>
      </section>
      <section anchor="client-removals-induced-by-the-delivery-service">
        <name>Client removals induced by the Delivery Service</name>
        <t>Independent of client requests, the Delivery Service itself can remove clients
from a group by issuing remove proposals in the following cases:</t>
        <ul spacing="normal">
          <li>A user has removed a client from its account</li>
          <li>A user has been deleted</li>
          <li>The client is removed from the group because it has been inactive for too
long</li>
        </ul>
      </section>
      <section anchor="serialization-format">
        <name>Serialization format</name>
        <t>MLS messages use the presentation language and encoding format defined in
<xref target="RFC8446"/> with the extensions defined in the MLS protocol specification. The
MIMI DS protocol uses the same serialization format, as both clients and DS
already have to support it to process MLS messages.</t>
        <t>Octet strings resulting from serialization in this format are unambiguous and
require no further canonicalization.</t>
      </section>
      <section anchor="keypackages">
        <name>KeyPackages</name>
        <t>Clients have to upload KeyPackages such that others can add them to groups. In
the context of interoperability, this means that clients have to be able to
download KeyPackages of clients belonging to other DSs.</t>
        <t>The MIMI DS protocol allows clients to download the KeyPackages of other
clients. Uploading KeyPackages is outside of the scope of this protocol, as it
is not relevant for interoperability.</t>
        <t>TODO: KeyPackages of last resort should be marked. Ideally by using a KeyPackage
extension.</t>
        <section anchor="connection-keypackages">
          <name>Connection KeyPackages</name>
          <t>In addition to regular KeyPackages, the MIMI DS protocol requires clients to
provide connection KeyPackages for other clients to download. Connection
KeyPackages are meant for use in the connection establishment process (explained
in more detail in <xref target="connection-establishment-flow"/>) and differ from regular
KeyPackages only in that they include a LeafNode extension marking them as such.</t>
          <t>TODO: Such an extension would have to be specified in the context of the MLS WG.</t>
        </section>
      </section>
      <section anchor="enqueue-authorization">
        <name>Enqueue authorization</name>
        <t>TODO: This section sketches an authorization mechanism based on a KeyPackage
extension. That extension would have to be defined in the context of the MLS WG.</t>
        <t>Each KeyPackage that a client publishes also carries a FanoutAuthToken inside
a FanoutAuth KeyPackage extension.</t>
        <artwork><![CDATA[
struct {
  opaque token<V>;
} FanoutAuthToken
]]></artwork>
        <t>Whenever a client is added to a group (or when a new group is created), the DS
checks that the KeyPackages of all joiners contain a FanoutAuth extension and
stores the contained token alongside the group state.</t>
        <t>The FanoutAuthToken is included in DSFanoutRequests and allows the receiving
DS to check whether the sender is authorized to enqueue messages for the
recipient.</t>
        <t>Clients can change their FanoutAuthToken by sending a new token with an
update operation.</t>
        <t>TODO: Details on the cryptographic scheme underlying the token.</t>
      </section>
      <section anchor="clients-and-users">
        <name>Clients and users</name>
        <t>TODO: This section needs to be revisited once identifiers and client/user
authentication in general have been decided on by the MIMI WG.</t>
        <t>TODO: This topic is still under discussion, so this section only represents a
suggestion for an MLS-based flow. Once we have more clarity on what participant
data management looks like, we will update all other relevant sections of this
document.</t>
        <t>Each MIMI-DS managed group contains a MIMIParticipantExtension as part of its
GroupContext. The MIMIParticipantExtension contains a participant list, i.e. all
users that are associated with the group. Note that this includes inactive
participants.</t>
        <t>TODO: This extension can later be extended by also containing the roles of the
participants to facilitate RBAC.</t>
        <t>The participant list is changed via MIMIParticipant proposals, which can be
issued by clients or servers and that can be the committed by clients as part of
client-initiated operations as specified in <xref target="operations"/>. Each
MIMIParticpipant proposal can add, remove or update a user's record in the
MIMIParticipantExtension. The data in the extension MUST be consistent with the
membership data of the MLS group.</t>
      </section>
      <section anchor="version-agility">
        <name>Version agility</name>
        <t>MLS provides version, ciphersuite and extension agility. The versions,
ciphersuites and extensions a client supports are advertised in its LeafNodes,
both in all of the client's groups, as well as in its KeyPackages through the
Capabilities field (Section 7.2 of <xref target="I-D.ietf-mls-protocol"/>).</t>
        <t>MLS DS protocol clients MUST make use of a LeafNode extension to advertise the
MIMI DS protocol versions they support.</t>
        <t>TODO: Such an extension would have to be specified in the context of the MLS WG.</t>
      </section>
      <section anchor="group-lifecycle">
        <name>Group lifecycle</name>
        <t>Upon creation MLS groups are parameterized by a GroupID, an MLS version number,
as well as a ciphersuite. All three parameters are fixed and cannot be changed
throughout the lifetime of a group.</t>
        <t>Groups capable of interoperability with the MIMI DS protocol MUST use a
GroupContext extension that indicates the MIMI DS protocol version with which it
was created. This extension MUST NOT be changed throughout the lifetime of the
group.</t>
        <t>While all these parameters cannot be changed throughout a group's lifetime, the
group can be re-initialized as described in Section 11.2. of
<xref target="I-D.ietf-mls-protocol"/> to create a new group with a new set of parameters.</t>
        <t>The MIMI DS protocol supports re-initializations of groups using the
corresponding ReInitialization operation under the condition that all MLS
parameters are compatible with the MIMI DS protocol version.</t>
        <t>If a group is no longer used, it can be deleted either by a client or the DS
itself.</t>
        <t>TODO: Each MIMI DS protocol version should probably fix a set of ciphersuites,
MLS protocol versions and maybe even extensions it supports. New ones can be
added with protocol version upgrades.</t>
      </section>
    </section>
    <section anchor="security-properties-overview">
      <name>Security properties overview</name>
      <t>The MIMI DS protocol provides a number of security guarantees.</t>
      <section anchor="mls-based-security-properties">
        <name>MLS-based security properties</name>
        <t>The MLS protocol underlying the MIMI DS protocol provides a number of security
guarantees that primarily affect end-to-end communication between clients such
as authentication and confidentiality with forward- as well as post-compromise
security (although the latter only holds for application messages). While the
MIMI DS protocol acts as a layer around the MLS protocol it inherits some of
MLSs security guarantees.</t>
        <t>More concretely, the DS can verify client signatures on MLS messages and thus
ensure that end-to-end authentication holds. Since the DS uses MLS messages to
track the group state (including group membership), it is guaranteed to have the
same view of that state as the group members.</t>
        <t>Finally, the MIMI DS protocol also makes use of the authenticated channel
provided by MLS to verify the authenticity of relevant extension data such as
the FanoutAuth tokens used for queue authorization.</t>
      </section>
      <section anchor="queue-authorization">
        <name>Queue Authorization</name>
        <t>When a client from a guest DS joins a group, it provides the hub with a
FanoutAuth token. The hub can then use that token to prove to the guest DS
that it is authorized to deliver messages to the queue of that client.</t>
      </section>
    </section>
    <section anchor="framing-and-processing-overview">
      <name>Framing and processing overview</name>
      <section anchor="client-to-server-requests">
        <name>Client to server requests</name>
        <t>All client to server requests consist of a MIMI DS specific protocol wrapper
called DSRequst. DSRequest contains the MIMI DS protocol version, a body with
operation-specific data, as well as authentication information.</t>
        <artwork><![CDATA[
enum {
  ds_request_group_id(0),
  ds_create_group(1),
  ds_delete_group(2),
  ...
} DSRequestType;

struct {
  DSRequestType request_type;
  select (DSRequestBody.request_type) {
    case ds_delete_group:
      DeleteGroupRequest delete_group_request;
    ...
  }
} DSRequestBody;

struct {
  DSProtocolVersion version;
  DSRequestBody request_body;
  DSAuthData authentication_data;
} DSRequest;
]]></artwork>
        <t>A DS supports a variety of operations. For presentational reasons, we only
define DSRequestType and the corresponding <tt>case</tt> statement in DSRequestBody
partially here. The full definition with all operations relevant for the
normal DS operating mode can be found in <xref target="operations"/>.</t>
        <t>The <tt>authentication_data</tt> field of a DSRequest depends on the request type and
contains the data necessary for the DS to authenticate the request.</t>
        <artwork><![CDATA[
enum {
  Anonymous,
  ClientSignature,
} DSAuthType;

struct {
  DSAuthType auth_type;
  select (DSAuthData.auth_type) {
    case Anonymous:
      struct {};
    case ClientSignature:
      uint32 sender_index;
      opaque signature<0..255>;
  }
} DSAuthData;
]]></artwork>
        <t>Before the DS performs the requested operation, it performs an authentication
operation depending on the DSAuthType.</t>
        <ul spacing="normal">
          <li>Anonymous: No authentication required</li>
          <li>ClientSignature: The DS uses the public signature key of the MLS client in
leaf with the leaf index <tt>sender_index</tt> to verify the signature over the
following struct:</li>
        </ul>
        <artwork><![CDATA[
struct {
  DSProtocolVersion protocol_version;
  DSRequestBody request_body;
  u32 sender_index
} ClientSignatureTBS
]]></artwork>
        <t>Note that all group operations additionally contain an MLSMessage the content
of which mirrors the request type, e.g., an AddUsers request wraps an MLS commit
that in turn contains the Add proposals for the users' clients. In that case,
the DS uses the GroupID inside the MLSMessage to determine which group the
request refers to and verifies the MLSMessage in the same way an MLS client
would (including the signature).</t>
        <t>Depending on the nature of the request, clients can also include data in the AAD
field of the MLSMessage, where it can be read and authenticated by both DS and
all other group members.</t>
        <t>After performing the desired operation using the data in DSRequestBody the DS
responds to the client (or the proxying guest DS) with a DSResponse.</t>
        <artwork><![CDATA[
struct {
  DSProtocolVersion protocol_version;
  DSResponseBody response_body;
} DSResponse

enum DSResponseType {
  Ok,
  Error,
  GroupID,
  WelcomeInfo,
  ExternalCommitInfo
  SignaturePublicKey,
  KeyPackages,
  ConnectionKeyPackages,
}

struct DSResponseBody {
  DSResponseType response_type;
  select (DSResponseBody.response_type) {
    case Ok:
      struct {};
    case Error:
      DSError error;
    case GroupID:
      opaque group_id<V>;
    case WelcomeInfo:
      optional<Node> ratchet_tree<V>;
    case ExternalCommit:
      MLSMessage: group_info;
      optional<Node> ratchet_tree<V>;
    case SignaturePublicKey:
      SignaturePublicKey signature_public_key;
    case KeyPackages:
      KeyPackage key_packages<V>;
    case ConnectionKeyPackages:
      KeyPackage key_packages<V>;
  }
}

struct {
  TODO: Operation specific errors.
} DSError
]]></artwork>
      </section>
      <section anchor="server-to-server-requests">
        <name>Server to server requests</name>
        <t>After sending the response, and depending on the operation the DS might fan out
messages to one or more guest DSs.</t>
        <t>To that end, it wraps the MLSMessage to be fanned out into a DSFanoutRequest. In
addition to the MLSMessage, the DSFanoutRequest contains the protocol version, a
list of client ids representing the clients for which the payload is meant, a
FanoutAuthToken (see <xref target="enqueue-authorization"/>) for each of the clients, as well
as the payload to be fanned out.</t>
        <artwork><![CDATA[
struct {
  DSProtocolVersion protocol_version;
  opaque recipient_ids<V>;
  FanoutAuthToken fanout_auth_tokens<V>;
  MLSMessage mls_message;
} DSFanoutRequest
]]></artwork>
        <t>The receiving DS first verifies the signature using the sending DS' public
signature key and then further validates the message by performing the following
checks:</t>
        <ul spacing="normal">
          <li>That the protocol version is compatible with its configuration</li>
          <li>That the <tt>recipient_ids</tt> are all clients of this DS</li>
          <li>The the <tt>fanout_auth_tokens</tt> are all valid tokens for the individual
recipients</li>
        </ul>
        <t>The recieving DS can then store and forward the contained MLS message to the
clients indicated in the <tt>recipient_ids</tt> field and send a DSFanoutResponse.</t>
        <artwork><![CDATA[
enum {
  Ok,
  Error,
} DSFanoutResponseType

struct {
  TODO: Fanout error types
} DSFanoutError

struct DSFanoutResponseBody {
  DSFanoutResponseType response_type;
  select (DSFanoutResponseBody.response_type) {
    case Ok:
      struct {};
    case Error:
      DSFanoutError error;
  }
}

struct {
  DSProtocolVersion protocol_version;
  DSResponseBody response_body;
} DSFanoutResponse
]]></artwork>
      </section>
      <section anchor="keypackages-1">
        <name>KeyPackages</name>
        <t>As noted in <xref target="keypackages"/>, clients must upload KeyPackages such that other
clients can add them to groups.</t>
      </section>
    </section>
    <section anchor="connection-establishment-flow">
      <name>Connection establishment flow</name>
      <t>A user can establish a connection to another user by creating a connection
group, fetching a connection KeyPackage of the target user's clients from its DS
and inviting that user to the connection group. The receiving user can process
the Welcome and figure out from the group state who the sender is. Additional
information can either be attached to the group via an extension, or via MLS
application messages within that group.</t>
      <t>TODO: This is a sketch for a simple connection establishment flow that allows
the recipient to identify and authenticate the sender and that establishes an
initial communication channel between the two users. More functionality can be
added via additional messages or MLS extensions.</t>
      <figure>
        <name>Example flow for connection establishment</name>
        <artset>
          <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="336" width="632" viewBox="0 0 632 336" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round">
              <path d="M 8,48 L 8,304" fill="none" stroke="black"/>
              <path d="M 240,48 L 240,88" fill="none" stroke="black"/>
              <path d="M 240,104 L 240,136" fill="none" stroke="black"/>
              <path d="M 240,152 L 240,304" fill="none" stroke="black"/>
              <path d="M 448,48 L 448,304" fill="none" stroke="black"/>
              <path d="M 608,48 L 608,304" fill="none" stroke="black"/>
              <path d="M 8,96 L 440,96" fill="none" stroke="black"/>
              <path d="M 16,144 L 448,144" fill="none" stroke="black"/>
              <path d="M 8,192 L 232,192" fill="none" stroke="black"/>
              <path d="M 8,240 L 232,240" fill="none" stroke="black"/>
              <path d="M 240,256 L 440,256" fill="none" stroke="black"/>
              <path d="M 448,272 L 600,272" fill="none" stroke="black"/>
              <polygon class="arrowhead" points="608,272 596,266.4 596,277.6" fill="black" transform="rotate(0,600,272)"/>
              <polygon class="arrowhead" points="448,256 436,250.4 436,261.6" fill="black" transform="rotate(0,440,256)"/>
              <polygon class="arrowhead" points="448,96 436,90.4 436,101.6" fill="black" transform="rotate(0,440,96)"/>
              <polygon class="arrowhead" points="240,240 228,234.4 228,245.6" fill="black" transform="rotate(0,232,240)"/>
              <polygon class="arrowhead" points="240,192 228,186.4 228,197.6" fill="black" transform="rotate(0,232,192)"/>
              <polygon class="arrowhead" points="24,144 12,138.4 12,149.6" fill="black" transform="rotate(180,16,144)"/>
              <g class="text">
                <text x="24" y="36">Alice</text>
                <text x="248" y="36">Hub</text>
                <text x="464" y="36">Guest</text>
                <text x="500" y="36">DS</text>
                <text x="616" y="36">Bob</text>
                <text x="48" y="68">Request</text>
                <text x="124" y="68">Connection</text>
                <text x="64" y="84">KeyPackages</text>
                <text x="60" y="132">Connection</text>
                <text x="152" y="132">KeyPackages</text>
                <text x="44" y="180">Create</text>
                <text x="116" y="180">Connection</text>
                <text x="184" y="180">group</text>
                <text x="32" y="228">Add</text>
                <text x="88" y="228">Responder</text>
                <text x="488" y="228">Deliver</text>
                <text x="552" y="228">Welcome</text>
                <text x="264" y="244">Fan</text>
                <text x="296" y="244">out</text>
                <text x="344" y="244">Welcome</text>
                <text x="508" y="244">(proprietary</text>
                <text x="504" y="260">protocol)</text>
              </g>
            </svg>
          </artwork>
          <artwork type="ascii-art"><![CDATA[
Alice                        Hub                       Guest DS            Bob
+                            +                         +                   +
| Request Connection         |                         |                   |
| KeyPackages                |                         |                   |
+----------------------------------------------------->+                   |
|                            |                         |                   |
| Connection KeyPackages     |                         |                   |
+<-----------------------------------------------------+                   |
|                            |                         |                   |
| Create Connection group    |                         |                   |
+--------------------------->+                         |                   |
|                            |                         |                   |
| Add Responder              |                         | Deliver Welcome   |
+--------------------------->+ Fan out Welcome         | (proprietary      |
|                            +------------------------>+  protocol)        |
|                            |                         +------------------>+
|                            |                         |                   |
+                            +                         +                   +

]]></artwork>
        </artset>
      </figure>
    </section>
    <section anchor="ds-assisted-joining">
      <name>DS assisted joining</name>
      <t>To verify and deliver messages, authenticate clients as members of a group and
to assist clients that want to join a group, the DS keeps track of the state of
each group for which it is the hub. More specifically, it keeps track of the
group's ratchet tree, the group's GroupContext and other information required to
produce a valid GroupInfo for the current group epoch. It does this by
processing incoming MLS messages in the same way a member of that group would,
except of course that the DS doesn't hold any private key material.</t>
      <t>While MLS messages are sufficient to keep track of most of the group information,
it is not quite enough to create a GroupInfo. To allow the DS to provide a valid
GroupInfo to externally joining clients, it additionally requires clients to
provide the remaining required information. Concretely, it requires clients to
upload the Signature and the GroupInfo extensions. Clients need to send this
information whenever they send an MLS message (i.e. an MLSMessage struct) that
contains a commit.</t>
      <artwork><![CDATA[
struct {
  Extension group_info_extensions<V>;
  opaque Signature<V>;
} PartialGroupInfo
]]></artwork>
      <t>The combination of a commit and a partial group info is called an
MLSGroupUpdate.</t>
      <artwork><![CDATA[
struct {
  MLSMessage commit;
  PartialGroupInfo partial_group_info;
} MLSGroupUpdate
]]></artwork>
      <t>Whenever the DS receives an MLSGroupUpdate, it must verify that the
MLSMessage contains a PublicMessage with a commit and that commit and partial
group info are valid relative to the existing group state according to the MLS
specification.</t>
      <t>TODO: For now there is no distinct endpoint to obtain authentication material
that allows the DS to authenticate clients. This would be part of the AS design.</t>
      <t>By tracking the group information in this way, the DS can help clients that join
via external commit by providing them with a ratchet tree and a group into.</t>
      <t>Similary, clients that wish to join a group via a regular invite (i.e. a Welcome
message) have already received a GroupInfo and can obtain a ratchet tree from
the DS.</t>
      <t>In the time between a client being added to a group by a commit and the client
wanting to join the group, the group state can have progressed by one or more
epochs. As a consequence, the DS MUST keep track of epochs in which clients are
added and store the corresponding group states until each client has
successfully joined.</t>
    </section>
    <section anchor="proposals-by-reference">
      <name>Proposals and DS-initiated operations</name>
      <t>MLS relies on a proposal-commit logic, where the proposals encode the specific
action the sending client intends to take and the commit then performs the
actions of a set of commits.</t>
      <t>The advantage of this approach is that the sender of the proposal does not have
to be the committer, which allows, for example, the DS to propose the removal of
a client, or a client to propose that it be removed from the group. Note that
the latter example is the only way that a client can remove itself (i.e. leave)
from a group.</t>
      <t>Such proposals, where the original sender differs from the sender of the commit
are called "proposal by reference", or "proposal by value" if the proposal is
sent by the committer as part of the commit itself.</t>
      <t>The following sections detail operations that can be performed by clients, so
each operation that entails a change to the group state (with the exception of
the self remove operation) require the sender to perform a commit, where the
semantics of the operation are reflected as proposals by value. For example, the
commit in the AddUsersRequest must only contain Add proposals.</t>
      <t>If a client receives a valid standalone proposal, it MUST store it and verify
that the next commit includes said proposal.</t>
      <t>TODO: Be more specific about proposal validation. Also, we might want to allow
the server to rescind a proposal.</t>
      <t>Whenever a client sends a commit as part of an operation, it MUST include all
stored proposals by reference, such as server-initiated Remove proposals, or proposals sent
as part of a self-remove operation.</t>
      <t>TODO: Proposals by reference pose a problem in the context of external commits,
as, even if the external committer had access to all proposals in an epoch, it
wouldn't be able to verify them, thus potentially leading to an invalid external
commit. A solution could be introduced either as part of the MIMI DS protocol,
or as an MLS extension. The latter would be preferable, as other users of MLS
are likely going to encounter the same problem.</t>
    </section>
    <section anchor="ds-operations">
      <name>DS-initiated operations</name>
      <t>While the nature of MLS prevents the DS from performing changes to the group
state itself, it can propose that clients perform certain actions and enforce
the enactment of such proposals.</t>
      <t>To allow the DS to send proposals, all groups MUST contain an <tt>external_senders</tt>
extension as defined in Section 12.1.8.1. of <xref target="I-D.ietf-mls-protocol"/> that
includes the DS' credential and its signature public key.</t>
      <t>TODO: We might also want to mandate that the group includes credentials of guest
DSs involved in the group. However, for them to be able to send proposals, we'd
need an additional operation/endpoint that the DS exposes.</t>
      <t>TODO: Details of the DS credential. A BasicCredential
with the FQDN of the DS would probably be sufficient.</t>
      <t>The DS can simply create such proposals itself based on the group information
and distribute it to all group members via regular DSFanoutRequests.</t>
      <section anchor="client-removals">
        <name>Client removals</name>
        <t>The DS can propose that one or more clients be removed from a given group. To
that end, it issues a remove proposal for each client it wants removed, where
each remove proposal targets the leaf of one of the clients in question.</t>
      </section>
      <section anchor="client-additions">
        <name>Client additions</name>
        <t>The DS can propose that one or more clients be added to the group. It does so by
issueing an add proposal for each client, where each add proposal contains a
KeyPackage of the respective client.</t>
        <t>TODO: If the DS should be allowed to add clients that belong to another DS, we
need an endpoint that allows DSs to fetch KeyPackages from one-another.</t>
      </section>
    </section>
    <section anchor="operations">
      <name>Client-initiated operations</name>
      <t>The DS supports a number of operations, each of which is represented by a
variant of the DSRequestType enum and has its own request body.</t>
      <artwork><![CDATA[
enum {
  ds_request_group_id(0),
  ds_create_group(1),
  ds_delete_group(2),
  ds_add_users(3),
  ds_remove_users(4),
  ds_add_clients(5),
  ds_remove_clients(6),
  ds_self_remove_client(7),
  ds_update_client(8),
  ds_external_join(9),
  ds_send_message(10),
  ds_signature_public_key(11),
  ds_key_packages(12),
  ds_connection_key_packages(13),
  ds_re_initialize_group(14),
} DSRequestType;

struct {
  DSRequestType request_type;
  select (DSRequestBody.request_type) {
    case ds_request_group_id:
      struct {};
    case ds_create_group:
      CreateGroupRequest create_group_request;
    case ds_delete_group:
      DeleteGroupRequest delete_group_request;
    case ds_add_users:
      AddUsersRequest add_users_request;
    case ds_remove_users:
      RemoveUsersRequest remove_users_request;
    case ds_add_clients:
      AddClientsRequest add_clients_request;
    case ds_remove_clients:
      RemoveClientsRequest remove_clients_request;
    case ds_self_remove_clients:
      SelfRemoveClientsRequest self_remove_clients_request;
    case ds_update_client:
      UpdateClientRequest update_client_request;
    case ds_external_join:
      ExternalJoinRequest external_join_request;
    case ds_send_message:
      SendMessageRequest send_message_request;
    case ds_signature_public_key:
      struct {};
    case ds_key_packages:
      KeyPackagesRequest key_packages_request;
    case ds_connection_key_packages:
      ConnectionKeyPackagesRequest connection_key_packages_request;
    case ds_re_initialize_group:
      ReInitializeGroupRequest re_initialize_group_request;
  }
} DSRequestBody;
]]></artwork>
      <section anchor="request-group-id">
        <name>Request group id</name>
        <t>Clients can use this operation to request a group id. This group ID can
subsequently used to create a group on this DS.</t>
        <t>After receiving this request, the DS generates a unique group id and responds
with a DSResponse struct of type GroupID.</t>
      </section>
      <section anchor="create-group">
        <name>Create group</name>
        <t>A request from the client to create a new group on the Delivery Service. This
operation can be used both for the creation of regular groups and for the
creation of connection groups.</t>
        <t>The client sends the following CreateGroupRequest to the Delivery Service:</t>
        <artwork><![CDATA[
struct {
  opaque group_id<V>;
  LeafNode LeafNode;
  MLSMessage group_info;
} CreateGroupRequest;
]]></artwork>
        <t>The Delivery Service internally creates and stores the group based on the
information in the request and responds with a CreateGroupResponse:</t>
        <artwork><![CDATA[
enum {
  invalid_group_id(0),
  invalid_leaf_node(1),
  invalid_group_info(2),
} CreateGroupResponse;
]]></artwork>
        <t>TODO: How to mark connection groups? Have the creator include a connection
extension in the LeafNode?</t>
        <t><strong>Validation:</strong></t>
        <t>The Delivery Service validates the request as follows:</t>
        <ul spacing="normal">
          <li>The group ID MUST NOT be not empty and MUST NOT already be in use.</li>
          <li>The LeafNode MUST be valid, according to <xref target="I-D.ietf-mls-protocol"/> 7.3. Leaf
Node validation.</li>
          <li>The GroupInfo MUST be valid, according to <xref target="I-D.ietf-mls-protocol"/> 12.4.3.
Adding Members to the Group.</li>
        </ul>
      </section>
      <section anchor="delete-group">
        <name>Delete group</name>
        <t>A request from the client to delete a group from the Delivery Service. This
operation allows clients to delete a group from the DS. Clients can of course
keep a copy of the group state locally for archival purposes.</t>
        <artwork><![CDATA[
struct {
  MLSGroupUpdate group_update;
} DeleteGroupRequest;
]]></artwork>
        <t><strong>Validation:</strong></t>
        <t>The Delivery Service validates the request as follows:</t>
        <ul spacing="normal">
          <li>The MLSGroupUpdate MUST contain a PublicMessage with a commit that contains
Remove proposals for every member of the group except the committer.</li>
        </ul>
      </section>
      <section anchor="add-users-to-a-group">
        <name>Add users to a group</name>
        <t>A request from a client to add one or more users to a group. For each user, one
or more of the user's clients are added to the group. The Welcome messages in
the request are then fanned out to the user's DSs.</t>
        <t>To obtain the KeyPackages required to add the users' clients, the sender must
first fetch the clients' KeyPackages from their DS.</t>
        <artwork><![CDATA[
struct {
  MLSGroupUpdate group_update;
  MLSMessage welcome_messages<V>;
} AddUsersRequest;
]]></artwork>
        <t><strong>Validation:</strong></t>
        <ul spacing="normal">
          <li>The MLSGroupUpdate in the <tt>commit</tt> field MUST contain a PublicMessage with a
commit that contains only Add proposals with the possible exception of Remove
proposals as detailed in <xref target="proposals-by-reference"/>.</li>
          <li>The commit MUST NOT change the sender's client credential.</li>
          <li>Add proposals MUST NOT contain clients of existing group members.</li>
          <li>Add proposals MUST NOT contain connection KeyPackages, except if the group is
a connection group.</li>
          <li>If guest users are added as part of the request, there MUST be a distinct
Welcome message for each guest DS involved.</li>
          <li>All KeyPackages included in Add proposals MUST include a FanoutAuth extension.</li>
        </ul>
      </section>
      <section anchor="remove-users-from-a-group">
        <name>Remove users from a group</name>
        <t>A request from a client to remove one or more users from a group. The DS will
still fan out the request to the users. The commit contained in the message will
allow the users to recognize that they were removed.</t>
        <artwork><![CDATA[
struct {
  MLSGroupUpdate group_update;
} RemoveUsersRequest;
]]></artwork>
        <t><strong>Validation:</strong></t>
        <ul spacing="normal">
          <li>The MLSGroupUpdate MUST contain a PublicMessage with a commit that contains
only Remove proposals (see also <xref target="proposals-by-reference"/>).</li>
          <li>The commit MUST NOT change the sender's client credential.</li>
          <li>The Remove proposals that are committed by-value MUST always remove all
clients of one or more users.</li>
        </ul>
      </section>
      <section anchor="add-clients-to-a-group">
        <name>Add clients to a group</name>
        <t>A request from a client to add one or more clients of the same user. This
operation allows users to add new clients to an existing group. Alternatively,
new clients can add themselves by joining via external commit.</t>
        <artwork><![CDATA[
struct {
  MLSGroupUpdate group_update;
  MLSMessage welcome_messages<V>;
} AddClientsRequest;
]]></artwork>
        <t><strong>Validation:</strong></t>
        <ul spacing="normal">
          <li>The MLSGroupUpdate MUST contain a PublicMessage with a commit that contains
only Add proposals with the possible exception of Remove proposals as detailed
in <xref target="proposals-by-reference"/>.</li>
          <li>The commit MUST NOT change the sender's client credential.</li>
          <li>All Add proposals MUST contain clients of the same user as an existing group
member.</li>
          <li>All KeyPackages included in Add proposals MUST include a FanoutAuth extension.</li>
        </ul>
      </section>
      <section anchor="remove-clients-from-a-group">
        <name>Remove clients from a group</name>
        <t>A request from a client to remove one or more other clients of the same user
from a group. This operation allows users to remove their own clients from a
group. Note that this operation cannot be used by a client to remove itself from
the group. For that purpose, the SelfRemoveClientRequest should be used instead.</t>
        <artwork><![CDATA[
struct {
  MLSGroupUpdate group_update;
} RemoveClientsRequest;
]]></artwork>
        <t><strong>Validation:</strong></t>
        <ul spacing="normal">
          <li>The MLSGroupUpdate MUST contain a PublicMessage with a commit that contains only
Remove proposals.</li>
          <li>The commit MUST NOT change the sender's client credential.</li>
          <li>All Remove proposals committed to by-value MUST target clients of the same
user as the sending client</li>
        </ul>
      </section>
      <section anchor="self-remove-a-client-from-a-group">
        <name>Self remove a client from a group</name>
        <t>A request from a client to remove itself from the group. If it's the last client
of a user, this effectively removes the user from the group. Note that this
request only contains a proposal, so the client is not effectively removed from
the group until another group member commits that proposal. See
<xref target="proposals-by-reference"/> for more details.</t>
        <artwork><![CDATA[
struct {
  MLSMessage proposal;
} SelfRemoveClientRequest;
]]></artwork>
        <t><strong>Validation:</strong></t>
        <ul spacing="normal">
          <li>The MLSMessage MUST contain a PublicMessage that contains a single
Remove proposal.</li>
          <li>The Remove proposal MUST target the sending client.</li>
        </ul>
      </section>
      <section anchor="update-a-client-in-a-group">
        <name>Update a client in a group</name>
        <t>A request from a client to update its own leaf in an MLS group. This operation
can be used to update any information in the sender's leaf node. For example,
the sender could use this operation to update its key material to achieve
post-compromise security, update its Capabilities extension, or its leaf
credential.</t>
        <t>The sending client can also choose to send a FanoutAuthToken, which the DS uses
to replace the client's existing token.</t>
        <artwork><![CDATA[
struct {
  MLSGroupUpdate group_update;
  optional<FanoutAuthToken> token;
} UpdateClientRequest;
]]></artwork>
        <t><strong>Validation:</strong></t>
        <ul spacing="normal">
          <li>The MLSGroupUpdate MUST contain a PublicMessage that contains a commit with an
UpdatePath, but no other proposals by value.</li>
          <li>If the leaf credential is changed by the update, the DS MUST validate the new
credential.</li>
        </ul>
        <t>TODO: The discussion around identity and credentials should yield a method to
judge if a new credential is a valid update to an existing one.</t>
      </section>
      <section anchor="join-the-group-using-an-external-commit">
        <name>Join the group using an external commit</name>
        <t>A request from a client to join a group using an external commit, i.e. without
the help of an existing group member. This operation can be used, for example,
by new clients of a user that already has clients in the group, or by existing
group members that have to recover from state loss.</t>
        <t>To retrieve the information necessary to create the external commit, the joiner
has to fetch the external commit information from the DS.</t>
        <artwork><![CDATA[
struct {
  MLSGroupUpdate group_update;
} ExternalJoinRequest;
]]></artwork>
        <t><strong>Validation:</strong></t>
        <ul spacing="normal">
          <li>The MLSGroupUpdate MUST contain a PublicMessage that contains a commit with sender
type NewMemberCommit.</li>
          <li>The sender of the ExternalJoinRequest MUST be a client that belongs to a user
that is already in the group.</li>
        </ul>
      </section>
      <section anchor="send-an-application-message-to-a-group">
        <name>Send an application message to a group</name>
        <t>A request from a client to fan out an application message to a group. This
operation is meant to send arbitrary data to the rest of the group. Since the
application message is a PrivateMessage, the DS can not verify its content or
authenticate its sender (even though it does authenticate the sender of the
surrounding DSRequest).</t>
        <artwork><![CDATA[
struct {
  MLSMessage application_message;
} SendMessageRequest;
]]></artwork>
        <t><strong>Validation:</strong></t>
        <ul spacing="normal">
          <li>The MLSMessage MUST contain a PrivateMessage with ContentType application.</li>
        </ul>
      </section>
      <section anchor="fetch-the-ds-signature-public-key">
        <name>Fetch the DS' signature public key</name>
        <t>A request from a remote DS to retrieve the signature public key of this DS. The
signature public key can be used by other DSs to verify DSFanoutRequests sent by
the DS. While the DS also uses its signature private key to sign proposals (see
<xref target="proposals-by-reference"/>), clients should use the signature key included in
the group's <tt>external_senders</tt> extension to validate those.</t>
        <t>The DS responds with a DSResponse of type SignaturePublicKey that contains the
signature public key of this DS.</t>
      </section>
      <section anchor="fetch-keypackages-of-one-or-more-clients">
        <name>Fetch KeyPackages of one or more clients</name>
        <t>A request from a client to retrieve the KeyPackage(s) of one or more clients of
this DS. KeyPackages are required to add other clients (and thus other users) to
a group.</t>
        <artwork><![CDATA[
struct {
  ClientID client_identifiers<V>;
} KeyPackagesRequest;
]]></artwork>
        <t>The DS responds with the KeyPackages of all clients listed in the request.</t>
        <t><strong>Validation:</strong></t>
        <ul spacing="normal">
          <li>All client identifiers MUST refer to clients native to this DS.</li>
          <li>The DS SHOULD verify that the sender of the request is authorized to retrieve
the DSKeyPackages of the clients in question. For example, it could check if
the user of the sending client has a connection with the user of the target
client(s).</li>
        </ul>
      </section>
      <section anchor="fetch-connection-keypackages-of-one-or-more-clients">
        <name>Fetch connection KeyPackages of one or more clients</name>
        <t>A request from a client to retrieve the KeyPackage(s) of all clients of a user
of this DS. KeyPackages obtained via this operation can only be used to add
clients to a connection group.</t>
        <t>Connection KeyPackages are available separately from regular KeyPackages, as
they are meant to be accessed by clients of users with which the owning user has
no connection.</t>
        <artwork><![CDATA[
struct {
  UserID user_identifier;
} ConnectionKeyPackagesRequest;
]]></artwork>
        <t>The DS responds with connection KeyPackages of all clients of the user
corresponding to the identifier in the request.</t>
        <t><strong>Validation:</strong></t>
        <ul spacing="normal">
          <li>All client identifiers MUST refer to clients native to this DS.</li>
          <li>All clients referred to by the identifiers MUST belong to the same user.</li>
        </ul>
      </section>
      <section anchor="reinitialize-a-group">
        <name>ReInitialize a group</name>
        <t>A request from a client to re-initialize a group with different parameters as
outlined in <xref target="group-lifecycle"/>.</t>
        <artwork><![CDATA[
struct {
  MLSGroupUpdate commit;
} ReInitializeGroupRequest;
]]></artwork>
        <t><strong>Validation:</strong></t>
        <ul spacing="normal">
          <li>The MLSGroupUpdate MUST contain a PublicMessage that contains a commit with a
re-init proposal.</li>
          <li>The GroupID in the re-init proposal MUST point to another group on this hub,
which has a MIMI DS protocol version that is greater or equal than this group.</li>
        </ul>
      </section>
    </section>
    <section anchor="dsfanoutrequests-and-ds-to-ds-authentication">
      <name>DSFanoutRequests and DS-to-DS authentication</name>
      <t>After the DS has processed an incoming MLSMessage, it prepares a DSFanoutRequest
as described in <xref target="framing-and-processing-overview"/>.</t>
      <t>To authenticate these messages, an additional layer of DS-to-DS authentication
is required. As defined in <xref target="framing-and-processing-overview"/>, DSFanoutRequests
are signed using signing key of the sending DS. The receiving DS can obtain the
corresponding signature public key by sending a DSRequest to the sender
indicated in the DSFanoutRequest.</t>
      <t>The request for the signature public key MUST be sent via an HTTPS secured
channel, or otherwise authenticated using a root of trust present on the DS.</t>
      <t>TODO: If the transport provides server-to-server authentication this section and
the signature on the DSFanoutRequest can be removed.
TODO: Details on key management, caching etc. We can probably get away with
using very small lifetimes for these keys, as they can be re-fetched cheaply and
essentially at any time.</t>
    </section>
    <section anchor="role-based-access-control-in-groups">
      <name>Role-based access control in groups</name>
      <t>TODO: Access control is beyond the charter. However, to show how easily
implementable it is with MLS, this is section sketches a possible MLS extension
to handle access control in groups that is enforcible and verifiable by both
clients and DS. It is just an example and details can be changed later.</t>
      <t>As group operations are handled by MLS PublicMessages, the DS can enforce access
control policies on groups. The privileges of clients in a group are determined
by the group's RBAC GroupContext Extension.</t>
      <artwork><![CDATA[
struct {
  uint32 admins<V>;
} RBACExtension
]]></artwork>
      <t>The RBACExtension supports two roles: Members and Admins. Since all group
members are Members by default, the extension only lists admins.</t>
      <t>Any client the leaf node index of which is listed in the <tt>admins</tt> field of the
RBACExtension in a given group is considered as an Admin role and allowed to
perform the following operations in the context of this group.</t>
      <ul spacing="normal">
        <li>AddUsers, RemoveUsers, DeleteGroup, SetRole</li>
      </ul>
      <t>The SetRole operation is an additional operation available to groups that have
an RBACExtension.</t>
      <artwork><![CDATA[
struct {
  MLSGroupUpdate group_update;
} SetRoleRequest
]]></artwork>
      <t>The <tt>group_update</tt> needs to contain a commit which commits to a single
RBACProposal.</t>
      <artwork><![CDATA[
struct {
  uint32 promoted_members;
  uint32 demoted_members;
} SetRole
]]></artwork>
      <t>The DS (and all clients) process this proposal by changing the role of the group
members with the leaf indices listed in the <tt>promoted_members</tt> and
<tt>demoted_members</tt> fields and change the <tt>admins</tt> field of the group's
RBACExtension accordingly. For example, if the leaf index admin is listed in the
<tt>changed_members</tt> field of the proposal, it is demoted to Member and removed
from the <tt>admins</tt> field. Similarly, if a Member is listed, it is promoted to
Admin and added to the <tt>admins</tt> field.</t>
    </section>
    <section anchor="rate-limiting-and-spam-prevention">
      <name>Rate-limiting and spam prevention</name>
      <t>All requests (with the exception of the VerificationKeyRequest) can be
explicitly authenticated by the recipient through the verification of a
signature. This means that recipients can follow a rate-limiting strategy of
their choice based on the sender's identity.</t>
      <t>For DSRequests, the DS can rate-limit on a per group-level, per-DS level
(reducing the messages from all clients or users belonging to a single DS), or
even based on individual clients or users.</t>
      <t>For DSFanoutRequests, rate-limiting or blocking can happen based on the identity
of the sending DS, or it can happen on a per-group basis, where the recipient
only blocks messages from a particular group.</t>
      <t>Such rate-limiting can happen by decision of the DS itself, or on the request of
its local users. For example, a user might wish to block connection requests
from one specific other user without blocking connection requests from all other
users of that DS.</t>
    </section>
    <section anchor="abusive-and-illegal-content">
      <name>Abusive and illegal content</name>
      <t>As all application messages are encrypted, the DS has no way of analyzing their
content for illegal or abusive content. It may make use of a message franking
scheme to allow its users to report such content, although this is beyond the
scope of this document.</t>
      <t>Additionally, in the same way as a DS might allow its users to block certain
messages from specific users in the context of spam prevention, it may do the
same based on abusive or illegal content.</t>
    </section>
    <section anchor="security-considerations">
      <name>Security considerations</name>
      <t>TODO: There is currently no consensus in the MIMI w.r.t. the security goals we
want to reach.</t>
      <t>The underlying MLS protocol provides end-to-end encryption and authentication
for all MLSMessages, as well as group state agreement.</t>
      <section anchor="transport-security">
        <name>Transport Security</name>
        <t>Transport of DSFanoutRequests, as well as their responses MUST use a recipient
authenticated transport. This is to ensure that these messages are mutually
authenticated.</t>
        <t>To protect the metadata in all request-response flows, requests and responses
SHOULD be secured using an encrypted transport channel.</t>
      </section>
    </section>
  </middle>
  <back>
    <references>
      <name>Normative References</name>
      <reference anchor="I-D.ietf-mls-protocol">
        <front>
          <title>The Messaging Layer Security (MLS) Protocol</title>
          <author fullname="Richard Barnes" initials="R." surname="Barnes">
            <organization>Cisco</organization>
          </author>
          <author fullname="Benjamin Beurdouche" initials="B." surname="Beurdouche">
            <organization>Inria &amp; Mozilla</organization>
          </author>
          <author fullname="Raphael Robert" initials="R." surname="Robert">
            <organization>Phoenix R&amp;D</organization>
          </author>
          <author fullname="Jon Millican" initials="J." surname="Millican">
            <organization>Meta Platforms</organization>
          </author>
          <author fullname="Emad Omara" initials="E." surname="Omara">
            <organization>Google</organization>
          </author>
          <author fullname="Katriel Cohn-Gordon" initials="K." surname="Cohn-Gordon">
            <organization>University of Oxford</organization>
          </author>
          <date day="27" month="March" year="2023"/>
          <abstract>
            <t>Messaging applications are increasingly making use of end-to-end security mechanisms to ensure that messages are only accessible to the communicating endpoints, and not to any servers involved in delivering messages.  Establishing keys to provide such protections is challenging for group chat settings, in which more than two clients need to agree on a key but may not be online at the same time.  In this document, we specify a key establishment protocol that provides efficient asynchronous group key establishment with forward secrecy (FS) and post-compromise security (PCS) for groups in size ranging from two to thousands.
            </t>
          </abstract>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-ietf-mls-protocol-20"/>
      </reference>
      <reference anchor="RFC8446">
        <front>
          <title>The Transport Layer Security (TLS) Protocol Version 1.3</title>
          <author fullname="E. Rescorla" initials="E." surname="Rescorla"/>
          <date month="August" year="2018"/>
          <abstract>
            <t>This document specifies version 1.3 of the Transport Layer Security (TLS) protocol. TLS allows client/server applications to communicate over the Internet in a way that is designed to prevent eavesdropping, tampering, and message forgery.</t>
            <t>This document updates RFCs 5705 and 6066, and obsoletes RFCs 5077, 5246, and 6961. This document also specifies new requirements for TLS 1.2 implementations.</t>
          </abstract>
        </front>
        <seriesInfo name="RFC" value="8446"/>
        <seriesInfo name="DOI" value="10.17487/RFC8446"/>
      </reference>
    </references>
  </back>
  <!-- ##markdown-source:
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

-->

</rfc>
