<?xml version="1.0" encoding="UTF-8"?>
  <?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
  <!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.29 (Ruby 3.2.8) -->


<!DOCTYPE rfc  [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">

]>


<rfc ipr="trust200902" docName="draft-lopresti-open-cloud-mesh-03" category="std" consensus="true">
  <front>
    <title>Open Cloud Mesh</title>

    <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="2025" month="June" day="23"/>

    <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>

<t><list style="symbols">
  <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>
  <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>
  <t><strong>Sending Party</strong> - a person or party who is authorized to create Shares (similar to "Resource Owner" in OAuth)</t>
  <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>
  <t><strong>Sending Server</strong> - the server that:
  <list style="symbols">
      <t>holds the Resource ("file server" or "Entreprise File Sync and Share (EFSS) server" role),</t>
      <t>provides access to it (by exposing at least one "API"),</t>
      <t>takes the decision to create the Share based on user interface gestures from the Sending Party (the "Authorization Server" role in OAuth)</t>
      <t>takes the decision about authorizing attempts to access the Resource (the "Resource Server" role in OAuth)</t>
      <t>sends out Share Creation Notifications when appropriate (see below)</t>
    </list></t>
  <t><strong>Receiving Server</strong> - the server that:
  <list style="symbols">
      <t>receives Share Creation Notifications (see below)</t>
      <t>actively or passively notifies the receiving user or group of any incoming Share Creation Notification</t>
      <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>
    </list></t>
  <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>
  <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>
  <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>
  <t><strong>FQDN</strong> - Fully Qualified Domain Name, such as <spanx style="verb">"cloud.example.com"</spanx></t>
  <t><strong>OCM Server</strong> - a server that supports OCM.</t>
  <t><strong>Discovering Server</strong> - a server that tries to obtain information in OCM API discovery</t>
  <t><strong>Discoverable Server</strong> - a server that tries to supply information in OCM API discovery</t>
  <t><strong>OCM Address</strong> - a string of the form <spanx style="verb">&lt;Receiving Party's identifier&gt;@&lt;fqdn&gt;</spanx> which can be used to uniquely identify a user or group "at" an OCM Server. <spanx style="verb">&lt;Receiving Party's identifier&gt;</spanx> is an opaque string,
unique at the server. <spanx style="verb">&lt;fqdn&gt;</spanx> is the Fully Qualified Domain Name by which the server is identified. This MUST be the domain at which the <spanx style="verb">/.well-known/ocm</spanx> endpoint of that server is hosted.</t>
  <t><strong>OCM Notification</strong> - a message from the Receiving Server to the Sending Server or vice versa, using the OCM Notifications endpoint.</t>
  <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>
  <t><strong>Invite Sender</strong> - the party sending an Invite</t>
  <t><strong>Invite Receiver</strong> - the party receiving an Invite</t>
  <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>
  <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>
  <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>
  <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>
  <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>
  <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>
  <t><strong>Invite Acceptance Response</strong> - HTTP response to the Invite Acceptance Request</t>
  <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>
  <t><strong>Share Permissions</strong> - protocol-specific allowances granted to the Receiving Party on the modes of accessing the Resource</t>
  <t><strong>Share Requirements</strong> - protocol-specific restrictions on the modes of accessing the Resource</t>
  <t><strong>WAYF Page</strong> - a Where-Are-You-From page is a discovery service used to identify the OCM Server of an Invite Receiver</t>
  <t><strong>Directory Service</strong> - a third-party service that exposes a list of trusted OCM Servers</t>
</list></t>

</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>

