<?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.7.19 (Ruby 3.0.2) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-lopresti-open-cloud-mesh-00" category="std" consensus="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.24.0 -->
  <front>
    <title>Open Cloud Mesh</title>
    <seriesInfo name="Internet-Draft" value="draft-lopresti-open-cloud-mesh-00"/>
    <author initials="G." surname="Lo Presti" fullname="Giuseppe Lo Presti">
      <organization>CERN</organization>
      <address>
        <email>giuseppe.lopresti@cern.ch</email>
        <uri>http://cern.ch/lopresti</uri>
      </address>
    </author>
    <author initials="M. B." surname="de Jong" fullname="Michiel de Jong">
      <organization>Ponder Source</organization>
      <address>
        <email>michiel@pondersource.com</email>
        <uri>https://pondersource.com</uri>
      </address>
    </author>
    <author initials="M." surname="Baghbani" fullname="Mahdi Baghbani">
      <organization>Ponder Source</organization>
      <address>
        <email>mahdi@pondersource.com</email>
        <uri>https://pondersource.com</uri>
      </address>
    </author>
    <author initials="M." surname="Nordin" fullname="Micke Nordin">
      <organization>SUNET</organization>
      <address>
        <email>kano@sunet.se</email>
        <uri>https://code.smolnet.org/micke</uri>
      </address>
    </author>
    <date year="2024" month="November" day="15"/>
    <area>Security</area>
    <keyword>Internet-Draft</keyword>
    <abstract>
      <?line 37?>

<t>Open Cloud Mesh is a server federation protocol that is used to notify a Receiving Party that they have
been granted access to some Resource. It has similarities with authorization flows such as OAuth, as well as with social internet protocols such as ActivityPub and email.</t>
      <t>Open Cloud Mesh only handles the necessary interactions up to the point where the Receiving Party is informed that they were granted access to the Resource. The actual resource access is then left to protocols such as WebDAV and others.</t>
    </abstract>
  </front>
  <middle>
    <?line 44?>

<section anchor="terms">
      <name>Terms</name>
      <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and
"OPTIONAL" in this document are to be interpreted as described in
RFC 2119.</t>
      <t>We define the following concepts (with some non-normative references to related concepts from OAuth and elsewhere):</t>
      <ul spacing="normal">
        <li>
          <t><strong>Resource</strong> - the piece of data or interaction to which access is being granted, e.g. a file, folder, video call, or printer queue</t>
        </li>
        <li>
          <t><strong>Share</strong> - a policy rule stating that certain actors are allowed access to a Resource. Also: a record in a database representing this rule</t>
        </li>
        <li>
          <t><strong>Sending Party</strong> - a person or party who is authorized to create Shares (similar to "Resource Owner" in OAuth)</t>
        </li>
        <li>
          <t><strong>Receiving Party</strong> - a person, group or party who is granted access to the Resource through the Share (similar to "Requesting Party / RqP" in OAuth-UMA)</t>
        </li>
        <li>
          <t><strong>Sending Server</strong> - the server that:
          </t>
          <ul spacing="normal">
            <li>
              <t>holds the Resource ("file server" or "Entreprise File Sync and Share (EFSS) server" role),</t>
            </li>
            <li>
              <t>provides access to it (by exposing at least one "API"),</t>
            </li>
            <li>
              <t>takes the decision to create the Share based on user interface gestures from the Sending Party (the "Authorization Server" role in OAuth)</t>
            </li>
            <li>
              <t>takes the decision about authorizing attempts to access the Resource (the "Resource Server" role in OAuth)</t>
            </li>
            <li>
              <t>sends out Share Creation Notifications when appropriate (see below)</t>
            </li>
          </ul>
        </li>
        <li>
          <t><strong>Receiving Server</strong> - the server that:
          </t>
          <ul spacing="normal">
            <li>
              <t>receives Share Creation Notifications (see below)</t>
            </li>
            <li>
              <t>actively or passively notifies the receiving user or group of any incoming Share Creation Notification</t>
            </li>
            <li>
              <t>acts as an API client, allowing the receiving user to access the Resource through an API (e.g. WebDAV) of the sending server</t>
            </li>
          </ul>
        </li>
        <li>
          <t><strong>Sending Gesture</strong> - a user interface interaction from the Sending Party to the Sending Server, conveying the intention to create a Share</t>
        </li>
        <li>
          <t><strong>Share Creation</strong> - the addition of a Share to the database state of the Sending Server, in response to a successful Sending Gesture or for another reason</t>
        </li>
        <li>
          <t><strong>Share Creation Notification</strong> - a server-to-server request from the sending server to the receiving server, notifying the receiving server that a Share has been created</t>
        </li>
        <li>
          <t><strong>FQDN</strong> - Fully Qualified Domain Name, such as <tt>"cloud.example.com"</tt></t>
        </li>
        <li>
          <t><strong>OCM Server</strong> - a server that supports OCM.</t>
        </li>
        <li>
          <t><strong>Discovering Server</strong> - a server that tries to obtain information in OCM API discovery</t>
        </li>
        <li>
          <t><strong>Discoverable Server</strong> - a server that tries to supply information in OCM API discovery</t>
        </li>
        <li>
          <t><strong>OCM Address</strong> - a string of the form <tt>&lt;Receiving Party's identifier&gt;@&lt;fqdn&gt;</tt> which can be used to uniquely identify a user or group "at" an OCM Server. <tt>&lt;Receiving Party's identifier&gt;</tt> is an opaque string,
