<?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.39 (Ruby 4.0.5) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-mahy-mimi-credential-preauth-00" category="info" consensus="true" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.34.0 -->
  <front>
    <title abbrev="MIMI Deep Credential Preauth">MIMI Preauthorization based on deep references to MLS Credentials</title>
    <seriesInfo name="Internet-Draft" value="draft-mahy-mimi-credential-preauth-00"/>
    <author fullname="Rohan Mahy">
      <organization/>
      <address>
        <email>rohan.ietf@gmail.com</email>
      </address>
    </author>
    <date year="2026" month="July" day="06"/>
    <area>Applications and Real-Time</area>
    <workgroup>More Instant Messaging Interoperability</workgroup>
    <keyword>preauthorization</keyword>
    <keyword>credential</keyword>
    <keyword>CWT</keyword>
    <keyword>JWT</keyword>
    <keyword>X.509</keyword>
    <keyword>ASN.1</keyword>
    <keyword>DER</keyword>
    <keyword>credential matching</keyword>
    <keyword>credential comparison</keyword>
    <abstract>
      <?line 43?>

<t>This document describes a Work-In-Progress syntax called claim pointers that identify specific items in structured credentials, which often have nested levels of hierarchy;
and claim matchers that facilitate comparisons between items in credentials and a target value.
It also describes a new version of the More Instant Messaging Interoperability (MIMI) preauthorization format using claim pointers and claim matchers.</t>
    </abstract>
    <note removeInRFC="true">
      <name>About This Document</name>
      <t>
        The latest revision of this draft can be found at <eref target="https://rohanmahy.github.io/mimi-credential-preauth/draft-mahy-mimi-credential-preauth.html"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-mahy-mimi-credential-preauth/"/>.
      </t>
      <t>
        Discussion of this document takes place on the
        More Instant Messaging Interoperability Working Group mailing list (<eref target="mailto:mimi@ietf.org"/>),
        which is archived at <eref target="https://mailarchive.ietf.org/arch/browse/mimi/"/>.
        Subscribe at <eref target="https://www.ietf.org/mailman/listinfo/mimi/"/>.
      </t>
      <t>Source for this draft and an issue tracker can be found at
        <eref target="https://github.com/rohanmahy/mimi-credential-preauth"/>.</t>
    </note>
  </front>
  <middle>
    <?line 49?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>More Instant Messaging Interoperability (MIMI) room policy (<xref target="I-D.ietf-mimi-room-policy"/>) defines a format that allows potential joiners that are not enumerated beforehand to be preauthorized based on properties found in their Messaging Layer Security (MLS) <xref target="RFC9420"/> credentials.
The current version of the preauthorization format in <xref section="4" sectionFormat="of" target="I-D.ietf-mimi-room-policy"/> is underspecified and was designed to work with individual claims in a JSON Web Token (JWT) <xref target="RFC7519"/> or CBOR Web Token (CWT) <xref target="RFC8392"/>.
This document describes a Work-In-Progress syntax called claim pointers that can address claims nested inside JWT, CWT, and X.509 certificates <xref target="RFC5280"/>, and provides richer matching rules called claim matchers, capable of matching sub parts of those claims and predicates based on them.
It could also be extended to credentials based on most general purpose structured data formats.</t>
    </section>
    <section anchor="conventions-and-definitions">
      <name>Conventions and Definitions</name>
      <t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL
NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>",
"<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as
described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they
appear in all capitals, as shown here.</t>
      <?line -18?>

</section>
    <section anchor="structure-of-credentials">
      <name>Structure of Credentials</name>
      <t>Structured data formats use a handful of strategies for representing and organizing data.
All common structured data formats offer some type of record structure semantics. In this context this means a record contains a group of fields.
The names for record and fields differ across formats, as do their specific representations, as shown in the table below.</t>
      <table>
        <thead>
          <tr>
            <th align="left">Format</th>
            <th align="left">Representation of record</th>
            <th align="left">Identifier of field</th>
            <th align="left">Name of field</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td align="left">JSON</td>
            <td align="left">object (preferred)</td>
            <td align="left">name (quoted string)</td>
            <td align="left">value</td>
          </tr>
          <tr>
            <td align="left">JSON</td>
            <td align="left">array</td>
            <td align="left">position</td>
            <td align="left">value</td>
          </tr>
          <tr>
            <td align="left">CBOR</td>
            <td align="left">map (slight preference)</td>
            <td align="left">map key (often an integer)</td>
            <td align="left">value</td>
          </tr>
          <tr>
            <td align="left">CBOR</td>
            <td align="left">array</td>
            <td align="left">position</td>
            <td align="left">element</td>
          </tr>
          <tr>
            <td align="left">ASN.1</td>
            <td align="left">sequence</td>
            <td align="left">position or OID</td>
            <td align="left">element</td>
          </tr>
          <tr>
            <td align="left">TLS PL</td>
            <td align="left">struct</td>
            <td align="left">field name</td>
            <td align="left">value</td>
          </tr>
          <tr>
            <td align="left">TLS PL</td>
            <td align="left">vector (not used for records)</td>
            <td align="left">position</td>
            <td align="left">value</td>
          </tr>
          <tr>
            <td align="left">ProtoBuf</td>
            <td align="left">struct or record?</td>
            <td align="left">integer field identifier</td>
            <td align="left">??</td>
          </tr>
          <tr>
            <td align="left">msgpack</td>
            <td align="left"> </td>
            <td align="left"> </td>
            <td align="left"> </td>
          </tr>
          <tr>
            <td align="left">XML</td>
            <td align="left">element</td>
            <td align="left">XMLPath or id attribute</td>
            <td align="left">contents of element</td>
          </tr>
          <tr>
            <td align="left">XML</td>
            <td align="left">attribute</td>
            <td align="left">XMLPath</td>
            <td align="left">value of attribute</td>
          </tr>
          <tr>
            <td align="left">CSV</td>
            <td align="left">line</td>
            <td align="left">position</td>
            <td align="left">field</td>
          </tr>
          <tr>
            <td align="left">TOML</td>
            <td align="left">group</td>
            <td align="left">name</td>
            <td align="left">entry?</td>
          </tr>
          <tr>
            <td align="left">SQL</td>
            <td align="left">row</td>
            <td align="left">column name</td>
            <td align="left">column/field</td>
          </tr>
          <tr>
            <td align="left">YANG</td>
            <td align="left"> </td>
            <td align="left"> </td>
            <td align="left"> </td>
          </tr>
        </tbody>
      </table>
      <t>In this document, we are primarily interested in structured formats commonly used in credentials, specifically JSON Web Tokens (JWT), CBOR Web Tokens (CWT), and X.509 certificates (which use ASN.1) and their derivatives.