<t><list style="symbols">
  <t>the Invite Sender OCM Server generates a unique Invite Token and helps the Invite Sender to create the Invite Message</t>
  <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>
  <t>the Invite Receiver navigates to the Invite Receiver OCM Server and makes the Invite Acceptance Gesture. This step MAY be facilitated if the Invite Sender OCM Server implements a WAYF Page, such that the Invite Message would include a link to it for the Invite Receiver to navigate to: the Invite Receiver would then be able to indicate their OCM Server and proceed with the Invite Acceptance Gesture without manually copying the Invite Token.</t>
  <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>
  <t>the Invite Receiver OCM Server sends the Invite Acceptance Request to the Invite Sender OCM Server</t>
</list></t>

</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>

<t><list style="symbols">
  <t>to the <spanx style="verb">/invite-accepted</spanx> path in the Invite Sender OCM Server's OCM API</t>
  <t>using <spanx style="verb">application/json</spanx> as the <spanx style="verb">Content-Type</spanx> HTTP request header</t>
  <t>its request body containing a JSON document representing an object with the following string fields:
  <list style="symbols">
      <t>REQUIRED: <spanx style="verb">recipientProvider</spanx> - FQDN of the Invite Receiver OCM Server</t>
      <t>REQUIRED: <spanx style="verb">token</spanx> - the Invite Token. The Invite Sender OCM Server SHOULD recall which Invite Sender OCM Address this token was linked to</t>
      <t>REQUIRED: <spanx style="verb">userID</spanx> - the Invite Receiver's identifier at their OCM Server</t>
      <t>REQUIRED: <spanx style="verb">email</spanx> - non-normative / informational; an email address for the Invite Receiver. Not necessarily at the same FQDN as their OCM Server</t>
      <t>REQUIRED: <spanx style="verb">name</spanx> - human-readable name of the Invite Receiver, as a suggestion for display in the Invite Sender's address book</t>
    </list></t>
  <t>using TLS</t>
  <t>using <eref target="https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12">httpsig</eref></t>
</list></t>

<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 <spanx style="verb">userID</spanx>, 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 <spanx style="verb">userID</spanx> that forms part of their OCM Address does not need to match it.</t>

<t>Also, a different <spanx style="verb">userID</spanx> could be given out to each contact, to avoid correlation of identities.</t>

<t>If the Invite Sender OCM Server implements a WAYF Page, such a page MAY include a fixed list of servers, in addition to, or instead of, a free-text input where any OCM Server can be entered. This is especially useful if the Invite Sender is part of a federation of associated OCM Servers. In order to populate the list of associated OCM Servers, the Invite Sender's server MAY make use of a Directory Service, which is expected to follow the specification detailed in Appendix C.</t>

<t>Implementors that provide a WAYF Page SHOULD make the URL for the API endpoint of such a Directory Service configurable, allowing the OCM Server to be part of a network of associated OCM Servers. The configuration mechanism MAY allow an OCM Server to be part of multiple networks, thus displaying a union of multiple lists in its WAYF Page.</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>

<t><list style="symbols">
  <t>in response to the Invite Acceptance Request</t>
  <t>using <spanx style="verb">application/json</spanx> as the <spanx style="verb">Content-Type</spanx> HTTP response header</t>
  <t>its response body containing a JSON document representing an object with the following string fields:
  <list style="symbols">
      <t>REQUIRED: <spanx style="verb">userID</spanx> - the Invite Sender's identifier at their OCM Server</t>
      <t>REQUIRED: <spanx style="verb">email</spanx> - non-normative / informational; an email address for the Invite Sender. Not necessarily at the same FQDN as their OCM Server</t>
      <t>REQUIRED: <spanx style="verb">name</spanx> - human-readable name of the Invite Sender, as a suggestion for display in the Invite Receiver's address book</t>
    </list></t>
</list></t>

<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 <spanx style="verb">userID</spanx> 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 <spanx style="verb">name</spanx> 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>

<t><list style="symbols">
  <t>Resource to be shared</t>
  <t>Protocol to be offered for access</t>
  <t>Sending Party's identifier</t>
  <t>Receiving Party's identifier</t>
  <t>Receiving Server FQDN</t>
  <t>OPTIONAL: Share Requirements</t>
  <t>OPTIONAL: Share Name</t>
  <t>OPTIONAL: Share Permissions</t>