unique at the server. <tt>&lt;fqdn&gt;</tt> is the Fully Qualified Domain Name by which the server is identified. This can, but doesn't need to be, the domain at which the OCM API of that server is hosted.</t>
        </li>
        <li>
          <t><strong>OCM Notification</strong> - a message from the Receiving Server to the Sending Server or vice versa, using the OCM Notifications endpoint.</t>
        </li>
        <li>
          <t><strong>Invite Message</strong> - out-of-band message used to establish contact between parties and servers in the Invite Flow, containing an Invite Token (see below) and the Invite Sender's OCM Address</t>
        </li>
        <li>
          <t><strong>Invite Sender</strong> - the party sending an Invite</t>
        </li>
        <li>
          <t><strong>Invite Receiver</strong> - the party receiving an Invite</t>
        </li>
        <li>
          <t><strong>Invite Sender OCM Server</strong> - the server holding an address book used by the Invite Sender, to which details of the Invite Receiver are to be added</t>
        </li>
        <li>
          <t><strong>Invite Receiver OCM Server</strong> - the server holding an address book used by the Invite Receiver, to which details of the Invite Sender are to be added</t>
        </li>
        <li>
          <t><strong>Invite Token</strong> - a hard-to-guess string used in the Invite Flow, generated by the Invite Sender OCM Server and linked uniquely to the Invite Sender's OCM Address</t>
        </li>
        <li>
          <t><strong>Invite Creation Gesture</strong> - gesture from the Invite Sender to the Invite Sender OCM Server, resulting in the creation of an Invite Token.</t>
        </li>
        <li>
          <t><strong>Invite Acceptance Gesture</strong> - gesture from the Invite Receiver to the Invite Receiver OCM Server, supplying the Invite Token as well as the OCM Address of the Invite Sender, effectively allowlisting the Invite Sender OCM Server for sending Share Creation Notifications to the Invite Receiver OCM Server.</t>
        </li>
        <li>
          <t><strong>Invite Acceptance Request</strong> - API call from the Invite Receiver OCM Server to the Invite Sender OCM Server, supplying the Invite Token as well as the OCM Address of the Invite Receiver, effectively allowlisting the Invite Sender OCM Server for sending Share Creation Notifications to the Invite Receiver OCM Server.</t>
        </li>
        <li>
          <t><strong>Invite Acceptance Response</strong> - HTTP response to the Invite Acceptance Request</t>
        </li>
        <li>
          <t><strong>Share Name</strong> - a human-readable string, provided by the Sending Party or the Sending Server, to help the Receiving Party understand which Resource the Share grants access to</t>
        </li>
        <li>
          <t><strong>Share Permissions</strong> - protocol-specific allowances granted to the Receiving Party on the modes of accessing the Resource</t>
        </li>
        <li>
          <t><strong>Share Requirements</strong> - protocol-specific restrictions on the modes of accessing the Resource</t>
        </li>
      </ul>
    </section>
    <section anchor="general-flow">
      <name>General Flow</name>
      <t>The lifecycle of an Open Cloud Mesh Share starts with prerequisites such as
establishing trust, establishing contact, and OCM API discovery.</t>
      <t>Then the share creation involves the Sending Party making a Sending Gesture to the Sending Server,
the Sending Server carrying out the actual Share Creation,
and the Sending Server sending a Share Creation Notification to the Receiving Server.</t>
      <t>After this, the Receiving Server MAY notify the Receiving Party and/or the Sending Server, and will act as an API client
through which the Receiving Party can access the Resource. After that, the Share may be updated, deleted, and/or reshared.</t>
    </section>
    <section anchor="establishing-contact">
      <name>Establishing Contact</name>
      <t>Before the Sending Server can send a Share Creation Notification to the Receiving Server, it needs to establish the Receiving Party's OCM Address (containing the Receiving Server's FQDN, and the Receiving Party's identifier), among other things.
Some steps may preceed the Sending Gesture, allowing the Sending Party to establish (with some level of trust) the OCM Address of the Receiving Party. In other cases, establishing the OCM Address
of the Receiving Party happens as part of the Sending Gesture.</t>
      <section anchor="direct-entry">
        <name>Direct Entry</name>
        <t>The simplest way for this is if the Receiving Party shares their OCM Address with the Sending Party through some out-of-band means, and the Sending Party enters this string into the user interface of the Sending Server, by means of typing or pasting into an HTML form, or clicking a link to a URL that includes the string in some form.</t>
      </section>
      <section anchor="address-books">
        <name>Address books</name>
        <t>The Sending Server MAY offer the Sending Party an address book tool, where OCM Addresses can be stored over time in a labeled and/or searchable way. This decouples the act by which the OCM Address string is passed into the Sending Server's database from the selection of the Receiving Party in preparation for Share Creation.</t>
      </section>
      <section anchor="public-link-flow">
        <name>Public Link Flow</name>
        <t>An interface for anonymously viewing a Resource on the Sending Server MAY allow any internet user to type or paste an OCM address into an HTML form, as a Sending Gesture. This means that the Sending Party and the Receiving Party could be the same person, so contact between them does not need to be explicitly established.</t>
      </section>
      <section anchor="public-invite-flow">
        <name>Public Invite Flow</name>
        <t>Similarly, an interface on the Sending Server MAY allow any internet user to type or paste an OCM address into an HTML form, as a Sending Gesture for a given Resource, without itself providing a way to access that particular Resource. A link to this interface could then for instance be shared on a mailing list, allowing all subscribers to effectively request access to the Resource by making a Sending Gesture to the Sending Server with their own OCM Address.</t>
      </section>
      <section anchor="invite-flow">
        <name>Invite Flow</name>
        <t>### Rationale
