<?xml version="1.0" encoding="utf-8"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     docName="draft-schrock-ep-evidence-record-01"
     category="info" ipr="trust200902" submissionType="IETF"
     version="3" tocInclude="true" sortRefs="true" symRefs="true">
  <front>
    <title abbrev="EP Evidence Records">Long-Term, Crypto-Agile Preservation of Authorization Evidence (EP-EVIDENCE-RECORD)</title>
    <seriesInfo name="Internet-Draft" value="draft-schrock-ep-evidence-record-01"/>
    <author fullname="Iman Schrock">
      <organization>EMILIA Protocol, Inc.</organization>
      <address>
        <postal><country>US</country></postal>
        <email>team@emiliaprotocol.ai</email>
      </address>
    </author>
    <date year="2026" month="July" day="6"/>
    <area>sec</area>
    <keyword>authorization receipts</keyword>
    <keyword>long-term preservation</keyword>
    <keyword>crypto-agility</keyword>
    <keyword>evidence record</keyword>
    <keyword>AI agents</keyword>
    <abstract>
      <t>Regulations increasingly require that records of who authorized a
      high-risk action be retained for years (e.g. five years under DORA, six
      under HIPAA and SEC 17a-4). Any fixed signature or hash algorithm used to
      protect such a record weakens over time; a receipt signed today with
      Ed25519 over SHA-256 may be cryptographically attackable before its
      retention period ends. This document defines EP-EVIDENCE-RECORD, an
      OPTIONAL profile that preserves the verifiability of EMILIA Protocol
      authorization receipts (and other artifacts) across algorithm aging, using
      a renewal chain in the style of the Evidence Record Syntax [RFC4998]. Each
      renewal time-attests the entire prior renewal under a fresh, stronger
      algorithm before the older one is broken, so an unbroken chain links the
      original artifact to the most recent renewal. The record is offline-
      verifiable, fail-closed, and maintained as cross-language conformance
      vectors that three reference verifiers (JavaScript, Python, Go) are
      required to agree on. Those verifiers live in one repository, a
      cross-language consistency check, not clean-room independent
      implementations; independent implementations remain future
      interoperability evidence. This revision additionally defines two
      OPTIONAL companion profiles, EP-WITNESS-v1 witness cosignatures over a
      transparency log's committed checkpoint head and an independent RFC 3161
      time attestation verified offline against a relying-party-pinned
      time-stamping authority key; both are implemented today in the JavaScript
      reference verifier only.</t>
    </abstract>
    <note><name>Discussion</name><t>This document depends on
    [draft-schrock-ep-authorization-receipts] and uses its canonicalization and
    terminology without restating them.</t></note>
  </front>
  <middle>
    <section anchor="intro"><name>Introduction</name>
      <t>An EMILIA Protocol (EP) authorization receipt
      [draft-schrock-ep-authorization-receipts] is offline-verifiable evidence
      that a named human authorized a specific high-risk action. Compliance
      regimes require such evidence to be retained for years. Over that horizon
      the cryptography protecting it ages: hash functions succumb to collision
      attacks, signature algorithms to advances including cryptanalytically
      relevant quantum computers. A receipt that verifies today may not verify,
      or may not be trustworthy, a decade from now under the algorithm it was
      sealed with.</t>
      <t>This is a solved problem in long-term archiving: the Evidence Record
      Syntax <xref target="RFC4998"/> preserves data integrity across algorithm changes by
      periodically re-protecting the data, and the prior protection, under a
      newer algorithm before the old one is broken. EP-EVIDENCE-RECORD applies
      that idea to EP receipts with EP's own time-attestation primitive, so the
      result stays offline-verifiable with no new trust dependencies.</t>
      <section anchor="scope"><name>Scope and non-goals</name>
        <t>EP-EVIDENCE-RECORD preserves the *verifiability over time* of an
        artifact it is given (typically an EP receipt, but any byte string by its
        hash). It does NOT establish that the artifact was correct, nor that a
        renewal actually occurred before the prior algorithm was broken in the
        wild -- that is an operational discipline (<xref target="security"/>). It defines no new
        signature or hash algorithm; it composes existing ones over time.</t>
      </section>
    </section>

    <section anchor="terminology"><name>Terminology</name>
      <t>The key words "MUST", "MUST NOT", "SHOULD", and "MAY" 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.</t>
      <dl>
        <dt>Protected artifact</dt>
        <dd>the byte string whose long-term verifiability is being preserved,
        referenced only by its hash (`protected_hash`).</dd>
        <dt>Archive timestamp</dt>
        <dd>one renewal: an EP time-attestation by an independent, key-pinned
        time authority over a stated `hashed` value.</dd>
        <dt>Renewal chain</dt>
        <dd>the ordered list of archive timestamps, each (after the first)
        covering the entire previous archive timestamp under a possibly stronger
        hash algorithm.</dd>
      </dl>
    </section>

    <section anchor="model"><name>The renewal chain</name>
      <sourcecode type="json"><![CDATA[
{
  "@version": "EP-EVIDENCE-RECORD-v1",
  "protected_hash": "sha256:<hex>",
  "archive_timestamps": [
    { "time_attestation": { ... hashed = protected_hash ... } },
    { "time_attestation": { ... hashed = sha384(canon(prev)) ... } }
  ]
}
]]></sourcecode>
      <ul>
        <li>`@version` (REQUIRED) MUST be "EP-EVIDENCE-RECORD-v1".</li>
        <li>`protected_hash` (REQUIRED) the algorithm-tagged hash of the
        protected artifact (e.g. an EP receipt).</li>
        <li>`archive_timestamps` (REQUIRED, non-empty) the renewal chain, in
        order. The FIRST entry's time-attestation MUST be over `protected_hash`.
        Each LATER entry's attested `hashed` value MUST equal the algorithm-
        agile hash of the canonical serialization (JCS <xref target="RFC8785"/>) of the
        immediately preceding archive timestamp.</li>
      </ul>
      <t>Because renewal i covers the whole of renewal i-1, an unbroken chain
      links the protected artifact to the most recent renewal even across a
      change of hash algorithm (e.g. SHA-256 then SHA-384). This is the Archive
      Timestamp Chain concept of [RFC4998], expressed with EP time-attestations.
      A new renewal is appended under a fresh, stronger algorithm whenever the
      current algorithm's margin is judged to be eroding, BEFORE it is broken.</t>
    </section>

    <section anchor="verify"><name>Verification algorithm</name>
      <t>A verifier MUST proceed fail-closed and return invalid on any failure:</t>
      <ol>
        <li>`version_ok` -- `@version` equals "EP-EVIDENCE-RECORD-v1".</li>
        <li>`protected_bound` (when the relying party supplies the artifact)
        -- `protected_hash` equals the hash the relying party independently
        computes over the artifact it holds.</li>
        <li>`chain_nonempty` -- at least one archive timestamp is present.</li>
        <li>`all_timestamps_valid` -- every renewal's EP time-attestation verifies
        under a pinned, independent time authority's key.</li>
        <li>`chain_linked` -- the first renewal covers `protected_hash`; each later
        renewal's attested `hashed` equals the algorithm-agile hash of the prior
        archive timestamp's canonical serialization.</li>
        <li>`monotonic_time` -- attested times strictly increase along the chain.</li>
      </ol>
      <t>The record is valid iff all applicable checks pass. Verification requires
      no network and no live service.</t>
    </section>

    <section anchor="agility"><name>Crypto-agility</name>
      <t>Hash algorithms are carried as algorithm-tagged values
      (e.g. `sha256:`, `sha384:`, `sha512:`); supported renewal hashes are
      SHA-256, SHA-384, and SHA-512, and the set is extensible as stronger
      functions are standardized. Each renewal's time-attestation MAY use a
      different signature algorithm from earlier renewals, including post-quantum
      signatures once profiled, so the chain migrates forward without invalidating
      earlier links. The verifier selects the hash function by the tag, not by
      assumption.</t>
    </section>

    <section anchor="witness"><name>Witness Cosignatures (EP-WITNESS-v1)</name>
      <t>Evidence intended to outlive its operator should not rest on that
      operator's log signature alone. A transparency-log operator signs its own
      checkpoint `{tree_size, root_hash, log_key_id, ...}`; a single operator
      signature does not make a split view (equivocation) detectable, because
      the operator can sign two internally-consistent but divergent heads and
      present one to each of two verifiers. EP-WITNESS-v1 is an OPTIONAL
      companion profile in which an independent witness cosigns the log's
      committed checkpoint bytes.</t>
      <section anchor="witness-construction"><name>Construction</name>
        <ul>
          <li>The committed checkpoint is the checkpoint object with the log's
          own `log_signature` field removed -- exactly the bytes the log itself
          signed. A witness cosignature MUST be an Ed25519 signature over the
          SHA-256 digest of the domain separation tag followed by the JCS
          <xref target="RFC8785"/> canonical serialization of the committed
          checkpoint.</li>
          <li>The domain separation tag MUST be the UTF-8 string
          "EP-WITNESS-COSIGN-v1" followed by a single zero octet. The log's own
          signature is computed over the untagged canonical bytes (which begin
          with 0x7b and never contain a zero octet), so the two pre-images are
          disjoint: a witness cosignature can never be presented as, or
          confused with, the log signature, and vice versa, even if the same
          key were misconfigured into both roles.</li>
          <li>Witness identity is a self-certifying key fingerprint:
          `witness_id` MUST be the string "witness:sha256:" followed by the
          first 16 lowercase hex characters of the SHA-256 digest of the
          witness's Ed25519 public key in SPKI DER form, so anyone holding the
          public key can recompute and confirm the identifier.</li>
          <li>A cosignature envelope MUST carry `witness_id` and a base64url
          Ed25519 `signature`; it MAY echo the head it cosigned (`tree_size`,
          `root_hash`, `log_key_id`) and MAY carry an `alg` field, which MUST
          equal "EP-WITNESS-v1" when present.</li>
        </ul>
      </section>
      <section anchor="witness-verify"><name>Verification</name>
        <t>Verification is fail-closed: every check refuses on missing,
        malformed, or unrecognized input and never silently passes. A verifier
        MUST refuse when: the cosignature names a witness identifier that the
        relying party has not pinned (an unpinned witness is never trusted);
        `alg` is present and is not "EP-WITNESS-v1"; any echoed head field is
        present and differs from the checkpoint under verification (a
        cosignature lifted from a different head refuses before any
        cryptography runs); the checkpoint cannot be canonically serialized; or
        the signature does not verify over the domain-tagged committed bytes
        under the pinned key. A relying party pins witness keys out of band;
        nothing defaults to trusted.</t>
        <t>A relying party MAY require k distinct pinned witnesses over one
        head. The quorum check MUST count each pinned witness identifier at
        most once (a witness cannot satisfy a threshold by cosigning twice),
        MUST ignore cosignatures that fail verification or name unpinned
        witnesses, and MUST treat a witness identifier pinned more than once
        as ambiguous and drop it rather than trust either entry. Fewer than k
        distinct valid cosignatures over the one head refuses.</t>
      </section>
      <section anchor="witness-scope"><name>What a cosignature proves (honest scope)</name>
        <t>A cosignature attests only that the named witness observed this
        head. It does not vouch for the log's honesty or its append-only
        behavior: a witness signs the bytes it was shown and does not re-derive
        the tree. It does not establish current validity: it is evidence of
        observation at cosign time only. A single witness detects nothing.
        Equivocation becomes DETECTABLE only when multiple independent
        witnesses -- distinct operators, distinct incentives -- cosign and
        their views are later compared; the quorum check above is the local,
        single-view half of that comparison, and cross-view comparison
        (gossip) remains the deployment's responsibility.</t>
      </section>
      <section anchor="witness-relevance"><name>Relevance to long-term evidence</name>
        <t>Evidence intended to outlive its operator SHOULD reference witnessed
        heads rather than bare operator-signed checkpoints, and each
        re-anchoring event in a renewal chain SHOULD itself be anchored to a
        witnessed head. The pre-quantum retroactive-forgery defense -- a
        renewal under a stronger algorithm made while the older one is still
        unbroken -- is only as strong as the independence of the anchoring: a
        renewal anchored solely to material the operator alone signs adds the
        operator's word, not an independent observation.</t>
      </section>
    </section>

    <section anchor="timeproof"><name>Independent Time Attestation (RFC 3161)</name>
      <t>The renewal chain in this document time-attests with EP's native,
      key-pinned time-attestation primitive. This OPTIONAL companion profile
      adds an interoperable, standards-track alternative for the WHEN: an RFC
      3161 <xref target="RFC3161"/> timestamp token over the record digest (or
      over a checkpoint root), verified OFFLINE against a time-stamping
      authority (TSA) key the relying party has pinned out of band. A verified
      token establishes that the bytes bound by the digest existed no later
      than the TSA-asserted genTime, so the age of a record no longer reduces
      to trusting the operator's own clock.</t>
      <section anchor="timeproof-verify"><name>Verification</name>
        <t>A verifier MUST proceed fail-closed and refuse, with a distinct
        reason, on any failure:</t>
        <ol>
          <li>The token MUST parse as an RFC 3161 TimeStampToken: a CMS
          SignedData <xref target="RFC5652"/> whose encapsulated content type
          is id-ct-TSTInfo. An unparseable token, a token that is not
          SignedData, or a token that is not a timestamp token refuses.</li>
          <li>The TSTInfo messageImprint MUST equal the digest the relying
          party independently expects (the record digest or checkpoint root it
          holds). A digest mismatch refuses regardless of who signed the
          token.</li>
          <li>The TSA signature MUST verify under a key the relying party has
          pinned. An empty or absent pinned-key set is an unpinned TSA and
          refuses; nothing defaults to trusted, and no certificate-chain walk
          substitutes for the pin.</li>
          <li>When CMS signed attributes are present, the signature MUST be
          verified over the DER re-encoding of the SignedAttributes per
          Section 5.4 of <xref target="RFC5652"/>, the content-type attribute
          MUST be id-ct-TSTInfo, and the message-digest attribute MUST equal
          the digest of the encapsulated TSTInfo; any mismatch refuses.</li>
        </ol>
        <t>On success the verifier reports the TSA-asserted time and a SHA-256
        fingerprint of the pinned SPKI key that verified the token, so the
        record can state which pinned authority stamped it.</t>
      </section>
      <section anchor="timeproof-scope"><name>What it does and does not prove</name>
        <t>A verified token proves existence-by-time only: a TSA the relying
        party chose to pin asserted that these bytes existed at genTime, i.e.
        the bytes predate genTime. It does NOT prove the underlying action was
        correct, authorized, or even sensible; it does not prove the TSA's
        clock was accurate; it does not prove that no earlier timestamp
        exists; and, like every offline check in this document, it does not
        establish current validity or the revocation status of the TSA's
        credentials (that needs a fresh online status check).</t>
      </section>
    </section>

    <section anchor="security"><name>Security Considerations</name>
      <t>The central operational requirement is timeliness: a renewal under a
      stronger algorithm MUST be appended while the current algorithm is still
      unbroken. The chain cannot prove this happened; deployments retain a renewal
      policy and monitoring as out-of-band discipline. A renewal added after the
      prior algorithm is already broken provides no additional assurance.</t>
      <t>Trust derives from the pinned, independent time authorities across the
      chain. Using the same authority for every renewal concentrates trust;
      diversity of authorities strengthens the record. The profile preserves only
      *verifiability*, not *correctness* of the protected artifact.</t>
      <t>The record is fail-closed: a missing renewal, a broken link, a non-
      monotonic time, or an unverifiable time-attestation yields invalid.</t>
    </section>

    <section anchor="relationship"><name>Relationship to Other Work</name>
      <t>EP-EVIDENCE-RECORD adapts the Archive Timestamp Chain of [RFC4998]
      (Evidence Record Syntax) to EP's JSON/JCS evidence and EP time-attestations,
      keeping the result offline-verifiable. It composes with
      <xref target="draft-schrock-ep-authorization-receipts"/> (the typical
      protected artifact) and with
      <xref target="draft-schrock-ep-authorization-evidence-chain"/> (a chain may
      be preserved as the protected artifact). A renewal chain MAY additionally be
      registered with a transparency service such as SCITT
      <xref target="I-D.ietf-scitt-architecture"/> for third-party anchoring, but
      the profile does not require it.</t>
    </section>

    <section anchor="iana"><name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
    </section>

    <section anchor="impl"><name>Implementation Status</name>
      <t>A reference verifier is maintained as open-source software in three
      cross-language implementations (JavaScript, Python, Go) that agree on a
      shared conformance vector set, exercised offline in continuous
      integration. The three verifiers live in one repository and are a
      cross-language consistency check, not clean-room independent
      implementations; independent implementations remain future
      interoperability evidence.</t>
      <t>The witness-cosignature and independent-time-attestation profiles
      added in this revision are implemented today in the JavaScript reference
      verifier only; the Python and Go ports cover the core evidence-record
      verification, not these profiles yet. The JavaScript RFC 3161 verifier is
      a purpose-built minimal DER/CMS reader: it supports a single SignerInfo
      signed with RSASSA-PKCS1-v1_5 or ECDSA over a SHA-2 digest, with or
      without CMS signed attributes, and refuses tokens outside that shape
      (including RSASSA-PSS and multi-signer tokens) rather than
      force-fitting them. A minimal reference witness cosigner
      service accompanies the verifier.</t>
    </section>
  </middle>
  <back>
    <references>
      <name>Normative References</name>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8785.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4998.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3161.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5652.xml"/>
      <reference anchor="draft-schrock-ep-authorization-receipts" target="https://datatracker.ietf.org/doc/draft-schrock-ep-authorization-receipts/">
        <front>
          <title>Authorization Receipts for High-Risk Agent Actions (EP)</title>
          <author fullname="Iman Schrock"><organization>EMILIA Protocol, Inc.</organization></author>
          <date year="2026" month="June"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-schrock-ep-authorization-receipts"/>
      </reference>
    </references>
    <references>
      <name>Informative References</name>
      <reference anchor="draft-schrock-ep-authorization-evidence-chain" target="https://datatracker.ietf.org/doc/draft-schrock-ep-authorization-evidence-chain/">
        <front>
          <title>Authorization Evidence Chains (EP-AEC)</title>
          <author fullname="Iman Schrock"><organization>EMILIA Protocol, Inc.</organization></author>
          <date year="2026" month="June"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-schrock-ep-authorization-evidence-chain"/>
      </reference>
      <reference anchor="I-D.ietf-scitt-architecture" target="https://datatracker.ietf.org/doc/draft-ietf-scitt-architecture/">
        <front>
          <title>An Architecture for Trustworthy and Transparent Digital Supply Chains</title>
          <author><organization>IETF SCITT WG</organization></author>
          <date year="2026"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-ietf-scitt-architecture"/>
      </reference>
    </references>
  </back>
</rfc>