In the context of credentials, each of these specific fields is often described as a claim.</t>
      <t>In JSON, a record is represented as an object by convention. The individual fields in the record are identified by the object name, which is always a quoted string.
Very rarely a record is represented as an array of heterogeneous elements.
Credential claims in a JWT are present in the JWT payload object.
Lists of homogenous elements are also arrays.</t>
      <t>In CBOR a record is typically represented as a map (very often with assigned integer map keys).
Records could also be represented as an array of heterogeneous elements.
Lists of homogenous elements are also arrays.</t>
      <t>In X.509v3, a certificate contains an ASN.1 <tt>SEQUENCE</tt> of exactly 3 elements, the <tt>tbsCertificate</tt> ("to be signed certificate", which is analogous to the certificate payload), the signature algorithm, and the signature.
The certificate "payload" record is an ASN.1 <tt>SEQUENCE</tt> of 6 mandatory elements (certificate serial number, signature algorithm, issuer, validity, subject, and subject public key) and up to four optional elements (version, issuer unique ID, subject unique ID, and extensions).
For the purpose of matching elements in the sequence we will assign an index to each field (starting from 0) as if all 10 elements were present.
In this way, the overall structure is addressed by absolute position, while specific names, types, and extensions are identified using registered Object Identifiers (OIDs).
The X.509 certificate extensions field contains a further syntax with a potentially large and varied basket of data structures.
Lists of items are represented as an ASN.1 <tt>SEQUENCE OF</tt> type, which is always of a single basic or composite type.
A composite type can contain a <tt>CHOICE</tt> of multiple subtypes.</t>
      <t>Records and lists in JSON, CBOR, and ASN.1 can be nested, sometimes deeply.
For example, the X.509 <tt>subjectAltName</tt> extension can contain a list of different types of names (DNS, URI, email, etc.) that all represent the subject.
In JWT or CWT credentials, an address claim might consist of several component claims (ex: country or postal code); a language claim might consist of a list of languages; or a groups claim might contain nested claims only relevant to that specific group.</t>
      <t>It is common to have a list of specific permission that have been granted in one context but not another.
For example a public relations manager might have regular access to resource A by virtue of being part of a company, access to resource B by virtue of being a full-time employee, regular access to resource C by virtue of being located in a particular country or office, moderator access to resource D by virtue of being a in public relations, and administrator access to resource E by virtue of being a manager.</t>
    </section>
    <section anchor="requirements-for-credential-inspection">
      <name>Requirements for Credential Inspection</name>
      <t>The following requirements were considered necessary to have a successful credential matching mechanism.</t>
      <ol spacing="normal" type="1"><li>
          <t>The mechanism can represent the difference between no match, and a match with a null or undefined value.</t>
        </li>
        <li>
          <t>The mechanism can find a value in a JSON object or CBOR map by the object name or key name.</t>
        </li>
        <li>
          <t>The mechanism can find an element in ASN.1 by its OID in a <tt>SET</tt> containing a two-element <tt>SEQUENCE</tt>.</t>
        </li>
        <li>
          <t>The mechanism can find an element in a list, array, or <tt>SEQUENCE OF</tt> by its position.</t>
        </li>
        <li>
          <t>The mechanism can find an element in an ASN.1 <tt>SEQUENCE</tt> that has any combination of its optional elements.</t>
        </li>
        <li>
          <t>The mechanism can find a single element in an list or array where one of the list/array elements contains a single "identifying" field somewhere in the array value.</t>
        </li>
        <li>
          <t>The mechanism can find an element among array elements that requires identification by multiple claim matchers joined with boolean logical ANDs (<strong>Maybe</strong>).</t>
        </li>
        <li>
          <t>The mechanism can find a numerical value matching simple numeric predicates, such as greater than, or less than or equal to a target value.</t>
        </li>
        <li>
          <t>The mechanism can match a target value to a well-defined part of a URI and email address claim.</t>
        </li>
        <li>
          <t>The mechanism can compare a target value to an arbitrary substring of a value identified by a claim pointer (<strong>Maybe</strong>).</t>
        </li>
      </ol>
      <t>The following requirements were considered and rejected as out of scope.</t>
      <ul spacing="normal">
        <li>
          <t>Can the mechanism find claim values matching regular expressions? No, since regular expressions often present a security footgun; as we are defining a mechanism expressly to be used with credentials, this is an unacceptable risk.</t>
        </li>
        <li>
          <t>Can the mechanism find claims using arbitrary combinations of boolean logical statements containing OR statements in a claim pointer? No, as this is likely to allow an unbounded explosion of claim combinations, and an OR mechanism can be introduced at the level of the application using the claim pointer mechanism.</t>
        </li>
        <li>
          <t>Can the mechanism find claims with information from partial or incomplete nested map keys? No, since JSON only supports strings as object names, and CWT does not map keys with maps or arrays. However, this might be a straightforward extension.</t>
        </li>
        <li>
          <t>Can the mechanism find multiple claims with a given query? No, this would imply a mechanism that could return a set of arbitrarily disjoint trees, instead of returning a single result (or no match).</t>
        </li>
      </ul>
    </section>
    <section anchor="matching-claims">
      <name>Matching claims</name>
      <t>In this section we introduce a method of matching claims in credentials that we describe here as Claim Pointers (which find a particular value), and Claim Matchers (which compare a value from a Claim Pointer to a specific value).
A claim pointer follows the hierarchy of a credential from its root to a specific claim, through a sequence of specifiers per level. Each level is described using a <tt>ClaimPointerItem</tt> object.</t>
      <t>For the purposes of this section, a level of hierarchy in JSON is the value of any object, or an element of an array. In CBOR a level of hierarchy is the value of any map key, an element of an array, or the contents of a tag. In ASN.1 a level of hierarchy is generally an element of either a <tt>SEQUENCE</tt> or <tt>SEQUENCE OF</tt>.</t>
      <t>For explanatory purposes, we will provide an example JWT payload here to demonstrate some of the claim matching options. Additional examples will be introduced as needed.</t>
      <sourcecode type="json"><![CDATA[
{                                   # contents are at level 1
  "iss": "https://issuer.example",
  ...
  "known_entity": true,
  "orig_timestamp": 1549560720,
  "nodes": [                        # contents are at level 2
    {                               # contents are at level 3
      ...
      "processor": "DCBA-101777",
      "origin": {                   # contents are at level 4
        "country": "us",
        ...
      },
      "domain": "smart.example"
      "eur_per_hour": 273.15
    },
    ...
  ],
  "service_flags": [false, false, true, false]
}
]]></sourcecode>
      <section anchor="matching-map-keys-object-names-and-oids">
        <name>Matching Map Keys, Object Names, and OIDs</name>
        <t>The value of an object in JSON or the value of a map in CBOR is accessed by its JSON name or CBOR map key, using the <tt>via_key</tt> pointer item type.