Many methods for establishing contact allow unsolicited contact with the prospective Receiving Party whenever that party's OCM Address is known. The Invite Flow requires the Receiving Party to explicitly accept it before it can be used, which establishes bidirectional trust between the two parties involved.</t>
        <t>OCM Servers MAY enforce a policy to only accept Shares between such trusted contacts, or MAY display a warning to the Receiving Party when a Share Creation Notification from an unknown Sending Party is received</t>
        <section anchor="steps">
          <name>Steps</name>
          <ul spacing="normal">
            <li>
              <t>the Invite Sender OCM Server generates a unique Invite Token and helps the Invite Sender to create the Invite Message</t>
            </li>
            <li>
              <t>the Invite Sender uses some out-of-band communication to send the Invite Message, containing the Invite Token and the Invite Sender OCM Server FQDN, to the Invite Receiver</t>
            </li>
            <li>
              <t>the Invite Receiver navigates to the Invite Receiver OCM Server (possibly using a Where-Are-You-From page provided as part of the Invite Message) and makes the Invite Acceptance Gesture</t>
            </li>
            <li>
              <t>the Invite Receiver OCM Server discovers the OCM API of the Invite Sender OCM Server using generic OCM API Discovery (see section below)</t>
            </li>
            <li>
              <t>the Invite Receiver OCM Server sends the Invite Acceptance Request to the Invite Sender OCM Server</t>
            </li>
          </ul>
        </section>
        <section anchor="invite-acceptance-request-details">
          <name>Invite Acceptance Request Details</name>
          <t>Whereas the precise syntax of the Invite Message and the Invite Acceptance Gesture will differ between implementations, the Invite Acceptance Request SHOULD be a HTTP POST request:</t>
          <ul spacing="normal">
            <li>
              <t>to the <tt>/invited-accepted</tt> path in the Invite Sender OCM Server's OCM API</t>
            </li>
            <li>
              <t>using <tt>application/json</tt> as the <tt>Content-Type</tt> HTTP request header</t>
            </li>
            <li>
              <t>its request body containing a JSON document representing an object with the following string fields:
              </t>
              <ul spacing="normal">
                <li>
                  <t>REQUIRED: <tt>recipientProvider</tt> - FQDN of the Invite Receiver OCM Server</t>
                </li>
                <li>
                  <t>REQUIRED: <tt>token</tt> - the Invite Token. The Invite Sender OCM Server SHOULD recall which Invite Sender OCM Address this token was linked to</t>
                </li>
                <li>
                  <t>REQUIRED: <tt>userID</tt> - the Invite Receiver's identifier at their OCM Server</t>
                </li>
                <li>
                  <t>REQUIRED: <tt>email</tt> - non-normative / informational; an email address for the Invite Receiver. Not necessarily at the same FQDN as their OCM Server</t>
                </li>
                <li>
                  <t>REQUIRED: <tt>name</tt> - human-readable name of the Invite Receiver, as a suggestion for display in the Invite Sender's address book</t>
                </li>
              </ul>
            </li>
            <li>
              <t>using TLS</t>
            </li>
            <li>
              <t>using <eref target="https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12">httpsig</eref></t>
            </li>
          </ul>
          <t>The Invite Receiver OCM Server SHOULD apply its own policies for trusting the Invite Sender OCM Server before making the Invite Acceptance Request.</t>
          <t>Since the Invite Flow does not require either Party to type or remember the <tt>userID</tt>, this string does not need to be human-memorable. Even if the Invite Receiver has a memorable username at the Invite Receiver OCM Server, this <tt>userID</tt> that forms part of their OCM Address does not need to match it.</t>
          <t>Also, a different <tt>userID</tt> could be given out to each contact, to avoid correlation of identities.</t>
        </section>
        <section anchor="invite-acceptance-response-details">
          <name>Invite Acceptance Response Details</name>
          <t>The Invite Acceptance Response SHOULD be a HTTP response:</t>
          <ul spacing="normal">
            <li>
              <t>in response to the Invite Acceptance Request</t>
            </li>
            <li>
              <t>using <tt>application/json</tt> as the <tt>Content-Type</tt> HTTP response header</t>
            </li>
            <li>
              <t>its response body containing a JSON document representing an object with the following string fields:
              </t>
              <ul spacing="normal">
                <li>
                  <t>REQUIRED: <tt>userID</tt> - the Invite Sender's identifier at their OCM Server</t>
                </li>
                <li>
                  <t>REQUIRED: <tt>email</tt> - non-normative / informational; an email address for the Invite Sender. Not necessarily at the same FQDN as their OCM Server</t>
                </li>
                <li>
                  <t>REQUIRED: <tt>name</tt> - human-readable name of the Invite Sender, as a suggestion for display in the Invite Receiver's address book</t>
                </li>
              </ul>
            </li>
          </ul>
          <t>A 200 response status means the Invite Acceptance Request was successful.
A 400 response status means the Invite Token is invalid or does not exist.
A 403 response status means the Invite Receiver OCM Server is not trusted to accept this Invite.
A 409 response status means the Invite was already accepted.</t>
          <t>The Invite Sender OCM Server SHOULD verify the HTTP Signature on the Invite Acceptance Request and apply its own policies for trusting the Invite Receiver OCM Server before processing the Invite Acceptance Request and sending the Invite Acceptance Response.</t>
          <t>As with the <tt>userID</tt> in the Invite Acceptance Request, the one in the Response also doesn't need to be human-memorable, doesn't need to match the Invite Sender's username at their OCM Server.</t>
        </section>
        <section anchor="addition-into-address-books">
          <name>Addition into address books</name>
          <t>Following these step, both servers MAY display the <tt>name</tt> of the other party as a trusted or allowlisted contact, and enable selecting them as a Receiving Party. OCM Servers MAY enforce a policy to only accept Share Creation Notifications from such trusted contacts, or MAY display a warning to users when a Share Creation Notification from an unknown party is received.</t>
          <t>Both servers MAY also allowlist each other as a server with which at least one of their users wishes to interact.</t>
          <t>Note that Invites act symmetrically, so once contact has been established, both the Invite Sender and the Invite Receiver may take on either the Sending Party or the Receiving Party role in subsequent Share Creation events.</t>
          <t>Both parties may delete the other party from their address book at any time without notifying them.</t>
        </section>
        <section anchor="security-advantages">
          <name>Security Advantages</name>
          <t>It is important to underscore the value of the Invite in this scenario, as it provides four important security advantages. First of all, if the Receiving Server blocks Share Creation Notifications from Sending Parties who are not in the address book of the Receiving Party, then this protects the Receiving Party from receiving unsolicited Shares. An attacker could still send the Receiving Party an unsolicited Share, but they would first need to convince the Receiving Party through an out-of-band communication channel to accept their invite. In many use cases, the Receiving Party has had other forms of contact with the Sending Party (e.g. in-person or email back-and-forth). The out-of-band Invite Message thus leverages the filters and context which the Receiving Party may already benefit from in that out-of-band communication. For instance, a careful Receiving Party may choose to only accept Invites that reach them via a private or moderated messaging platform.</t>
          <t>Second, when the Receiving Party accepts the Invite, the Receiving Server knows that the Sending Server they are about to interact with is trusted by the Sending Party, which in turn is trusted by the Receiving Party, which in turn is trusted by them. In other words, one of their users is requesting the allowlisting of a server they wish to interact with, in order to interact with a party they know out-of-band. This gives the Receiving Server reason to put more trust in the Sending Server than it would put into an arbitrary internet-hosted server.</t>
          <t>Third, equivalently, the Sending Server knows it is essentially registering the Receiving Server as an API client at the request of the Receiving Party, to whom the right to request this has been traceably delegated by the Sending Party, which is one of its registered users.</t>
          <t>Fourth, related to the second one, it removes the partial 'open relay' problem that exists when the Sending Server is allowed to include any Receiving Server FQDN in the Sending Gesture. Without the use of Invites, a Distributed Denial of Service attack could be organised if many internet users collude to flood a given OCM Server with Share Creation Notifications which will be hard to distinguish from legitimate requests without human interaction. An unsolicited (invalid) Invite Acceptance Request is much easier to filter out than an unsolicited (possibly valid, possibly invalid) Share Creation Notification Request, since the Invite Acceptance Request needs to contain an Invite Token that was previously uniquely generated at the Invite Sender OCM server.</t>
        </section>
      </section>
    </section>
    <section anchor="ocm-api-discovery">
      <name>OCM API Discovery</name>
      <t>## Introduction