</list></t>

<t>The next step is for the Sending Server to additionally discover:</t>

<t><list style="symbols">
  <t>if the Receiving Server is trusted</t>
  <t>if the Receiving Server supports OCM</t>
  <t>if so, which version and with which optional functionality</t>
  <t>at which URL</t>
  <t>the public key the Receiving Server will use for HTTP Signatures (if any)</t>
</list></t>

<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 <spanx style="verb">recipientProvider</spanx> field of an Invite Acceptance Request.</t>

<t>Step 1: In case it has an OCM Address, it should first extract <spanx style="verb">&lt;fqdn&gt;</spanx> from it (the part after the last <spanx style="verb">@</spanx> sign).
Step 2: The Discovering Server SHOULD attempt OCM API discovery a HTTP GET request to <spanx style="verb">https://&lt;fqdn&gt;/.well-known/ocm</spanx>.
Step 3: If that results in a valid HTTP response with a valid JSON response body within reasonable time, go to step 7.
Step 4: If not, try a HTTP GET with <spanx style="verb">https://&lt;fqdn&gt;/ocm-provider</spanx> 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 7.
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>

<t><list style="symbols">
  <t>REQUIRED: enabled (boolean) - Whether the OCM service is enabled at this endpoint</t>
  <t>REQUIRED: apiVersion (string) - The OCM API version this endpoint supports. Example: <spanx style="verb">"1.2.0"</spanx></t>
  <t>REQUIRED: endPoint (string) - The URI of the OCM API available at this endpoint. Example: <spanx style="verb">"https://my-cloud-storage.org/ocm"</spanx></t>
  <t>OPTIONAL: provider (string) - A friendly branding name of this endpoint. Example: <spanx style="verb">"MyCloudStorage"</spanx></t>
  <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:
  <list style="symbols">
      <t>name (string) -  A supported resource type (file, folder, calendar, contact, ...).
            Implementations MUST offer support for at least one resource type, where <spanx style="verb">file</spanx> is the commonly supported one. Each resource type is identified by its <spanx style="verb">name</spanx>:
            the list MUST NOT contain more than one resource type object per given <spanx style="verb">name</spanx>.</t>
      <t>shareTypes (array of string) -
            The supported recipient share types.
            MUST contain <spanx style="verb">"user"</spanx> at a minimum, plus optionally <spanx style="verb">"group"</spanx> and <spanx style="verb">"federation"</spanx>.
            Example: <spanx style="verb">["user"]</spanx></t>
      <t>protocols (object) - The supported protocols for accessing shared resources of this type.
            Implementations that offer <spanx style="verb">file</spanx> resources MUST support at least <spanx style="verb">webdav</spanx>,
            any other combination of resources and protocols is optional. Example:
            <spanx style="verb">json
            {
              "webdav": "/remote/dav/ocm/",
              "webapp": "/app/ocm/",
              "talk": "/apps/spreed/api/"
            }
           </spanx>
            Fields:
      <list style="symbols">
          <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>
          <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>
          <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>
          <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>
        </list></t>
    </list></t>
  <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: <spanx style="verb">["receive-code", "webdav-uri"]</spanx>. The array MAY include for instance:
  <list style="symbols">
      <t><spanx style="verb">"enforce-mfa"</spanx> - to indicate that this OCM Server can apply a Sending Server's MFA requirements for a Share on their behalf.</t>
      <t><spanx style="verb">"webdav-uri"</spanx> - to indicate that this OCM Server can append a relative URI to the path listed for WebDAV in the appropriate <spanx style="verb">resourceTypes</spanx> entry</t>
      <t><spanx style="verb">"protocol-object"</spanx> - to indicate that this OCM Server can receive a Share Creation Notification whose <spanx style="verb">protocol</spanx> object contains one property per supported protocol instead of containing the standard <spanx style="verb">name</spanx> and <spanx style="verb">options</spanx> properties.</t>
      <t><spanx style="verb">"invites"</spanx> - 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>
      <t><spanx style="verb">"receive-code"</spanx> - to indicate that this OCM Server can receive a <spanx style="verb">code</spanx> as part of a Share Creation Notification, and exchange it for a bearer token at the Sending Server's <spanx style="verb">/token</spanx> API endpoint.</t>
      <t><spanx style="verb">"invite-wayf"</spanx> - to indicate that this OCM Server exposes a WAYF Page to facilitate the Invite flow.</t>
    </list></t>
  <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: <spanx style="verb">["http-request-signatures", "code"]</spanx>. The array MAY include for instance:
  <list style="symbols">
      <t><spanx style="verb">"http-request-signatures"</spanx> - to indicate that API requests without http signatures will be rejected.</t>
      <t><spanx style="verb">"code"</spanx> - to indicate that API requests without code will be rejected (i.e. the <spanx style="verb">sharedSecret</spanx> in the protocol details will be ignored).</t>
      <t><spanx style="verb">"denylist"</spanx> - some servers may be blocked based on their IP address</t>
      <t><spanx style="verb">"allowlist"</spanx> - unknown servers may be blocked based on their IP address</t>
      <t><spanx style="verb">"invite"</spanx> - an invite must have been exchanged between the sender and the receiver before a Share Creation Notification can be sent</t>
    </list></t>
  <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, <spanx style="verb">id</spanx> and <spanx style="verb">publicKeyPem</spanx>.
      properties:
  <list style="symbols">
      <t>REQUIRED keyId (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>
      <t>REQUIRED publicKeyPem (string) - PEM-encoded version of the public key.
        Example: "-----BEGIN PUBLIC KEY-----\nMII...QDD\n-----END PUBLIC KEY-----\n"</t>
    </list></t>
  <t>OPTIONAL: inviteAcceptDialog (string) - URL path of a web page where a user can accept an invite, when query parameters <spanx style="verb">"token"</spanx> and <spanx style="verb">"providerDomain"</spanx> are provided. Implementations that offer the <spanx style="verb">"invites"</spanx> capability SHOULD provide this URL as well in order to enhance the UX of the Invite Flow. If for example <spanx style="verb">"/index.php/apps/sciencemesh/accept"</spanx> is specified here then a WAYF Page SHOULD redirect the end-user to <spanx style="verb">/index.php/apps/sciencemesh/accept?token=zi5kooKu3ivohr9a&amp;providerDomain=example.com</spanx>.</t>
</list></t>

</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>

<t><list style="symbols">
  <t>to the <spanx style="verb">/shares</spanx> path in the Receiving Server's OCM API</t>
  <t>using <spanx style="verb">application/json</spanx> as the <spanx style="verb">Content-Type</spanx> HTTP request header</t>
  <t>its request body containing a JSON document representing an object with the fields as described below</t>
  <t>using TLS</t>
  <t>using <eref target="https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12">httpsig</eref></t>
</list></t>

<section anchor="fields-1"><name>Fields</name>

<t><list style="symbols">
  <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>
  <t>REQUIRED name (string)
     Name of the resource (file or folder).
      Example: "resource.txt"</t>
  <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>
  <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>
  <t>REQUIRED owner (string) -
        Provider specific identifier of the user who owns the resource.
      Example: "6358b71804dfa8ab069cf05ed1b0ed2a@apiwise.nl"</t>
  <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 <spanx style="verb">remote</spanx> property
        is not part of the request body.
      Example: "527bd5b5d689e2c32ae974c6229ff785@apiwise.nl"</t>
  <t>OPTIONAL ownerDisplayName (string)
        Display name of the owner of the resource
      Example: "Dimitri"</t>
  <t>OPTIONAL senderDisplayName (string)
        Display name of the user that wants to share the resource
      Example: "John Doe"</t>
  <t>REQUIRED shareType (string)
      SHOULD have a value of "user", "group", or "federation", to indicated that the first part
      of the <spanx style="verb">shareWith</spanx> 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>
  <t>REQUIRED resourceType (string)
        Resource type (file, folder, calendar, contact, ...)</t>
  <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>
  <t>OPTIONAL code (string)
        A nonce to be exchanged for a (potentially short-lived) bearer token at the Sending Server's /token endpoint.</t>
  <t>REQUIRED protocol (object)
        JSON object with specific options for each protocol.
        The supported protocols are:
        - <spanx style="verb">webdav</spanx>, to access the data
        - <spanx style="verb">webapp</spanx>, to access remote web applications
        - <spanx style="verb">datatx</spanx>, to transfer the data to the remote endpoint  <vspace blankLines='1'/>
    <figure><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 is 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></figure>
  </t>
</list></t>

<t>If <spanx style="verb">multi</spanx> is given, one or more protocol
                endpoints are expected to be defined according to the optional
                properties specified below.
                Otherwise, at least <spanx style="verb">webdav</spanx> is expected to be supported, and
                its options MAY be given in the opaque <spanx style="verb">options</spanx> 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 <spanx style="verb">webdav</spanx> and <spanx style="verb">multi</spanx>, but v1.0 servers MAY
                only support <spanx style="verb">webdav</spanx>.</t>

<t><list style="symbols">
  <t>Protocol details for <spanx style="verb">webdav</spanx> MAY contain:
  <list style="symbols">
      <t>REQUIRED uri (string)
             An URI to access the remote resource. The URI SHOULD be relative,
             in which case the prefix exposed by the <spanx style="verb">/.well-known/ocm</spanx> endpoint MUST
             be used. Absolute URIs are deprecated.</t>
      <t>OPTIONAL sharedSecret (string) - required if no <spanx style="verb">code</spanx> 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>
      <t>OPTIONAL permissions (array of strings) -
               The permissions granted to the sharee. A subset of:
               - <spanx style="verb">read</spanx> allows read-only access including download of a copy.
               - <spanx style="verb">write</spanx> allows create, update, and delete rights on the resource.
               - <spanx style="verb">share</spanx> allows re-share rights on the resource.</t>
      <t>OPTIONAL requirements (array of strings) -
               The requirements that the sharee MUST fulfill to access the resource. A subset of:
               - <spanx style="verb">mfa-enforced</spanx> requires the consumer to be MFA-authenticated. This
                 MAY be used if the recipient provider exposes the <spanx style="verb">enforce-mfa</spanx> capability.
               - <spanx style="verb">use-code</spanx> requires the consumer to exchange the given <spanx style="verb">code</spanx> via a
                 signed HTTPS request. This MAY be used if the recipient provider exposes
                 the <spanx style="verb">receive-code</spanx> capability.</t>
    </list></t>
  <t>Protocol details for <spanx style="verb">webapp</spanx> MAY contain:
  <list style="symbols">
      <t>REQUIRED uri (string)
             An URI to a client-browsable view of the shared resource, such that
             users may use the web applications available at the site. The URI SHOULD
             be relative, in which case the prefix exposed by the <spanx style="verb">/.well-known/ocm</spanx>
             endpoint MUST be used. Absolute URIs are deprecated.</t>
      <t>REQUIRED viewMode (string)
             The permissions granted to the sharee. A subset of:
             - <spanx style="verb">view</spanx> allows access to the web app in view-only mode.
             - <spanx style="verb">read</spanx> allows read and download access via the web app.
             - <spanx style="verb">write</spanx> allows full editing rights via the web app.</t>
      <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>
    </list></t>
  <t>Protocol details for <spanx style="verb">datatx</spanx> MAY contain:
  <list style="symbols">
      <t>REQUIRED srcUri (string)
             An URI to access the remote resource. The URI SHOULD be relative,
             in which case the prefix exposed by the <spanx style="verb">/.well-known/ocm</spanx> endpoint MUST
             be used. Absolute URIs are deprecated.</t>
      <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>
      <t>OPTIONAL size (integer)
             The size of the file to be transferred from the sending server.</t>
    </list></t>
</list></t>

</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>

<t><list style="symbols">
  <t>the HTTP Signature is missing but the Sending Server does expose a keypair discoverable from the FQDN part of the <spanx style="verb">sender</spanx> field in the request body</t>
  <t>the HTTP Signature is missing</t>
  <t>the HTTP Signature is not valid</t>
  <t>no keypair is trusted or discoverable from the FQDN part of the <spanx style="verb">sender</spanx> field in the request body</t>
  <t>the keypair used to generate the HTTP Signature doesn't match the one trusted or discoverable from the FQDN part of the <spanx style="verb">sender</spanx> field in the request body</t>
  <t>the Sending Server is denylisted</t>
  <t>the Sending Server is not allowlisted</t>
  <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>
  <t>the Receiving Server is unable to act as an API client for (any of) the protocol(s) listed for accessing the resource</t>
  <t>an initial check shows that the resource cannot successfully be accessed through (any of) the protocol(s) listed</t>
</list></t>

</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 <spanx style="verb">&lt;fqdn&gt;</spanx> part of the <spanx style="verb">sender</spanx> 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>

<t><list style="symbols">
  <t>to the <spanx style="verb">/notifications</spanx> path in the Sending Server's OCM API</t>
  <t>using <spanx style="verb">application/json</spanx> as the <spanx style="verb">Content-Type</spanx> HTTP request header</t>
  <t>its request body containing a JSON document representing an object with the fields as described below</t>
  <t>using TLS</t>
  <t>using <eref target="https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12">httpsig</eref></t>
</list></t>

<section anchor="fields-2"><name>Fields</name>

<t><list style="symbols">
  <t>REQUIRED notificationType (string) - in a Share Acceptance Notification it SHOULD be one of:
  <list style="symbols">
      <t>'SHARE_ACCEPTED'</t>
      <t>'SHARE_DECLINED'</t>
    </list></t>
  <t>REQUIRED providerId (string) - copied from the Share Creation Notification for the Share this notification is about</t>
  <t>OPTIONAL resourceType (string) - copied from the Share Creation Notification for the Share this notification is about</t>
  <t>OPTIONAL notification (object) - optional additional parameters, depending on the notification and the resource type</t>
</list></t>

<t>For example, a notification MAY be sent by a recipient to let the provider know that the recipient declined a share. In this case, the provider site MAY mark the share as declined for its user(s).
Similarly, it MAY be sent by a provider to let the recipient know that the provider removed a given share, such that the recipient MAY clean it up from its database.
A notification MAY also be sent to let a recipient know that the provider removed that recipient from the list of trusted users, along with any related share. The recipient MAY reciprocally remove that provider from the list of trusted users, along with any related share.</t>

<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. The receiver MUST extract the OCM Server FQDN from the <spanx style="verb">sender</spanx> field of the received share, and MUST query the <xref target="ocm-api-discovery">Discovery</xref> endpoint at that address: the <spanx style="verb">resourceTypes[0].protocols.webdav</spanx> value is the <spanx style="verb">&lt;sender-ocm-path&gt;</spanx> to be used in step 3.
2. If <spanx style="verb">code</spanx> is not empty, the receiver SHOULD make a signed POST request to the <spanx style="verb">/token</spanx> 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 <spanx style="verb">protocol.name</spanx> = <spanx style="verb">webdav</spanx>, the receiver SHOULD inspect the <spanx style="verb">protocol.options</spanx> property. If it contains a <spanx style="verb">sharedSecret</spanx>, 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 <spanx style="verb">https://&lt;sharedSecret&gt;:@&lt;sender-host&gt;&lt;sender-ocm-path&gt;</spanx>. 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 <spanx style="verb">protocol.name</spanx> = <spanx style="verb">multi</spanx>, the receiver MUST inspect the <spanx style="verb">protocol.webdav.uri</spanx> 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 <spanx style="verb">&lt;key&gt;</spanx>, the receiver MUST make a HTTP PROPFIND request to <spanx style="verb">https://&lt;sender-host&gt;&lt;sender-ocm-path&gt;/&lt;key&gt;</spanx> in order to access the remote resource. Additionally, the receiver MUST pass an <spanx style="verb">Authorization: bearer</spanx> header with either the short-lived bearer token obtained in step 2, if applicable, or the <spanx style="verb">protocol.webdav.sharedSecret</spanx> 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 <spanx style="verb">https://&lt;sender-host&gt;&lt;sender-ocm-path&gt;/path/to/resource.txt</spanx>.</t>

<t>Additionally, if <spanx style="verb">protocol.&lt;protocolname&gt;.requirements</spanx> includes <spanx style="verb">mfa-enforced</spanx>, 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 <spanx style="verb">"SHARE_ACCEPTED"</spanx> notification followed by a <spanx style="verb">"SHARE_UNSHARED"</spanx> notification is
equivalent to a <spanx style="verb">"SHARE_DECLINED"</spanx> 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 <spanx style="verb">"RESHARE_CHANGE_PERMISSION"</spanx>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 <spanx style="verb">"REQUEST_RESHARE"</spanx> and <spanx style="verb">"RESHARE_UNDO"</spanx> 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 <spanx style="verb">enforce-mfa</spanx>, 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 <spanx style="verb">mfa-enforced</spanx> 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 <spanx style="verb">mfa-enforced</spanx> 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>

<figure><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></figure>

<t><list style="symbols">
  <t>'(request-target)' contains the reached endpoint and the used method,</t>
  <t>'content-length' is the total length of the payload of the request,</t>
  <t>'date' is the date and time when the request has been sent,</t>
  <t>'digest' is a checksum of the payload of the request,</t>
  <t>'host' is the hostname of the recipient of the request (remote when signing outgoing request, local on incoming request),</t>
  <t>'Signature' contains the signature generated using the private key and details on its generation:
  <list style="symbols">
      <t>'keyId' is a unique id, formatted as an url. hostname is used to retrieve the public key via custom discovery</t>
      <t>'algorithm' specify the algorithm used to generate signature</t>
      <t>'headers' specify the properties used when generating the signature</t>
      <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>
    </list></t>
</list></t>

<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 <spanx style="verb">Signature</spanx> header for outgoing requests:</t>

<figure><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></figure>

</section>
<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>

<t><list style="symbols">
  <t><spanx style="verb">(request-target)</spanx> and <spanx style="verb">host</spanx> are immutable to the type of the request and the local/current host,</t>
  <t><spanx style="verb">content-length</spanx> and <spanx style="verb">digest</spanx> can be re-generated and compared from the payload of the request,</t>
  <t>a maximum TTL must be applied to <spanx style="verb">date</spanx> and current timestamp,</t>
  <t>regarding data contained in the <spanx style="verb">Signature</spanx> header:
  <list style="symbols">
      <t>using <spanx style="verb">keyId</spanx> to get the public key from remote signatory,</t>
      <t><spanx style="verb">headers</spanx> is used to generate the clear version of the signature and must contain at least <spanx style="verb">content-length</spanx>, <spanx style="verb">date</spanx>, <spanx style="verb">digest</spanx> and <spanx style="verb">host</spanx>,</t>
      <t><spanx style="verb">signature</spanx> is the encrypted version of the signature.</t>
    </list></t>
</list></t>

<t>Here is an example of how to verify the signature using the headers, the signature and the public key:</t>

<figure><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></figure>

</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>
<section anchor="appendix-c-directory-service"><name>Appendix C: Directory Service</name>

<t>A third-party Directory Service is a back-end service used to federate multiple OCM Servers and facilitate the Invite flow. It is expected to expose, via anonymous HTTP GET, a JSON document with the following format:
  * REQUIRED: <spanx style="verb">federation</spanx> - a human-readable name for the list of OCM Servers exposed by the Directory Service
  * REQUIRED: <spanx style="verb">servers</spanx> - a JSON array of objects to describe the list of OCM Servers with the following string fields:
    * REQUIRED: <spanx style="verb">url</spanx> - the OCM Server's FQDN
    * REQUIRED: <spanx style="verb">displayName</spanx> - a human-readable name for the OCM Server
  Example:
  <spanx style="verb">json
  {
    "federation" : "The ScienceMesh Directory",
    "servers" : [
      {
       "url" : "https://ocm-server-1.fqdn",
       "displayName" : "OCM Server 1"
      },
      {
       "url" : "https://ocm-server-2.fqdn",
       "displayName" : "OCM Server 2"
      }
    ]
  }
 </spanx></t>

</section>
<section anchor="acknowledgements"><name>Acknowledgements</name>

<t>Our deepest thanks and appreciation go to the people who started the work on what would become this specification in 2015. In particular we want to thank (in alphabetical order) Guido Aben, Russell Albert, Holger Angenent, David Antoš, Hrachya Astsatryan, Kurt Bauer, Charles du Jeu, Andreas Eckey, David Gillard, Andranik Hayrapetyan Wahi, Christoph Herzog, David Jericho, Frank Karlitschek, Christian Kracher, Ralph Krimmel, Massimo Lamanna, Simon Leinen, Jari Miettinen, Jakub Moscicki, Frederik Orellana, Vlad Roman, Christian Schmitz, Woojin Seok, Rogier Spoor, Christian Sprajc, Peter Szegedi, Ron Trompert, Benedikt Wegmann and Johnatan Xu.</t>

<t>We would also like to thank Ishank Arora, Gianmaria Del Monte, Jörn Friedrich Dreyer, Hugo González Labrador, Maxence Lange, Lovisa Lugnegård, Sandro Mesterheide, Antoon Prins and Björn Schissle for their direct contributions to the specification.</t>

<t>Over the years many more people have been involved in the development of OCM. We would like to thank all of them for their contributions, including Jean-Thomas Acquaviva, Samuel Alfageme Sainz, Karsten Asshauer, Miroslav Bauer, Felix Böhm, Maciej Brzeźniak, Diogo Castro, Gavin Charles Kennedy, Jarosław Czub, Milan Danecek, Michael D'Silva, Lukasz Dutka, Pedro Ferreira, Renato Furter, Klaas Freitag, Raman Ganguly, Eva Gergely, Hilary Goodson, Daniel Halbe, Dave Heyns, Jan Holesovsky, Jan Hornicek, Carina Kemp, Fergus Kerins, Andreas Klotz, Matthias Knoll, Christian Kracher, Mario Lassnig, Claudius Laumanns, Anthony Leroy, Patrick Maier, Vladislav Makarenko, Anna Manou, Rita Meneses, Zheng Meyer-Zhao, Crystal Michelle Chua, Yoann Moulin, Daniel Müller, Frederik Müller, Rasmus Munk, Michał Orzechowski, Jacek Pawel Kitowski, Iosif Peterfi, Alessandro Petraro, Rene Ranger, Angelo Romasanta, David Rousse, Carla Sauvanaud, Klaus Scheibenberger, Christian Schmitz, Marcin Sieprawski, Tilo Steiger, C.D. Tiwari, Alejandro Unger and Tom Wezepoel.</t>

</section>


  </middle>

  <back>








  </back>

<!-- ##markdown-source:
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
DwEhFg72xwAA

-->

</rfc>