For JSON the <tt>key</tt> to be compared with the key is a double-quoted JSON string that matches the object name.</t>
        <t>For CBOR the <tt>key</tt> is the ordinary encoding <xref target="I-D.ietf-cbor-serialization"/> that matches the map key.
For example the CBOR map keys of 1 (unsigned integer), -1 (negative integer), '1' (byte string), "1" (text string), 1(0) (a timestamp at the start of the UNIX epoch), and 1.0 (float) match the <tt>key</tt>s of 0x01, 0x20, 0x41 0x31, 0x61 0x31, 0xC1 0x00, and 0xF9 0x3C 0x00 respectively.</t>
        <t>In X.509, a common pattern is to have a single element <tt>SET</tt> of a <tt>SEQUENCE</tt> of two elements consisting of an OID and data element (its "value").
The data element of such a 2 element <tt>SEQUENCE</tt> matches when its <tt>key</tt> is equal to the DER representation of its OID (excluding the OID type and length).</t>
        <t>This pointer item points to ("returns") the value corresponding to the object name, map key, or element in the <tt>SEQUENCE</tt>.</t>
        <t>When evaluating the JWT payload above, the following claim pointer points at the value <tt>true</tt>, since that is the value of the <tt>known_entity</tt> claim.</t>
        <sourcecode type="tls"><![CDATA[
pointer_item[0].item_type = via_key;
pointer_item[0].key.type = string;
pointer_item[0].key.value = "known_entity";
]]></sourcecode>
      </section>
      <section anchor="matching-lists-and-sequences-by-absolute-position">
        <name>Matching Lists and Sequences by Absolute Position</name>
        <t>The value of an element in an absolute position in a list is accessed using the <tt>array_position</tt> pointer item type.
The <tt>index</tt> value corresponds to the position counting from 0.</t>
        <t>The claim pointer below using the example JSON document above would point at the value <tt>true</tt> as well, the 3rd element of the <tt>service_flags</tt> array.</t>
        <sourcecode type="tls"><![CDATA[
/* pointer_item[0] points to entire array */
pointer_item[0].item_type = via_key; /* 0 */
pointer_item[0].key.type = string;
pointer_item[0].key.value = "service_flags";

/* pointer_item[1] points to 3rd element (true) */
pointer_item[1].item_type = array_position; /* 1 */
pointer_item[1].index = 2;
]]></sourcecode>
        <t>If there is no array, or the array does not have an element at the requested position, the claim pointer does not point at anything.
If the <tt>index</tt> above was instead 7, or the value of <tt>service_flags</tt> was not an array, the claim pointer would not point at any value.</t>
        <t>As previously mentioned, the elements of an X.509 <tt>SEQUENCE</tt> with optional elements (such as <tt>tbsCertificate</tt>) are given a logical position from zero as if all possible optional elements are present.</t>
      </section>
      <section anchor="matching-an-element-in-a-list-by-an-identifier-in-the-list">
        <name>Matching an Element in a List by an Identifier in the List</name>
        <t>The <tt>array_search</tt> claim pointer item type, can search a JSON or CBOR array, or an ASN.1  <tt>SEQUNCE OF</tt>, for the first entry which matched the nested claim matchers in <tt>nested_claim_pointer</tt>.</t>
        <t>The claim pointer below begins by pointing at the value of the entire <tt>nodes</tt> array.
Then, starting from the <tt>nodes</tt> array, its nested claim pointer points at the value of the <tt>processor</tt> object and compares it to the string value "DCBA-10177".
Finding a match, the top-level claim_pointer now points at the first element in the <tt>nodes</tt> array.
Finally, the next claim pointer item looks for a <tt>domain</tt> object in the first element of the <tt>nodes</tt> array.
The claim pointer now points at the value "smart.example".</t>
        <sourcecode type="tls"><![CDATA[
pointer_item[0].item_type = via_key;
pointer_item[0].key.type = string;
pointer_item[0].key.value = "nodes";
/* pointer_item[0] points to entire array of nodes elements */

/* pointer_item[1] searches for an item in the nodes array that has */
/*  "processor" object matching DCBA-10177 using a case insensitive */
/*  comparison                                                      */
pointer_item[1].item_type = via_array_search;
pointer_item[1].claim_match[0].pointer_item[0].item_type = via_key;
pointer_item[1].claim_match[0].pointer_item[0].key.type = string;
pointer_item[1].claim_match[0].pointer_item[0].key.value = "processor";
pointer_item[1].claim_match[0].semantics = string;
pointer_item[1].claim_match[0].match_as = utf8_ci;
pointer_item[1].claim_match[0].test_value = "Dcba-10177";

/* pointer_item[1] ends pointing to 1st element in the node array */
pointer_item[2].item_type = via_key;
pointer_item[2].key.type = string;
pointer_item[2].key.value = "domain";
/* value of pointer_item[2] is "smart.example" */
]]></sourcecode>
        <t>Instead imagine searching for the value of <tt>processor</tt> in the first element that matches the <tt>domain</tt> "smart.example".
We would use the following claim_pointer instead, which would point to the value "DCBA-10177" in the first element's <tt>processor</tt> object.</t>
        <sourcecode type="tls"><![CDATA[
pointer_item[0].item_type = via_key;
pointer_item[0].key.type = string;
pointer_item[0].key.value = "nodes";
/* pointer_item[0] points to entire array of nodes elements */

/* pointer_item[1] searches for an item in the nodes array that has */
/*  "domain" object matching "smart.example" using a domain name    */
/*  comparison                                                      */
pointer_item[1].item_type = via_array_search;
pointer_item[1].claim_match[0].pointer_item[0].item_type = via_key;
pointer_item[1].claim_match[0].pointer_item[0].key.type = string;
pointer_item[1].claim_match[0].pointer_item[0].key.value = "domain";
pointer_item[1].claim_match[0].semantics = domain;
pointer_item[1].claim_match[0].match_as = domain;
pointer_item[1].claim_match[0].test_value = "smart.example";

/* pointer_item[1] ends pointing to 1st element in the node array */
pointer_item[2].item_type = via_key;
pointer_item[2].key.type = string;
pointer_item[2].key.value = "processor";
/* value of pointer_item[2] is "DCBA-10177" */
]]></sourcecode>
        <t>Finally, imagine that the value of the <tt>domain</tt> field was instead "xn--ingnieux-d1a.example", the <tt>match_as</tt> type was "punycode" and the <tt>test_value</tt> was "ingénieux.example".