After establishing contact as discussed in the previous section, the Sharing User can send the Share Creation Gesture to the Sending Server, providing the Sending Server with the following information:</t>
      <ul spacing="normal">
        <li>
          <t>Resource to be shared</t>
        </li>
        <li>
          <t>Protocol to be offered for access</t>
        </li>
        <li>
          <t>Sending Party's identifier</t>
        </li>
        <li>
          <t>Receiving Party's identifier</t>
        </li>
        <li>
          <t>Receiving Server FQDN</t>
        </li>
        <li>
          <t>OPTIONAL: Share Requirements</t>
        </li>
        <li>
          <t>OPTIONAL: Share Name</t>
        </li>
        <li>
          <t>OPTIONAL: Share Permissions</t>
        </li>
      </ul>
      <t>The next step is for the Sending Server to additionally discover:</t>
      <ul spacing="normal">
        <li>
          <t>if the Receiving Server is trusted</t>
        </li>
        <li>
          <t>if the Receiving Server supports OCM</t>
        </li>
        <li>
          <t>if so, which version and with which optional functionality</t>
        </li>
        <li>
          <t>at which URL</t>
        </li>
        <li>
          <t>the public key the Receiving Server will use for HTTP Signatures (if any)</t>
        </li>
      </ul>
      <t>The Sending Server MAY first perform denylist and allowlist checks on the FQDN.</t>
      <t>If a finite allowlist of Receiving Servers exists on the Sending Server side, then this list may already contain all necessary information.</t>
      <t>If the FQDN passes the denylist and/or allowlist checks, but no details about its OCM API are known, the Sending Server can use the following process to try to fetch this information from the Receiving Server.</t>
      <t>This process MAY be influenced by a VPN connection and/or IP allowlisting.</t>
      <t>When OCM API discovery can occur in preparation of a Share Creation Notification, the Sending Server takes on the 'Discovering Server' role and the Receiving Server plays the role of 'Discoverable Server'.</t>
      <section anchor="process">
        <name>Process</name>
        <t>At the start of the process, the Discovering Server has either an OCM Address, or just an FQDN from for instance the <tt>recipientProvider</tt> field of an Invite Acceptance Request.</t>
        <t>Step 1: In case it has an OCM Address, it should first extract <tt>&lt;fqdn&gt;</tt> from it (the part after the <tt>@</tt> sign).
Step 2: The Discovering Server SHOULD attempt OCM API discovery a HTTP GET request to <tt>https://&lt;fqdn&gt;/.well-known/ocm</tt>.
Step 3: If that results in a valid HTTP response with a valid JSON response body within reasonable time, go to step 8.
Step 4: If not, try a HTTP GET with <tt>https://&lt;fqdn&gt;/ocm-provider</tt> as the URL instead.
Step 5: If that results in a valid HTTP response with a valid JSON response body within reasonable time, go to step 8.
Step 6: If not, fail.
Step 7: The JSON response body is the data that was discovered.</t>
      </section>
      <section anchor="fields">
        <name>Fields</name>
        <t>The JSON response body offered by the Discoverable Server SHOULD contain the following information about its OCM API:</t>
        <ul spacing="normal">
          <li>
            <t>REQUIRED: enabled (boolean) - Whether the OCM service is enabled at this endpoint</t>
          </li>
          <li>
            <t>REQUIRED: apiVersion (string) - The OCM API version this endpoint supports. Example: <tt>"1.1.0"</tt></t>
          </li>
          <li>
            <t>REQUIRED: endPoint (string) - The URI of the OCM API available at this endpoint. Example: <tt>"https://my-cloud-storage.org/ocm"</tt></t>
          </li>
          <li>
            <t>OPTIONAL: provider (string) - A friendly branding name of this endpoint. Example: <tt>"MyCloudStorage"</tt></t>
          </li>
          <li>
            <t>REQUIRED: resourceTypes (array) - A list of all resource types this server supports in both the Sending Server role and the Receiving Server role, with their access protocols. Each item in this list should
itself be an object containing the following fields:
            </t>
            <ul spacing="normal">
              <li>
                <t>name (string) -  A supported resource type (file, folder, calendar, contact, ...).
            Implementations MUST support <tt>file</tt> at a minimum. Each resource type is identified by its <tt>name</tt>: the list MUST NOT
      contain more than one resource type object per given <tt>name</tt>.</t>
              </li>
              <li>
                <t>shareTypes (array of string) -
            The supported recipient share types.
            MUST contain <tt>"user"</tt> at a minimum, plus optionally <tt>"group"</tt> and <tt>"federation"</tt>.
            Example: <tt>["user"]</tt></t>
              </li>
              <li>
                <t>protocols (object) - The supported protocols for accessing shared resources of this type.
            Implementations MUST support at least <tt>webdav</tt> for <tt>file</tt> resources,
            any other combination of resources and protocols is optional. Example:
            <tt>json
            {
              "webdav": "/remote/dav/ocm/",
              "webapp": "/app/ocm/",
              "talk": "/apps/spreed/api/"
            }
                  </tt>
            Fields:
                </t>
                <ul spacing="normal">
                  <li>
                    <t>webdav (string) - The top-level WebDAV path at this endpoint. In order to access
              a remote shared resource, implementations MAY use this path
              as a prefix, or as the full path (see sharing examples).</t>
                  </li>
                  <li>
                    <t>webapp (string) - The top-level path for web apps at this endpoint. This value
              is provided for documentation purposes, and it SHALL NOT
              be intended as a prefix for share requests.</t>
                  </li>
                  <li>
                    <t>datatx (string) - The top-level path to be used for data transfers. This
              value is provided for documentation purposes, and it SHALL
              NOT be intended as a prefix. In addition, implementations
              are expected to execute the transfer using WebDAV as
              the wire protocol.</t>
                  </li>
                  <li>
                    <t>Any additional protocol supported for this resource type MAY
              be advertised here, where the value MAY correspond to a top-level
              URI to be used for that protocol.</t>
                  </li>
                </ul>
              </li>
            </ul>
          </li>
          <li>
            <t>OPTIONAL: capabilities (array of string) - The optional capabilities supported by this OCM Server.
        As implementations MUST accept Share Creation Notifications to be compliant,
        it is not necessary to expose that as a capability.
        Example: <tt>["receive-code", "webdav-uri"]</tt>. The array MAY include for instance:
            </t>
            <ul spacing="normal">
              <li>
                <t><tt>"enforce-mfa"</tt> - to indicate that this OCM server can apply a Sending Server's MFA requirements for a Share on their behalf.</t>
              </li>
              <li>
                <t><tt>"webdav-uri"</tt> - to indicate that this OCM server can append a relative URI to the path listed for WebDAV in the appropriate <tt>resourceTypes</tt> entry</t>
              </li>
              <li>
                <t><tt>"protocol-object"</tt> - to indicate that this OCM server can receive a Share Creation Notification whose <tt>protocol</tt> object contains one property per supported protocol instead of containing the standard <tt>name</tt> and <tt>options</tt> properties.</t>
              </li>
              <li>
                <t><tt>"invites"</tt> - to indicate the server would support acting as an Invite Sender or Invite Receiver OCM Server. This might be useful for suggesting to a user that existing contacts might be upgraded to the more secure (and possibly required) invite flow.</t>
              </li>
              <li>
                <t><tt>"receive-code"</tt> - to indicate that this OCM server can receive a <tt>code</tt> as part of a Share Creation Notification, and exchange it for a bearer token at the Sending Server's <tt>/token</tt> API endpoint.</t>
              </li>
            </ul>
          </li>
          <li>
            <t>OPTIONAL: criteria (array of string) - The criteria for accepting a Share Creation Notification.
        As all Receiving Servers should require the use of TLS in API calls,
        it is not necessary to expose that as a criterium.
        Example: <tt>["http-request-signatures", "code"]</tt>. The array MAY include for instance:
            </t>
            <ul spacing="normal">
              <li>
                <t><tt>"http-request-signatures"</tt> - to indicate that API requests without http signatures will be rejected.</t>
              </li>
              <li>
                <t><tt>"code"</tt> - to indicate that API requests without code will be rejected (i.e. the <tt>sharedSecret</tt> in the protocol details will be ignored).</t>
              </li>
              <li>
                <t><tt>"denylist"</tt> - some servers may be blocked based on their IP address</t>
              </li>
              <li>
                <t><tt>"allowlist"</tt> - unknown servers may be blocked based on their IP address</t>
              </li>
              <li>
                <t><tt>"invite"</tt> - an invite must have been exchanged between the sender and the receiver before a Share Creation Notification can be sent</t>
              </li>
            </ul>
          </li>
          <li>
            <t>OPTIONAL: publicKey (object) - The signatory used to sign outgoing request to confirm its origin. The 
        signatory is optional, but if present, it MUST contain two string fields, <tt>id</tt> and <tt>publicKeyPem</tt>.
      properties:
            </t>
            <ul spacing="normal">
              <li>
                <t>REQUIRED id (string) unique id of the key in URI format. The hostname set the origin of the 
          request and MUST be identical to the current discovery endpoint.
        Example: https://my-cloud-storage.org/ocm#signature</t>
              </li>
              <li>
                <t>REQUIRED publicKeyPem (string) - PEM-encoded version of the public key.
        Example: "-----BEGIN PUBLIC KEY-----\nMII...QDD\n-----END PUBLIC KEY-----\n"</t>
              </li>
            </ul>
          </li>
        </ul>
      </section>
    </section>
    <section anchor="share-creation-notification">
      <name>Share Creation Notification</name>
      <t>To create a share, the sending server SHOULD make a HTTP POST request</t>
      <ul spacing="normal">
        <li>
          <t>to the <tt>/shares</tt> path in the Receiving Server's OCM API</t>
        </li>
        <li>
          <t>using <tt>application/json</tt> as the <tt>Content-Type</tt> HTTP request header</t>
        </li>
        <li>
          <t>its request body containing a JSON document representing an object with the fields as described below</t>
        </li>
        <li>
          <t>using TLS</t>
        </li>
        <li>
          <t>using <eref target="https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12">httpsig</eref></t>
        </li>
      </ul>
      <section anchor="fields-1">
        <name>Fields</name>
        <ul spacing="normal">
          <li>
            <t>REQUIRED shareWith (string)
        Consumer specific identifier of the user, group or federation the provider
        wants to share the resource with. This is known in advance.
        Please note that the consumer service endpoint is known in advance
        as well, so this is no part of the request body.
      Example: "51dc30ddc473d43a6011e9ebba6ca770@geant.org"</t>
          </li>
          <li>
            <t>REQUIRED name (string)
     Name of the resource (file or folder).
      Example: "resource.txt"</t>
          </li>
          <li>
            <t>OPTIONAL description (string)
      Optional description of the resource (file or folder).
      Example: "This is the Open API Specification file (in YAML format) of the Open
        Cloud Mesh API."</t>
          </li>
          <li>
            <t>REQUIRED providerId (string)
        Identifier to identify the shared resource at the provider side. This is
        unique per provider such that if the same resource is shared twice,
        this providerId will not be repeated.
      Example: 7c084226-d9a1-11e6-bf26-cec0c932ce01</t>
          </li>
          <li>
            <t>REQUIRED owner (string) -
        Provider specific identifier of the user who owns the resource.
      Example: "6358b71804dfa8ab069cf05ed1b0ed2a@apiwise.nl"</t>
          </li>
          <li>
            <t>REQUIRED sender (string) -
        Provider specific identifier of the user that wants to share the
        resource. Please note that the requesting provider is being
        identified on a higher level, so the former <tt>remote</tt> property
        is not part of the request body.
      Example: "527bd5b5d689e2c32ae974c6229ff785@apiwise.nl"</t>
          </li>
          <li>
            <t>OPTIONAL ownerDisplayName (string)
        Display name of the owner of the resource
      Example: "Dimitri"</t>
          </li>
          <li>
            <t>OPTIONAL senderDisplayName (string)
        Display name of the user that wants to share the resource
      Example: "John Doe"</t>
          </li>
          <li>
            <t>REQUIRED shareType (string)
      SHOULD have a value of "user", "group", or "federation", to indicated that the first part
      of the <tt>shareWith</tt> OCM Address refers to a Receiving Party who is a single user of the Receiving Server,
      a group of users at the Receiving Servers, or a group of users that is spread out over various servers,
      including at least one user at the Receiving Server.</t>
          </li>
          <li>
            <t>REQUIRED resourceType (string)
        Resource type (file, folder, calendar, contact, ...)</t>
          </li>
          <li>
            <t>OPTIONAL expiration (integer)
        The expiration time for the OCM share, in seconds
        of UTC time since Unix epoch. If omitted, it is assumed
        that the share does not expire.</t>
          </li>
          <li>
            <t>OPTIONAL code (string)
        A nonce to be exchanged for a (potentially short-lived) bearer token at the Sending Server's /token endpoint.</t>
          </li>
          <li>
            <t>REQUIRED protocol (object)
        JSON object with specific options for each protocol.
        The supported protocols are:
        - <tt>webdav</tt>, to access the data
        - <tt>webapp</tt>, to access remote web applications
        - <tt>datatx</tt>, to transfer the data to the remote endpoint  </t>
            <artwork><![CDATA[
    Other custom protocols might be added in the future.

    In case a single protocol is offered, there are three ways to specify this object:
    Option 1: Set the `name` field to the name of the protocol, and put the protocol
    details in a field named `options`.
    Option 2: Set the `name` field to the name of the protocol, and put the protocol
    details in a field carrying the name of the protocol.
    Option 3: Set the `name` field to `multi`, and put the protocol
    details in a field carrying the name of the protocol.

          Option 1 using the `options` field now deprecated. Implementations are encouraged to
          transition to the new optional properties defined below, such that
          this field may be removed in a future major version of the spec.

    When specifying more than one protocol as different ways to access the Share, the `name`
    field needs to be set to `multi`.
]]></artwork>
          </li>
        </ul>
        <t>If <tt>multi</tt> is given, one or more protocol
                endpoints are expected to be defined according to the optional
                properties specified below.
                Otherwise, at least <tt>webdav</tt> is expected to be supported, and
                its options MAY be given in the opaque <tt>options</tt> payload for
                compatibility with v1.0 implementations (see examples). Note
                though that this format is deprecated.
                Warning: client implementers should be aware that v1.1 servers
                MAY support both <tt>webdav</tt> and <tt>multi</tt>, but v1.0 servers MAY
                only support <tt>webdav</tt>.</t>
        <ul spacing="normal">
          <li>
            <t>Protocol details for <tt>webdav</tt> MAY contain:
            </t>
            <ul spacing="normal">
              <li>
                <t>OPTIONAL sharedSecret (string) - required if no <tt>code</tt> field is given for the Share as a whole (see above).
             An optional secret to be used to access the resource,
             such as a bearer token.
             To prevent leaking it in logs it MUST NOT appear in any URI.</t>
              </li>
              <li>
                <t>OPTIONAL permissions (array of strings) -
               The permissions granted to the sharee. A subset of:
               - <tt>read</tt> allows read-only access including download of a copy.
               - <tt>write</tt> allows create, update, and delete rights on the resource.
               - <tt>share</tt> allows re-share rights on the resource.</t>
              </li>
              <li>
                <t>OPTIONAL requirements (array of strings) -
               The requirements that the sharee MUST fulfill to access the resource. A subset of:
               - <tt>mfa-enforced</tt> requires the consumer to be MFA-authenticated. This
                 MAY be used if the recipient provider exposes the <tt>enforce-mfa</tt> capability.
               - <tt>use-code</tt> requires the consumer to exchange the given <tt>code</tt> via a
                 signed HTTPS request. This MAY be used if the recipient provider exposes
                 the <tt>receive-code</tt> capability.</t>
              </li>
              <li>
                <t>OPTIONAL uri (string)
             An URI to access the remote resource. The URI MAY be relative,
             in which case the prefix exposed by the <tt>/ocm-provider</tt> endpoint MUST
             be used, or it may be absolute (recommended). Additionally, the URI
             MAY include a secret hash in the path, in which case there MAY be
             no associated <tt>sharedSecret</tt>.</t>
              </li>
            </ul>
          </li>
          <li>
            <t>Protocol details for <tt>webapp</tt> MAY contain:
            </t>
            <ul spacing="normal">
              <li>
                <t>REQUIRED uriTemplate (string)
             A templated URI to a client-browsable view of the shared resource,
             such that users may use the web applications available at the site.
             The URI MAY include a secret hash in the path. If the path includes
             a <tt>{relative-path-to-shared-resource}</tt> placeholder, implementations
             MAY replace it with the actual path to ease user interaction.</t>
              </li>
              <li>
                <t>REQUIRED viewMode (string)
             The permissions granted to the sharee. A subset of:
             - <tt>view</tt> allows access to the web app in view-only mode.
             - <tt>read</tt> allows read and download access via the web app.
             - <tt>write</tt> allows full editing rights via the web app.</t>
              </li>
              <li>
                <t>OPTIONAL sharedSecret (string)
             An optional secret to be used to access the remote web app,
             for example in the form of a bearer token.</t>
              </li>
            </ul>
          </li>
          <li>
            <t>Protocol details for <tt>datatx</tt> MAY contain:
            </t>
            <ul spacing="normal">
              <li>
                <t>OPTIONAL sharedSecret (string)
             An optional secret to be used to access the resource,
             for example in the form of a bearer token.
             To prevent leaking it in logs it MUST NOT appear in any URI.</t>
              </li>
              <li>
                <t>REQUIRED srcUri (string)
             An URI to access the remote resource. The URI MAY be relative,
             in which case the prefix exposed by the <tt>/ocm-provider</tt> endpoint MUST
             be used, or it may be absolute (recommended). Additionally, the
             URI MAY include a secret hash in the path.</t>
              </li>
              <li>
                <t>OPTIONAL size (integer)</t>
              </li>
            </ul>
          </li>
        </ul>
      </section>
      <section anchor="decision-to-discard">
        <name>Decision to Discard</name>
        <t>The Receiving Server MAY discard the notification if any of the following hold true:</t>
        <ul spacing="normal">
          <li>
            <t>the HTTP Signature is missing</t>
          </li>
          <li>
            <t>the HTTP Signature is not valid</t>
          </li>
          <li>
            <t>no keypair is trusted or discoverable from the FQDN part of the <tt>sender</tt> field in the request body</t>
          </li>
          <li>
            <t>the keypair used to generate the HTTP Signature doesn't match the one trusted or discoverable from the FQDN part of the <tt>sender</tt> field in the request body</t>
          </li>
          <li>
            <t>the Sending Server is denylisted</t>
          </li>
          <li>
            <t>the Sending Server is not allowlisted</t>
          </li>
          <li>
            <t>the Sending Party is not trusted by the Receiving Party (e.g. no Invite was exchanged and/or the Sending Party's OCM Address does not appear in the Receiving Party's address book)</t>
          </li>
          <li>
            <t>the Receiving Server is unable to act as an API client for (any of) the protocol(s) listed for accessing the resource</t>
          </li>
          <li>
            <t>an initial check shows that the resource cannot successfully accessed through (any of) the protocol(s) listed</t>
          </li>
        </ul>
      </section>
    </section>
    <section anchor="receiving-party-notification">
      <name>Receiving Party Notification</name>
      <t>If the Share Creation Notification is not discarded by the Receiving Server, they MAY notify the Receiving Party passively by adding the Share to some inbox list, and MAY also notify them actively through for instance a push notification or an email message.</t>
      <t>They could give the Receiving Party the option to accept or reject the share, or add the share automatically and only send an informational notification that this happened.</t>
    </section>
    <section anchor="share-acceptance-notification">
      <name>Share Acceptance Notification</name>
      <t>In response to a Share Creation Notification, the Receiving Server MAY discover the OCM API of the Sending Server,