This would also point to the same value ("DCBA-10177") since the punycode representation of the Internationalized Domain Name (IDN) or "punycode" representation of "ingénieux.example" is "xn--ingnieux-d1a.example".</t>
        <t>Full explanation of comparison rules will be discussed in section <xref target="types-of-comparisons"/>.</t>
      </section>
      <section anchor="matching-multiple-claim-pointers">
        <name>Matching multiple claim pointers</name>
        <t>If no single value in an array element is sufficient to uniquely identify the target element, an <tt>array_search</tt> can search multiple <tt>claim_match</tt> elements.
While implementations may choose a variety of techniques to match multiple items, be aware that the claim matches need to be evaluated together.
One way to do this would be to start with the first item in an array, try each <tt>claim_match</tt> with that item until one of them fails to find a match, stopping at the first item that matches every <tt>claim_match</tt>, or returning no match if none is found.</t>
        <t>The following example presents the value of the processor object for the first element of the nodes item which matches both the domain "smart.example", and the origin country "us".</t>
        <sourcecode type="tls"><![CDATA[
/* pointer_item[0] matches the entire array under the nodes object */
pointer_item[0].item_type = via_key;
pointer_item[0].key.type = string;
pointer_item[0].key.value = "nodes";

/* pointer_item[1] is an array_search with two claim_matches */
/* it will point at the entire array element satisfying both *
pointer_item[1].item_type = via_array_search;

/* first claim_match matches "smart.example" in the domain object */
pointer_item[1].claim_match[0].pointer_item[0].item_type = via_key;
pointer_item[1].claim_match[0].pointer_item[0].key.type = string;
pointer_item[1].claim_match[0].pointer_item[0].key.value = "domain"
pointer_item[1].claim_match[0].semantics = domain
pointer_item[1].claim_match[0].match_as = domain
pointer_item[1].claim_match[0].value = "smart.example"

/* second claim_match matches "us" in the country object in the */
/*   origin object                                              */
pointer_item[1].claim_match[1].pointer_item[0].item_type = via_key;
pointer_item[1].claim_match[1].pointer_item[0].key.type = string;
pointer_item[1].claim_match[1].pointer_item[0].key.value = "origin"
pointer_item[1].claim_match[1].pointer_item[1].item_type = via_key;
pointer_item[1].claim_match[1].pointer_item[1].key.type = string;
pointer_item[1].claim_match[1].pointer_item[1].key.value = "country";
pointer_item[1].claim_match[1].semantics = string;
pointer_item[1].claim_match[1].match = utf8_ci;
pointer_item[1].claim_match[1].value = "us";

/* pointer_item[2] points to the value of the processor object */
pointer_item[2].item_type = via_key;
pointer_item[2].key.type = string;
pointer_item[2].key.value = "processor";
]]></sourcecode>
      </section>
      <section anchor="matching-with-numerical-predicates">
        <name>Matching with Numerical Predicates</name>
        <t>In this example we use the concept of predicates to find an element with a numerical value in designed ranges.
In our example we are looking for an element of the nodes array with a <tt>eur_per_hour</tt> value greater than or equal to 200.</t>
        <artwork><![CDATA[
/* pointer_item[0] points to entire array of nodes elements */
pointer_item[0].item_type = via_key;
pointer_item[0].key.type = string;
pointer_item[0].key.value = "nodes";

/* pointer_item[1] finds the first element with a `eur_per_hour`    */
/*  floating point value greater than or equal to 200.00            */
pointer_item[1].item_type = via_array_search;
pointer_item[1].claim_match[0].pointer_item[0].item_type = via_key;
pointer_item[1].claim_match[0].pointer_item[0].key.type = string;
pointer_item[1].claim_match[0].pointer_item[0].key.value = "processor";
pointer_item[1].claim_match[0].semantics = number;
pointer_item[1].claim_match[0].match_as = finite_float;
pointer_item[1].claim_match[0].operation = greater_than_or_equal;
pointer_item[1].claim_match[0].test_value = 200.0

/* pointer_item[1] ends pointing to 1st element in the node array */
]]></artwork>
      </section>
      <section anchor="matching-parts-of-uris-and-email-addresses">
        <name>Matching Parts of URIs and email addresses</name>
        <t>Standard URIs and email addresses have a complicated but predictable internal structure.
It is often useful to compare a specific component of a URI or an email address to a specific value.</t>
        <t>In the example fragments below the first <tt>claim_match</tt> will match when the domain of the URI matches "example.com".