starting from the <tt>&lt;fqdn&gt;</tt> part of the <tt>sender</tt> field in the Share Creation Notification.</t>
      <t>If the OCM API of the Sending Server is successfully discovered, the Receiving Server MAY
make a HTTP POST request</t>
      <ul spacing="normal">
        <li>
          <t>to the <tt>/notifications</tt> path in the Sending Server's OCM API</t>
        </li>
        <li>
          <t>using <tt>application/json</tt> as the <tt>Content-Type</tt> HTTP request header</t>
        </li>
        <li>
          <t>its request body containing a JSON document representing an object with the fields as described below</t>
        </li>
        <li>
          <t>using TLS</t>
        </li>
        <li>
          <t>using <eref target="https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12">httpsig</eref></t>
        </li>
      </ul>
      <section anchor="fields-2">
        <name>Fields</name>
        <ul spacing="normal">
          <li>
            <t>REQUIRED notificationType (string) - in a Share Acceptance Notification it SHOULD be one of:
            </t>
            <ul spacing="normal">
              <li>
                <t>'SHARE_ACCEPTED'</t>
              </li>
              <li>
                <t>'SHARE_DECLINED'</t>
              </li>
            </ul>
          </li>
          <li>
            <t>REQUIRED providerId (string) - copied from the Share Creation Notification for the Share this notification is about</t>
          </li>
          <li>
            <t>OPTIONAL resourceType (string) - copied from the Share Creation Notification for the Share this notification is about</t>
          </li>
          <li>
            <t>OPTIONAL notification (object) - optional additional parameters, depending on the notification and the resource type</t>
          </li>
        </ul>
        <section anchor="receiving-party-notification-1">
          <name>Receiving Party Notification</name>
          <t>If the Share Creation Notification is not discarded by the Receiving Server, they MAY notify the Receiving Party passively by adding the Share to some inbox list, and MAY also notify them actively through for instance a push notification or an email message.</t>
          <t>They could give the Receiving Party the option to accept or reject the Share, or add the Share automatically and only send an informational notification that this happened.</t>
        </section>
      </section>
    </section>
    <section anchor="resource-access">
      <name>Resource Access</name>
      <t>To access the Resource, the Receiving Server MAY use multiple ways, depending on the body of the Share Creation Notification. The procedure is as follows:
1. A root path <tt>&lt;sender-ocm-path&gt;</tt> MUST be obtained by querying the <xref target="ocm-api-discovery">Discovery</xref> endpoint at the Sending Server and getting <tt>resourceTypes[0].protocols.webdav</tt>.
2. If <tt>code</tt> is not empty, the receiver SHOULD make a signed POST request to the <tt>/token</tt> path inside the Sending Server's OCM API, to exchange the code for a short-lived bearer token, and then use that bearer token to access the Resource.
3. If <tt>protocol.name</tt> = <tt>webdav</tt>, the receiver SHOULD inspect the <tt>protocol.options</tt> property. If it contains a <tt>sharedSecret</tt>, as in the <eref target="https://cs3org.github.io/OCM-API/docs.html?branch=develop&amp;repo=OCM-API&amp;user=cs3org#/paths/~1shares/post">legacy example</eref>, then the receiver SHOULD make a HTTP PROPFIND request to <tt>https://&lt;sharedSecret&gt;:@&lt;sender-host&gt;&lt;sender-ocm-path&gt;</tt>. Note that this access method, based on Basic Auth, is <em>deprecated</em> and may be removed in a future release of the Protocol.
4. Otherwise, if <tt>protocol.name</tt> = <tt>multi</tt>, the receiver MUST inspect the <tt>protocol.webdav.uri</tt> property: if it's a complete URI, the receiver MUST make a HTTP PROPFIND request against it to access the remote resource. If it only contains an identifier <tt>&lt;key&gt;</tt>, the receiver MUST make a HTTP PROPFIND request to <tt>https://&lt;sender-host&gt;&lt;sender-ocm-path&gt;/&lt;key&gt;</tt> in order to access the remote resource. Additionally, the receiver MUST pass an <tt>Authorization: bearer</tt> header with either the short-lived bearer token obtained in step 2, if applicable, or the <tt>protocol.webdav.sharedSecret</tt> value.</t>
      <t>In all cases, in case the Shared Resource is a folder and the Receiving Server accesses a resource within that shared folder, it SHOULD append its relative path to that URL. In other words, the Sending Server SHOULD support requests to URLs such as <tt>https://&lt;sender-host&gt;&lt;sender-ocm-path&gt;/path/to/resource.txt</tt>.</t>
      <t>Additionally, if <tt>protocol.&lt;protocolname&gt;.requirements</tt> includes <tt>mfa-enforced</tt>, the Receiving Server MUST ensure that the Receiving Party has been authenticated with MFA, or prompt the consmer in order to elevate their session, if applicable.</t>
    </section>
    <section anchor="share-deletion">
      <name>Share Deletion</name>
      <t>A <tt>"SHARE_ACCEPTED"</tt> notification followed by a <tt>"SHARE_UNSHARED"</tt> notification is
equivalent to a <tt>"SHARE_DECLINED"</tt> notification.</t>
      <t>Note that the Sending Server MAY at any time revoke access to a Resource (effectively undoing or deleting the Share) without notifying the Receiving Server.</t>
    </section>
    <section anchor="share-updating">
      <name>Share Updating</name>
      <t>Some implementations have experimented with a <tt>"RESHARE_CHANGE_PERMISSION"</tt>notification, but the payload and side effects such a notification may have are out of scope of this version of this specification.
The Receiving Party sending such a notification has no way of knowing if the Sending Party understood and processed the reshare request or not.</t>
    </section>
    <section anchor="resharing">
      <name>Resharing</name>
      <t>The <tt>"REQUEST_RESHARE"</tt> and <tt>"RESHARE_UNDO"</tt> notification types MAY be used by the