The second matches when the email hostpart matches "example.com".
The last one matches when a MIMI URI where the first item in the URI path matches "r" (room).</t>
        <sourcecode type="json"><![CDATA[
{
    "room-uri": "mimi://example.com/r/clubhouse",
    "email-checked": "alice@example.com"
}
]]></sourcecode>
        <sourcecode type="tls"><![CDATA[
/* first example */
pointer_item[0].item_type = via_key;
pointer_item[0].key.type = string;
pointer_item[0].key.value = "room-uri";
semantics = uri;
match_as = domain;
test_value = "example.com";

/* second example */
pointer_item[0].item_type = via_key;
pointer_item[0].key.type = string;
pointer_item[0].key.value = "email-checked";
semantics = uri;
match_as = hostpart;
test_value = "example.com";

/* third example */
claim_match[0].pointer_item[0].item_type = via_key;
claim_match[0].pointer_item[0].key.type = string;
claim_match[0].pointer_item[0].key.value = "room-uri";
claim_match[0].semantics = uri;
claim_match[0].match_as = scheme;
claim_match[0].test_value = "mimi";
claim_match[1].pointer_item[0].item_type = via_key;
claim_match[1].pointer_item[0].key.type = string;
claim_match[1].pointer_item[0].key.value = "room-uri";
claim_match[1].semantics = uri;
claim_match[1].match_as = uri_path;
claim_match[1].operation = path_slice;
claim_match[1].path_index = 0
claim_match[1].test_value = "r";
]]></sourcecode>
      </section>
      <section anchor="matching-arbitrary-substrings">
        <name>Matching Arbitrary Substrings</name>
        <t>mimi://example.com/u/46133c9e-df4c-4c88-91d2-00a527bdd0f7</t>
        <artwork><![CDATA[
value_semantics = uri,
match_as = uripath,
operation = substring,
  start = 3,
  length = 36
test_value = "46133c9e-df4c-4c88-91d2-00a527bdd0f7"
]]></artwork>
      </section>
    </section>
    <section anchor="match-syntax-definition">
      <name>Match Syntax Definition</name>
      <sourcecode type="tls"><![CDATA[
enum {
    reserved (0),
    x509 (1),
    jwt (2),
    cwt(3),
    (255)
} ClaimFamily;

enum {
    null (0),
    number (1),
    int (2),
    float (3),
    bool (4),
    date (5),
    bytes (6),
    string (7),
    domain (8),
    uri (9),
    https_uri (10),
    mimi_uri (11),
    email (12),
    (255)
} ClaimSemantics;

enum {
    exists (0),
    number (1),
    int (2),
    uint (3),
    float (4),
    finite_float (5),
    bool (6),
    secs_since_epoch (7),
    iso8601 (8),
    bytes (9),
    hex (10),
    base64 (11),
    base64url (12),
    der (13),
    pem (14),
    ipv4 (15),
    ipv6 (16),
    deterministic_cbor (17),
    utf8 (18),
    utf8_ci (19),
    nfc (20),
    nfd (21),
    canonical_json (22),
    domain (23),
    punycode (24),
    email_address (25),
    generic_uri (26),
    https_uri (27),
    userpart (28),
    hostpart (29),
    uri_path (30),
    mimi_uri (31),
    user_id (32),
    device_id (33),
    room_id (34),
    length_bytes (35),
    length_chats (36),
    (255)
} MatchAs;

enum {
    member_name (0),
    array_position (1),
    array_search (2),
    tagged_value (3), /* CBOR only */
    bstr_encoded (4), /* CBOR only */
    (255)
} ClaimItemType;




struct {
    JwtItemType item_type;
    select (item_type) {
        case member_name:
            opaque name<V>;
        case array_index:
            uint index;
    }
} JwtToken;

struct {
    JwtToken claim_pointer<V>;
} JwtClaimRoot;

enum {
    map_key (0),
    array_position (1),
    array_search (2),
    tagged_value (3),
    bstr_encoded (4),
    any (5),
    (255)
} ItemType;

struct {
    ItemType item_type;
    select (item_type) {
        case map_key:
            opaque opaque_key<V>;
        case array_position:
            uint index;
        case array_search:
            ClaimMatcher nested_matches<V>;
        case tagged_value:
            uint tag;
        case bstr_encoded:
            struct {};
        case any:
            struct {};
    };
} ClaimPointerItem;

enum {
    equal (0),
    less_than (1),
    less_than_or_equal (2),
    greater_than (3),
    greater_than_or_equal (4),
    contains (7),
    starts_with (8),
    ends_with (9),
    substring (10),
    path_slice (11),
} OperationType;

struct {
  OperationType operation_type;
  select (operation_type) {
    case equal:
    case less_than:
    case less_than_or_equal:
    case greater_than:
    case greater_than_or_equal:
    case contains:
        struct {};
    case starts_with:
        optional<uint> length;
    case ends_width:
        optional<uint> length;
    case substring:
        uint start_position;
        optional<uint> length;
    case path_slice:
        uint path_index;
  };
} Operation;

struct {
    ClaimPointerItem claim_pointer<V>;
    ClaimSemantics claim_semantics;
    MatchAs match_as;
    optional<Operation> operation;
    opaque test_value<V>;
} ClaimMatcher;

struct {
    ClaimFamily claim_family;
    select (claim_family) {
        case json:
            String object_name;
        case cbor:
            Bytes cbor_encoding;
        case asn1:
            Bytes der_encoded_oid;
    };
} MapKey;

struct {
  bool claim_exists;
  select (claim_exists) {
    case false:
      select {};
    case true:
      ClaimFamily claim_family;
      select (claim_family) {
        case json:
          JsonType json_type;
          select (json_type) {
            case number:
              Double value;
            case string:
            case object:
            case array:
              Bytes value;
            case true:
            case false:
            case null:
              struct {};
          };
        case cbor:
          Bytes cbor_encoding;
        case asn1:
          /* we might need another option */
          Bytes der_encoding;
      };
  };
} FoundValue;


struct {
    CborType type;
    select (type) {
        case no_match:
            struct {};
        case uint:
        case nint:
            uint64 value;
        case float
            Double value;
        case array:
            CborValue elements<V>;
        case map:
            CborKeyAndValue map_entries<V>;
        case text_string:
            Bytes value;
        case byte_string:
            Bytes value;
        case tag:
            uint64 tag;
            CborValue value;
        case undefined:
            select {};
        case simple:
            uint8 value;
    };
} CborValue;

struct {
    CborValue key;
    CborValue value;
} CborKeyAndValue;

enum {
    no_match (0),
    number (1),
    string (2),
    object (3),
    array (4),
    true (5),
    false (6),
    null (7)
    (255)
} JsonType;

enum {
    uint (0),
    nint (1),
    array (2),
    map (3),
    byte_string (4),
    text_string (5),
    tag (6),
    simple (7),
    true (8),
    false (9),
    null (10),
    undefined (11),
    float (12),
    no_match (13),
    (255)
} CborType;

struct {
    CwtToken claim_pointer<V>;
} CwtClaimRoot;

struct {
    ClaimFamily claim_family;
    select (claim_family) {
        case x509:
            opaque oid<V>;
        case jwt:
            JwtClaimRoot claim_root;
        case cwt:
            CwtClaimRoot claim_root;
    }
    ClaimSemantics claim_semantics;
    MatchAs match_as;
    bool match_any_in_list;
    opaque target_value<V>;
} Claim;
]]></sourcecode>
    </section>
    <section anchor="types-of-comparisons">
      <name>Types of comparisons</name>
      <t>TODO</t>
      <artwork><![CDATA[
`exists`
number,
int,
uint,
float,
finite_float,
bool,
`secs_since_epoch` convert into a Javascript date (seconds since the epoch )
    iso8601,
    bytes (0),
    hex,
    base64,
    base64url,
    der,
    pem,
    ipv4,
    ipv6,
    deterministic_cbor,
    utf8 (1),
    utf8_ci ,
    nfc,
    nfd,
    canonical_json,
    domain (2),
    punycode,
    email_address,
    generic_uri,
    https_uri,
    userpart (6),
    hostpart (7),
    uri_path (8),
    mimi_uri,
    user_id (3),
    device_id (4),
    room_id (5),
    (255)
]]></artwork>
    </section>
    <section anchor="more-examples">
      <name>More examples</name>
      <section anchor="cbor-examples">
        <name>CBOR Examples</name>
        <sourcecode type="cbor-diag"><![CDATA[
{                                   # contents are level 1
  1: "https://issuer.example",
  ...
  502: 1(1549560720),               # tagged value is level 2
  504: [                            # contents are level 2
    {                               # contents are level 3
      ...
      501: "DCBA-101777",
      503: {                        # contents are level 4
        1: "us",
        ...
      },
      505: 4(                       # decimal fraction tag
        [                           #   273.15
          -2,
          27315                     # level 5
        ]
      )
    },
    ...
  ],
  509: [false, false, true, false]
}
]]></sourcecode>
        <section anchor="cbor-example-with-tagged-value-accessed-directly-as-opaquevalue">
          <name>CBOR example with tagged value accessed directly as opaque_value</name>
          <sourcecode type="tls"><![CDATA[
pointer_item[0].item_type = via_key;
pointer_item[0].key.type = uint;
pointer_item[0].key.value = 502;
]]></sourcecode>
        </section>
        <section anchor="cbor-example-parsing-into-tagged-value">
          <name>CBOR example parsing into tagged value</name>
          <sourcecode type="tls"><![CDATA[
pointer_item[0].item_type = via_key;
pointer_item[0].key.type = uint;
pointer_item[0].key.value = 502;
pointer_item[1].item_type = tagged_value;
pointer_item[1].tag;
]]></sourcecode>
        </section>
        <section anchor="cbor-example-with-custom-simple-values-maybe-not-needed">
          <name>CBOR example with custom simple values ?? - maybe not needed</name>
        </section>
      </section>
      <section anchor="x509-examples">
        <name>X.509 Examples</name>
        <artwork><![CDATA[
SEQUENCE (1 elem)
  SET (1 elem)
    SEQUENCE (2 elem)
      OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component)
      PrintableString github.com
...
    SEQUENCE (3 elem)
      OBJECT IDENTIFIER 2.5.29.15 keyUsage (X.509 extension)
      BOOLEAN true
      OCTET STRING (4 byte) 03020780
        BIT STRING (1 bit) 1
    SEQUENCE (3 elem)
      OBJECT IDENTIFIER 2.5.29.19 basicConstraints (X.509 extension)
      BOOLEAN true
      OCTET STRING (2 byte) 3000
        SEQUENCE (0 elem)
    SEQUENCE (2 elem)
      OBJECT IDENTIFIER 2.5.29.37 extKeyUsage (X.509 extension)
      OCTET STRING (22 byte) 301406082B0601050507030106082B06010505070302
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 1.3.6.1.5.5.7.3.1 serverAuth (PKIX key purpose)
          OBJECT IDENTIFIER 1.3.6.1.5.5.7.3.2 clientAuth (PKIX key purpose)
...
    SEQUENCE (2 elem)
      OBJECT IDENTIFIER 2.5.29.17 subjectAltName (X.509 extension)
      OCTET STRING (30 byte) 301C820A6769746875622E636F6D820E7777772E6769746875622E636F6D
        SEQUENCE (2 elem)
          [2] (10 byte) github.com
          [2] (14 byte) www.github.com
]]></artwork>
        <section anchor="simple-x509-example-cn">
          <name>Simple X.509 example (CN)</name>
        </section>
        <section anchor="x509-matching-one-dns-item-in-issueraltname">
          <name>X.509 Matching one DNS item in issuerAltName</name>
        </section>
        <section anchor="x509-matching-one-uri-part-of-subjectaltname">
          <name>X.509 matching one URI part of subjectAltName</name>
        </section>
        <section anchor="x509-matching-one-uri-part-of-subjectaltname-with-a-domain-substring">
          <name>X.509 matching one URI part of subjectAltName with a domain substring</name>
          <sourcecode type="tls"><![CDATA[
pointer_item[0].item_type = via_key;
pointer_item[0].key.type = oid;
pointer_item[0].key.value = 0x551d11; /* 2.5.29.17 = subjectAltName */
pointer_item[1].item_type = array_search;
pointer_item[1].nested_matches[0].pointer_item[0].item_type = any;
pointer_item[1].nested_matches[0].pointer_item[1].item_type = array_position;
pointer_item[1].nested_matches[0].pointer_item[1].index = 6; /* URI type */
pointer_item[1].claim_semantics = uri;
pointer_item[1].match_as = host_part;
pointer_item[1].operation = substring;
pointer_item[1].start_position = 0;
pointer_item[1].length = 11;
pointer_item[1].test_value = "example.org"
]]></sourcecode>
          <artwork><![CDATA[
claim_pointer = [
  [
    type = oid,
    value = 2.5.29.17 = 0x55 1d 11   # subjectAltName
  ],
  [
    type = array_serach,
    nested_claim_pointer = [
      [
      ]
    ],
    semantics = uri,
    match_as = domain / userpart / user_id
    test_value = "provider.example"
    MATCH
  ] /* value is [ ["URI", "https://provider.example/path"] ] */
],
semantics = uri,
match_as = exists,
test_value = true
MATCH

try email?  match domain in nester pointer, match on user in main match??
]]></artwork>
          <t>RFC5820 matches only host part of URIs??</t>
        </section>
      </section>
    </section>
    <section anchor="old-text-on-preauth">
      <name>Old text on Preauth</name>
      <t>Preauthorized users are MIMI users and external senders that have authorization to adopt a role in a room by virtue of certain credential claims or properties, as opposed to being individually enumerated in the participant list.
For example, a room for employee benefits might be available to join with the regular participant role to all full-time employees with a residence in a specific country; while anyone working in the human resources department might be able to join the same room as a moderator.
This data structure is consulted in two situations: for external joins (external commits) and external proposals when the requester does not already appear in the participant list; and separately when an existing participant explicitly tries to change its <em>own</em> role.</t>
      <ul empty="true">
        <li>
          <t>Only consulting Preauthorized users in these cases prevents several attacks. For example, it prevents an explicitly banned user from rejoining a group based on a preauthorization.</t>
        </li>
      </ul>
      <t>PreAuthData is the format of the <tt>data</tt> field inside the ComponentData struct for the Preauthorized Participants component in the <tt>application_data</tt> GroupContext extension.</t>
      <t>The individual <tt>PreAuthRoleEntry</tt> rules in <tt>PreAuthData</tt> are consulted one at a time.
A <tt>PreAuthRoleEntry</tt> matches for a requester when every <tt>Claim.claim_id</tt> has a corresponding claim in the requester's MLS Credential which exactly matches the corresponding <tt>claim_value</tt>.
When the rules in a Preauthorized users struct match multiple roles, the requesting client receives the first role which matches its claims.</t>
      <ul empty="true">
        <li>
          <t><strong>TODO</strong>: refactor Claims</t>
        </li>
      </ul>
      <sourcecode type="tls-presentation"><![CDATA[
struct {
  /* MLS Credential Type of the "claim"  */
  CredentialType credential_type;
  /* the binary representation of an X.509 OID, a JWT claim name  */
  /* string, or the CBOR map claim key in a CWT (an int or tstr)  */
  opaque id<V>;
} ClaimId;

struct {
  ClaimId claim_id;
  opaque claim_value<V>;
} Claim;

struct {
  /* when all claims in the claimset are satisfied, the claimset */
  */ is satisfied */
  Claim claimset<V>;
  Role target_role;
} PreAuthRoleEntry;

struct {
  PreAuthRoleEntry preauthorized_entries<V>;
} PreAuthData;

PreAuthData preauth_list;
PreAuthData PreAuthUpdate;
]]></sourcecode>
      <!--