Receiving Server to persuade the Sending Server to share the same Resource with another Receiving Party.
The details of the payload and side effects such a notification may have are out of scope of this version of this specification.
Note that the Receiving Party sending such a notification has no way of knowing if the Sending Party understood and processed the reshare request or not.</t>
    </section>
    <section anchor="appendix-a-multi-factor-authentication">
      <name>Appendix A: Multi Factor Authentication</name>
      <t>If a Receiving Server exposes the capability <tt>enforce-mfa</tt>, it indicates that it will try and comply with a MFA requirement set on a Share. If the Sending Server trusts the Receiving Server, the Sending Server MAY set the requirement <tt>mfa-enforced</tt> on a Share, which the Receiving Server MUST honor. A compliant Receiving Server that signals that it is MFA-capable MUST not allow access to a resource protected with the <tt>mfa-enforced</tt> requirement, if the Receiving Party has not provided a second factor to establish their identity with greater confidence.</t>
      <t>Since there is no way to guarantee that the Receiving Server will actually enforce the MFA requirement, it is up to the Sending Server to establish a trust with the Receiving Server such that it is reasonable to assume that the Receiving Server will honor the MFA requirement. This establishment of trust will inevitably be implementation dependent, and can be done for example using a pre approved allow list of trusted Receiving Servers. The procedure of establishing trust is out of scope for this specification: a mechanism similar to the <eref target="https://sciencemesh.io">ScienceMesh</eref> integration for the <xref target="invite-flow">Invite</xref> capability may be envisaged.</t>
    </section>
    <section anchor="appendix-b-request-signing">
      <name>Appendix B: Request Signing</name>
      <t>A request is signed by adding the signature in the headers. The sender also needs to expose the public key used to generate the signature. The receiver can then validate the signature and therefore the origin of the request.
To help debugging, it is recommended to also add all properties used in the signature as headers, even if they can easily be re-generated from the payload.</t>
      <t>Note: Signed requests prove the identity of the sender but do not encrypt nor affect its payload.</t>
      <t>Here is an example of headers needed to sign a request.</t>
      <artwork><![CDATA[
  {
    "(request-target)": "post /path",
    "content-length": 380,
    "date": "Mon, 08 Jul 2024 14:16:20 GMT",
    "digest": "SHA-256=U7gNVUQiixe5BRbp4Tg0xCZMTcSWXXUZI2\\/xtHM40S0=",
    "host": "hostname.of.the.recipient",
    "Signature": "keyId=\"https://author.hostname/key\",algorithm=\"rsa-sha256\",headers=\"content-length date digest host\",signature=\"DzN12OCS1rsA[...]o0VmxjQooRo6HHabg==\""
  }
]]></artwork>
      <ul spacing="normal">
        <li>
          <t>'(request-target)' contains the reached endpoint and the used method,</t>
        </li>
        <li>
          <t>'content-length' is the total length of the payload of the request,</t>
        </li>
        <li>
          <t>'date' is the date and time when the request has been sent,</t>
        </li>
        <li>
          <t>'digest' is a checksum of the payload of the request,</t>
        </li>
        <li>
          <t>'host' is the hostname of the recipient of the request (remote when signing outgoing request, local on incoming request),</t>
        </li>
        <li>
          <t>'Signature' contains the signature generated using the private key and details on its generation:
          </t>
          <ul spacing="normal">
            <li>
              <t>'keyId' is a unique id, formatted as an url. hostname is used to retrieve the public key via custom discovery</t>
            </li>
            <li>
              <t>'algorithm' specify the algorithm used to generate signature</t>
            </li>
            <li>
              <t>'headers' specify the properties used when generating the signature</t>
            </li>
            <li>
              <t>'signature' the signature of an array containing the properties listed in 'headers'. Some properties like content-length, date, digest, and host are mandatory to protect against authenticity override.</t>
            </li>
          </ul>
        </li>
      </ul>
      <section anchor="how-to-generate-the-signature-for-outgoing-request">
        <name>How to generate the Signature for outgoing request</name>
        <t>After properties are set in the headers, the Signature is generated and added to the list.</t>
        <t>This is a pseudo-code example for generating the <tt>Signature</tt> header for outgoing requests:</t>
        <artwork><![CDATA[
headers = {
    '(request-target)': 'post /path',
    'content-length': length_of(payload),
    'date': current_gmt_datetime(),  # Use a function to get the current GMT date as 'D, d M Y H:i:s T'
    'digest': 'SHA-256=' + base64_encode(hash('sha256', utf8_encode(payload))),
    'host': 'recipient-fqdn',
}

signed = ssl_sign(concatenate_with_newlines(headers), private_key, 'sha256')
signature = {
    'keyId': 'sender-fqdn',  # The sending server's FQDN; find its public key through OCM API discovery
    'algorithm': 'rsa-sha256',
    'headers': 'content-length date digest host',
    'signature': signed,
}

headers['Signature'] = format_signature(signature)
]]></artwork>
        <section anchor="how-to-confirm-signature-on-incoming-request">
          <name>How to confirm Signature on incoming request</name>
          <t>The first step would be to confirm the validity of each properties:</t>
          <ul spacing="normal">
            <li>
              <t><tt>(request-target)</tt> and <tt>host</tt> are immutable to the type of the request and the local/current host,</t>
            </li>
            <li>
              <t><tt>content-length</tt> and <tt>digest</tt> can be re-generated and compared from the payload of the request,</t>
            </li>
            <li>
              <t>a maximum TTL must be applied to <tt>date</tt> and current timestamp,</t>
            </li>
            <li>
              <t>regarding data contained in the <tt>Signature</tt> header:
              </t>
              <ul spacing="normal">
                <li>
                  <t>using <tt>keyId</tt> to get the public key from remote signatory,</t>
                </li>
                <li>
                  <t><tt>headers</tt> is used to generate the clear version of the signature and must contain at least <tt>content-length</tt>, <tt>date</tt>, <tt>digest</tt> and <tt>host</tt>,</t>
                </li>
                <li>
                  <t><tt>signature</tt> is the encrypted version of the signature.</t>
                </li>
              </ul>
            </li>
          </ul>
          <t>Here is an example of how to verify the signature using the headers, the signature and the public key:</t>
          <artwork><![CDATA[
clear = {
    '(request-target)': 'post /path',
    'content-length': length_of(payload),
    'date': 'Mon, 08 Jul 2024 14:16:20 GMT',  # The date used in the verification process
    'digest': 'SHA-256=' + base64_encode(hash('sha256', utf8_encode(payload))),  # Recompute the digest for verification
    'host': 'sender-fqdn',
}

signed = headers['Signature']
verification_result = ssl_verify(concatenate_with_newlines(clear), signed, public_key, 'sha256')

if not verification_result then
    raise InvalidSignatureException
]]></artwork>
        </section>
      </section>
      <section anchor="validating-the-payload">
        <name>Validating the payload</name>
        <t>Following the validation of the signature, the host should also confirm the validity of the payload, that is ensuring that the actions implied in the payload actually initiated on behalf of the source of the request.</t>
        <t>As an example, if the payload is about initiating a new share the file owner has to be an account from the instance at the origin of the request.</t>
      </section>
    </section>
  </middle>
  <back>








  </back>
  <!-- ##markdown-source:
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
w2/v/wNxrQWxcbIAAA==

-->

</rfc>