struct {
  select (Credential.credential_type) {
    case basic:
        struct {}; /* only identity */
    case x509:
        /* ex: subjectAltName (2.5.29.17) = hex 06 03 55 1d 1e */
        opaque oid<V>;
        /* for sequence or set types, the specific item (1-based) */
        /* in the collection. zero means any item in a collection */
        uint8 ordinal;
    case jwt:
        opaque json_path<V>;
    case cwt:
        CborKeyNameOrArrayIndex cbor_path<V>;
  };
} Claim;

struct {
    /* a CBOR CDE encoded integer, tstr, bstr, or tagged version of */
    /* any of those map key types. Ex: -1 = 0x20, "hi" = 0x626869,  */
    /* 1(3600) = 0xC1190E10 */
    opaque cbor_encoded_claim<V>;
    optional uint array_index;
} CborKeyNameOrArrayIndex;
-->

<t>PreAuthUpdate (which has the same format as PreAuthData) is the format of the <tt>update</tt> field inside the AppDataUpdate struct in an AppDataUpdate Proposal for the Preauthorized Participants component.
If the contents of the <tt>update</tt> field are valid and if the proposer is authorized to generate such an update, the value of the <tt>update</tt> field completely replaces the value of the <tt>data</tt> field.</t>
      <ul empty="true">
        <li>
          <t>As with the definition of roles, in MIMI it is not expected that the definition of Preauthorized users would change frequently. Instead the claims in the underlying credentials would be modified without modifying the preauthorization policy.</t>
        </li>
      </ul>
      <t>Changing Preauthorized user definitions is sufficiently disruptive, that an update to this component is not valid if it appears in the same commit as any Participant List change, except for user removals.</t>
      <t>Because the Preauthorized users component usually authorizes non-members, it is also a natural choice for providing concrete authorization for policy enforcing systems incorporated into or which run in coordination with the MIMI Hub provider or specific MLS Distribution Services. For example, a preauthorized role could allow the Hub to remove participants and to ban them, but not to add any users or devices. This unifies the authorization model for members and non-members.</t>
    </section>
    <section anchor="security-considerations">
      <name>Security Considerations</name>
      <t>TODO Security</t>
    </section>
    <section anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
    </section>
  </middle>
  <back>
    <references anchor="sec-normative-references">
      <name>Normative References</name>
      <reference anchor="I-D.ietf-mimi-room-policy">
        <front>
          <title>Room Policy for the More Instant Messaging Interoperability (MIMI) Protocol</title>
          <author fullname="Rohan Mahy" initials="R." surname="Mahy">
            <organization>Rohan Mahy Consulting Services</organization>
          </author>
          <date day="18" month="December" year="2025"/>
          <abstract>
            <t>   This document describes a set of concrete room policies for the More
   Instant Messaging Interoperability (MIMI) Working Group.  It
   describes several independent properties and policy attributes which
   can be combined to model a wide range of chat and multimedia
   conference types.

            </t>
          </abstract>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-ietf-mimi-room-policy-03"/>
      </reference>
      <reference anchor="RFC9420" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9420.xml">
        <front>
          <title>The Messaging Layer Security (MLS) Protocol</title>
          <author fullname="R. Barnes" initials="R." surname="Barnes"/>
          <author fullname="B. Beurdouche" initials="B." surname="Beurdouche"/>
          <author fullname="R. Robert" initials="R." surname="Robert"/>
          <author fullname="J. Millican" initials="J." surname="Millican"/>
          <author fullname="E. Omara" initials="E." surname="Omara"/>
          <author fullname="K. Cohn-Gordon" initials="K." surname="Cohn-Gordon"/>
          <date month="July" year="2023"/>
          <abstract>
            <t>Messaging applications are increasingly making use of end-to-end security mechanisms to ensure that messages are only accessible to the communicating endpoints, and not to any servers involved in delivering messages. Establishing keys to provide such protections is challenging for group chat settings, in which more than two clients need to agree on a key but may not be online at the same time. In this document, we specify a key establishment protocol that provides efficient asynchronous group key establishment with forward secrecy (FS) and post-compromise security (PCS) for groups in size ranging from two to thousands.</t>
          </abstract>
        </front>
        <seriesInfo name="RFC" value="9420"/>
        <seriesInfo name="DOI" value="10.17487/RFC9420"/>
      </reference>
      <reference anchor="RFC7519">
        <front>
          <title>JSON Web Token (JWT)</title>
          <author fullname="M. Jones" initials="M." surname="Jones"/>
          <author fullname="J. Bradley" initials="J." surname="Bradley"/>
          <author fullname="N. Sakimura" initials="N." surname="Sakimura"/>
          <date month="May" year="2015"/>
          <abstract>
            <t>JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.</t>
          </abstract>
        </front>
        <seriesInfo name="RFC" value="7519"/>
        <seriesInfo name="DOI" value="10.17487/RFC7519"/>
      </reference>
      <reference anchor="RFC8392">
        <front>
          <title>CBOR Web Token (CWT)</title>
          <author fullname="M. Jones" initials="M." surname="Jones"/>
          <author fullname="E. Wahlstroem" initials="E." surname="Wahlstroem"/>
          <author fullname="S. Erdtman" initials="S." surname="Erdtman"/>
          <author fullname="H. Tschofenig" initials="H." surname="Tschofenig"/>
          <date month="May" year="2018"/>
          <abstract>
            <t>CBOR Web Token (CWT) is a compact means of representing claims to be transferred between two parties. The claims in a CWT are encoded in the Concise Binary Object Representation (CBOR), and CBOR Object Signing and Encryption (COSE) is used for added application-layer security protection. A claim is a piece of information asserted about a subject and is represented as a name/value pair consisting of a claim name and a claim value. CWT is derived from JSON Web Token (JWT) but uses CBOR rather than JSON.</t>
          </abstract>
        </front>
        <seriesInfo name="RFC" value="8392"/>
        <seriesInfo name="DOI" value="10.17487/RFC8392"/>
      </reference>
      <reference anchor="RFC5280">
        <front>
          <title>Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile</title>
          <author fullname="D. Cooper" initials="D." surname="Cooper"/>
          <author fullname="S. Santesson" initials="S." surname="Santesson"/>
          <author fullname="S. Farrell" initials="S." surname="Farrell"/>
          <author fullname="S. Boeyen" initials="S." surname="Boeyen"/>
          <author fullname="R. Housley" initials="R." surname="Housley"/>
          <author fullname="W. Polk" initials="W." surname="Polk"/>
          <date month="May" year="2008"/>
          <abstract>
            <t>This memo profiles the X.509 v3 certificate and X.509 v2 certificate revocation list (CRL) for use in the Internet. An overview of this approach and model is provided as an introduction. The X.509 v3 certificate format is described in detail, with additional information regarding the format and semantics of Internet name forms. Standard certificate extensions are described and two Internet-specific extensions are defined. A set of required certificate extensions is specified. The X.509 v2 CRL format is described in detail along with standard and Internet-specific extensions. An algorithm for X.509 certification path validation is described. An ASN.1 module and examples are provided in the appendices. [STANDARDS-TRACK]</t>
          </abstract>
        </front>
        <seriesInfo name="RFC" value="5280"/>
        <seriesInfo name="DOI" value="10.17487/RFC5280"/>
      </reference>
      <reference anchor="RFC2119" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml">
        <front>
          <title>Key words for use in RFCs to Indicate Requirement Levels</title>
          <author fullname="S. Bradner" initials="S." surname="Bradner"/>
          <date month="March" year="1997"/>
          <abstract>
            <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
          </abstract>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="2119"/>
        <seriesInfo name="DOI" value="10.17487/RFC2119"/>
      </reference>
      <reference anchor="RFC8174" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml">
        <front>
          <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
          <author fullname="B. Leiba" initials="B." surname="Leiba"/>
          <date month="May" year="2017"/>
          <abstract>
            <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t>
          </abstract>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="8174"/>
        <seriesInfo name="DOI" value="10.17487/RFC8174"/>
      </reference>
      <reference anchor="I-D.ietf-cbor-serialization">
        <front>
          <title>CBOR Serialization and Determinism</title>
          <author fullname="Laurence Lundblade" initials="L." surname="Lundblade">
            <organization>Security Theory LLC</organization>
          </author>
          <date day="3" month="July" year="2026"/>
          <abstract>
            <t>   This document defines two CBOR serializations: "preferred-plus
   serialization" and "deterministic serialization."  It also introduces
   the term "general serialization" to name the complete set of all
   serializations defined in RFC 8949.  Together, these three form a set
   of serializations that cover the majority of CBOR serialization use
   cases.

   These serializations are largely compatible with those widely
   implemented by the CBOR community.

            </t>
          </abstract>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-ietf-cbor-serialization-07"/>
      </reference>
    </references>
    <?line 1032?>

<section anchor="more-example-documents-to-match-against">
      <name>More example documents to match against</name>
      <sourcecode type="json"><![CDATA[
{
  "abc": "foo"
  "def": [
     "carrot",
     "tomato",
     2.5,
     true
  ],
  "ghi": [
    [
    ],
    [
    ],
    {
      "roles": ["Employees", "Boston", "PR", "Manager"],
      "start_date": "01-Apr-2021"
    }
  ],
  "jkl": {
     "AAA": "all \"a\"'s",
     "BBB": "all b's"
  },
  "xyz": 1.0
}
]]></sourcecode>
    </section>
    <section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>TODO acknowledge.</t>
    </section>
  </back>
  <!-- ##markdown-source:
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
IwsbkNcJdnAqLmNW8jBe+sN45Q3DmJE2152NcUhkxcQ3LJ57ldiWCIkKdR/y
4I58D+73tggwPFfvMcXj6jT9+a4kdFz/UkDICFCv2qhc7eihave/0fwiu0Fe
JeheD/AgsW930dbNquWlY73qSqdEdTaaBsHV+fE5B2uv2fK4livHWgGQrBUs
6b/EEfDHiby1AgSqFVyXQ23XnIQ8QyeTlv2+C29DTJezKCRSyYs0ubPBl2N0
PLUkQOcF5zS3TqNPbhiuFJIz0TgTiLMxOBt+Wxd584JupZibibeZUFtdlK0U
YCvF12pCa5WoWimgVo6lmYibCaWZeJuJpOlprwNp5RhaNYSmBY2JoPlxDY6Z
Y9AcL4jSWXBo9YACUyfmDQbPKanGOA4nn5P+xua+6T0l781Ot7+vek2b1Gaj
VWmfoxF6S03u5K/Z6W4/kPlmLXSflfpmXd6bnW5vTb6bne5Wfaqb9c3bZDe9
JyS52enu7Kvt5toOxtEonlMerZC3qgMmTXsPoe0L+L+TEYf/tfst5wk+93bW
VOax2Lo/yS8WDtX8Oijsn5JT5wvNr2bzFO28ddnDJGUYx1lESfAxZx2H2ajE
73cUC8Xqw2vKwNx6L1oN8DD76awTiVh3EP90EB/a2OSGAqslyUR9gDajZV6k
c23dSCbL169VG48QDPlyOM66xSiSU/2ePAoCk0ms2SNTH/no8uTKfcQXulDf
eavU+ZvvTo6u1OnxydnV6dvTkwvV7+x0tjtbkueGD5hAv/2uOj6zm2F0/Q9g
tdEmG4lJyBWPeLuinpK2660ndN1/BfMKLebvc0wQ3uQhm4yHuvKb8/N3J4dn
fEmotHd0BaO+vLo4PfsjyHzSrBuqu9Xtd/deds10e3NqC/XUMC42SB5/Dpyv
OPf8ESdco22Cnw1vX+Dd6nYtrBak7mfTEgDd2kOA/vQYTksAWYh6293d7sv+
G/hvrwtitbsHWO3VvOvXQO7DWA9nr7PV2e30ANqdzh787ilakc4Ol6jwP/zp
9C+URUuS4j2vrT6YoXgmaF1bVTZ9IlZ7e8pP3/9ExG51LWKPXva7h7t7u6/2
tndf7u3s9vsnu1u7b3eP4f3JHv2DNzXfn4Ro3IwMjpB050zNchE9We7u7jpO
MSO6LllC6eGxCGsenW3wZ35vdlrgrrHjs0uzI4zNG0GSFvZcZ+7W4V1jmeSy
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

-->

</rfc>
