<?xml version="1.0" encoding="utf-8"?>
<!-- name="GENERATOR" content="github.com/mmarkdown/mmark Mmark Markdown Processor - mmark.miek.nl" -->
<rfc version="3" ipr="trust200902" docName="draft-ritz-sae-01" submissionType="IETF" category="exp" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude" indexInclude="true">

<front>
<title abbrev="SAE">Static Artifact Exchange (SAE) Protocol</title><seriesInfo value="draft-ritz-sae-01" stream="IETF" status="experimental" name="Internet-Draft"></seriesInfo>
<author fullname="Nathanael Ritz"><organization>Independent</organization><address><postal><street></street>
</postal><email>nathanritz@gmail.com</email></address></author><date year="2025" month="September" day="30"></date>
<area>SEC</area>
<workgroup></workgroup>

<abstract>
<t>This document specifies the Static Artifact Exchange (SAE) protocol,
an asynchronous transport pattern for exchanging cryptographic
artifacts between two parties via a shared, stateless repository.
SAE uses a &quot;publish-then-poll,&quot; pull-only communication model where
peers use the presence and size of immutable artifacts to coordinate
a sequenced exchange. By enforcing a strict set of invariants,
including a prohibition on parsing arbitrary content to drive the
transport's state machine, SAE is designed to minimize common attack
surfaces like injection and parser vulnerabilities. The pattern is
transport-agnostic and is intended for use by higher-level
cryptographic protocols, like Ephemeral Compute Attestation (ECA),
that require a secure, minimal channel.</t>
</abstract>

</front>

<middle>

<section anchor="sec-intro"><name>Introduction</name>
<t>Many cryptographic protocols require a coordinated, multi-phase
exchange of artifacts. Traditional request-response patterns often
introduce security risks at the transport layer, including complex
state management, parser vulnerabilities, and injection attacks.</t>
<t>This document specifies the Static Artifact Exchange (SAE) protocol,
an alternative model designed for security and simplicity. In SAE,
parties do not communicate directly but interact asynchronously
through a simple, stateless repository. One party publishes a set of
immutable, pre-computed artifacts and then a status indicator to
signal completion. The other party polls for this status indicator
and, upon observing it, retrieves the artifacts.</t>
<t>This &quot;publish-then-poll&quot; pattern, governed by a strict set of
invariants, reduces the need for active listeners or dynamic request
processing, limiting common attack surfaces. The security of the
higher-level protocol relies on the cryptographic validity of the
artifacts themselves, while the SAE transport provides a hardened,
minimal-surface communication channel.</t>
<t>SAE is intended as a reusable transport pattern for higher-level
protocols, motivated by the requirements of Ephemeral Compute
Attestation (ECA) <xref target="I-D.ritz-eca"></xref>.</t>
</section>

<section anchor="sec-terms"><name>Terminology and Core Concepts</name>
<t>The key words &quot;MUST&quot;, &quot;MUST NOT&quot;, &quot;REQUIRED&quot;, &quot;SHALL&quot;, &quot;SHALL NOT&quot;,
&quot;SHOULD&quot;, &quot;SHOULD NOT&quot;, &quot;RECOMMENDED&quot;, &quot;NOT RECOMMENDED&quot;, &quot;MAY&quot;, and
&quot;OPTIONAL&quot; in this document are to be interpreted as described in
BCP 14 <xref target="RFC2119"></xref> <xref target="RFC8174"></xref> when, and only when, they appear in all
capitals, as shown here.</t>

<dl spacing="compact">
<dt>Peer</dt>
<dd>An entity participating in the SAE protocol.</dd>
<dt>Artifact</dt>
<dd>An immutable blob of data published by a peer.</dd>
<dt>Status Indicator</dt>
<dd>A signal indicating the completion of a phase. A zero-byte artifact
indicates success, while a non-zero-byte artifact contains an
authenticated and encrypted error signal.</dd>
<dt>Repository</dt>
<dd>A durable, addressable, and immutable store for artifacts.</dd>
<dt>Exchange Identifier</dt>
<dd>A unique identifier for a specific exchange instance, used to
construct artifact paths.</dd>
</dl>
</section>

<section anchor="sec-invariants"><name>Protocol Requirements (Normative)</name>
<t>SAE implementations MUST satisfy the following invariants:</t>

<ol type="%d.">
<li><t><strong>Static Artifact Model</strong>: All communication MUST conform to a
strict artifact exchange model where both peers operate as passive
repositories of pre-computed, immutable artifacts.</t>
</li>
<li><t><strong>Pull-Only Communication</strong>: Peers MUST NOT push data. All
artifact retrieval MUST be initiated by the consuming peer
through polling.</t>
</li>
<li><t><strong>Phased Atomic Progression</strong>: All artifacts for a phase MUST be
published before its corresponding status indicator is published.</t>
</li>
<li><t><strong>Immutability</strong>: Once a status indicator for a phase is
published, all associated artifacts for that phase MUST NOT be
changed or removed.</t>
</li>
<li><t><strong>Prohibited Processing (Transport Layer)</strong>: The SAE transport-
level state machine MUST be driven solely by the presence and size
of artifacts. A non-zero size for a status indicator MUST be
treated by the SAE layer as a terminal failure, ending the
exchange. This invariant prevents the SAE layer from parsing
arbitrary or variable-length content to determine its outcome.
This rule does <strong>not</strong> prohibit the higher-level application
protocol (e.g., ECA) from performing its own content-based
validation, such as verifying a digital signature, as part of its
own application-level logic after retrieving an artifact.</t>
</li>
<li><t><strong>Bounded Polling</strong>: Polling for status indicators MUST use
exponential backoff.</t>
</li>
<li><t><strong>Transport Simplicity</strong>: The protocol logic MUST remain
independent of transport-level features beyond basic artifact
retrieval (e.g., HTTP GET/HEAD) and presence signaling (e.g.,
HTTP 200/404).</t>
</li>
<li><t><strong>Repository Consistency</strong>: Any repository used to host artifacts
MUST provide strong read-after-write consistency.</t>
</li>
<li><t><strong>Resilient Artifact Retrieval</strong>: The peer's retrieval logic MUST
be resilient to transient transport- or storage-layer delays.</t>
</li>
</ol>
</section>

<section anchor="sec-mechanics"><name>Protocol Mechanics</name>

<section anchor="sec-repo-structure"><name>Artifact Repository Structure</name>
<t>Each peer MUST organize its repository using a consistent path
structure based on the Exchange Identifier.</t>
<t><strong>Recommended Structure</strong>:</t>

<artwork><![CDATA[/<exchange_id>/<artifact_name>
/<exchange_id>/<phase_name>.status
]]></artwork>
</section>

<section anchor="sec-phase-coordination"><name>Phase Coordination</name>
<t>The protocol progresses using a &quot;publish-then-poll&quot; pattern:</t>

<ol type="%d.">
<li><t><strong>Publication</strong>: A peer publishes all required artifacts for the
current phase.</t>
</li>
<li><t><strong>Signaling</strong>: After publication, the peer publishes the status
indicator.</t>

<ul spacing="compact">
<li><strong>Success</strong>: The status indicator MUST be a zero-byte artifact.</li>
<li><strong>Failure</strong>: The status indicator MUST be a non-zero-byte
artifact containing an authenticated and encrypted error signal
as defined in <eref target="#sec-error-signaling">§ 4.4</eref>.</li>
</ul></li>
<li><t><strong>Polling</strong>: The counterpart peer polls for the status indicator.</t>
</li>
<li><t><strong>Retrieval and Interpretation</strong>: Upon detecting the status
indicator:</t>

<ul spacing="compact">
<li>If the size is zero, the phase was successful; proceed to
retrieve phase artifacts.</li>
<li>If the size is greater than zero, the SAE exchange has failed
and MUST be terminated. Diagnosing the specific error by
decrypting the artifact's content is an OPTIONAL step for the
higher-level application.</li>
</ul></li>
</ol>
</section>

<section anchor="sec-error-signaling"><name>Error Signaling</name>
<t>When a peer encounters an error, it MUST publish a status indicator
containing a fixed-length, authenticated ciphertext. This is
generated by first hashing the canonical error string and then
encrypting that hash using an AEAD scheme.</t>

<ul spacing="compact">
<li><strong>Key (<tt>K</tt>)</strong>: A secret key derived from a value shared between the
peers out-of-band or established by the higher-layer protocol for
this specific <tt>exchange_id</tt>.</li>
<li><strong>Plaintext</strong>: The raw binary output of
<tt>SHA-256(canonical_error_string)</tt>.</li>
<li><strong>AEAD</strong>: An AEAD scheme such as AES-256-GCM is RECOMMENDED, with a
fixed, zero-byte AAD and a randomly generated 12-byte nonce
prepended to the ciphertext.</li>
</ul>
<t>This method conceals the error from passive observers and provides
integrity, while allowing the recipient to perform an efficient O(1)
lookup by hashing known error strings and comparing them to the
decrypted hash.</t>
</section>
</section>

<section anchor="sec-security"><name>Security Considerations</name>

<section anchor="sec-security-processing"><name>Elimination of Processing Vulnerabilities</name>
<t>The security benefits of SAE are not inherent to the static artifact
model itself, but are a direct result of the strict invariants placed
upon it. Specifically, the <strong>Prohibited Processing (Transport Layer)</strong>
invariant, which forbids the SAE state machine from parsing content
to determine its outcome, is what eliminates common attack vectors
like parser vulnerabilities and injection flaws at the transport
level.</t>
</section>

<section anchor="sec-security-race"><name>Prevention of Race Conditions</name>
<t>The atomic &quot;publish-then-signal&quot; model prevents Time-of-Check-to-Time-
of-Use (TOCTOU) vulnerabilities.</t>
</section>

<section anchor="sec-replay"><name>Resilience to Replay Attacks</name>
<t>Replay protection across exchanges MUST be provided by the higher-
layer protocol (e.g., ECA’s accept-once semantics for <tt>eca_uuid</tt>).</t>
</section>
</section>

<section anchor="sec-iana"><name>IANA Considerations</name>

<section anchor="sae-error-codes-registry"><name>SAE Error Codes Registry</name>
<t>IANA is requested to establish a registry for SAE Error Codes. This
registry defines the error code identifier and the canonical string
that MUST be used as the input to the <tt>SHA-256</tt> hash function when
generating an error signal.</t>
<table>
<thead>
<tr>
<th align="left">Code</th>
<th align="left">Canonical Content (UTF-8)</th>
</tr>
</thead>

<tbody>
<tr>
<td align="left"><tt>BAD_REQUEST</tt></td>
<td align="left"><tt>BAD_REQUEST</tt></td>
</tr>

<tr>
<td align="left"><tt>UNAUTHORIZED</tt></td>
<td align="left"><tt>UNAUTHORIZED</tt></td>
</tr>

<tr>
<td align="left"><tt>FORBIDDEN</tt></td>
<td align="left"><tt>FORBIDDEN</tt></td>
</tr>

<tr>
<td align="left"><tt>CONFLICT</tt></td>
<td align="left"><tt>CONFLICT</tt></td>
</tr>

<tr>
<td align="left"><tt>GATEWAY_TIMEOUT</tt></td>
<td align="left"><tt>GATEWAY_TIMEOUT</tt></td>
</tr>
</tbody>
</table></section>
</section>

<section anchor="sec-refs-norm"><name>Normative References</name>

<dl spacing="compact">
<dt><xref target="I-D.ritz-eca"></xref></dt>
<dd>Ritz, N., &quot;Ephemeral Compute Attestation (ECA) Protocol&quot;, Work in
Progress, draf-ritz-eca-00, 16 September 2025.</dd>
<dt><xref target="RFC2119"></xref></dt>
<dd>Bradner, S., &quot;Key words for use in RFCs to Indicate Requirement
Levels&quot;, BCP 14, RFC 2119.</dd>
<dt><xref target="RFC6234"></xref></dt>
<dd>Eastlake 3rd, D. and T. Hansen, &quot;US Secure Hash Algorithms (SHA
and SHA-based HMAC and HKDF)&quot;, RFC 6234, DOI 10.17487/RFC6234,
May 2011, <eref target="https://www.rfc-editor.org/info/rfc6234">https://www.rfc-editor.org/info/rfc6234</eref>.</dd>
<dt><xref target="RFC8174"></xref></dt>
<dd>Leiba, B., &quot;Ambiguity of Uppercase vs Lowercase in RFC 2119 Key
Words&quot;, BCP 14, RFC 8174.</dd>
<dt><xref target="RFC8446"></xref></dt>
<dd>Rescorla, E., &quot;The Transport Layer Security (TLS) Protocol
Version 1.3&quot;, RFC 8446, DOI 10.17487/RFC8446, August 2018.</dd>
<dt><xref target="RFC9110"></xref></dt>
<dd>Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed.,
&quot;HTTP Semantics&quot;, STD 97, RFC 9110, DOI 10.17487/RFC9110, June
2022.</dd>
</dl>
</section>

<section anchor="acknowledgements"><name>Acknowledgements</name>
<t>The author wishes to thank Eric Rescorla for his thorough review
of the initial draft. His expert feedback led to significant
improvements in the protocol's security claims, the clarification
of a key normative invariant, and a more robust and efficient
error signaling mechanism.</t>
</section>

</middle>

<back>
<references><name>Informative References</name>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ritz-eca.xml"/>
<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.6234.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.8446.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9110.xml"/>
</references>

<section anchor="appendix-a"><name>HTTPS Profile (Normative)</name>
<t>This section provides a normative example of how the abstract SAE
protocol can be implemented using standard HTTPS.</t>

<section anchor="appendix-a-example"><name>Example Exchange</name>
<t><strong>Error example:</strong> If B encounters a timeout, it publishes an
authenticated and encrypted error signal.</t>

<artwork><![CDATA[# B derives the AEAD key (K) and a nonce
# B computes the plaintext: HASH = SHA-256("GATEWAY_TIMEOUT")
# B encrypts the hash: C = AEAD.Seal(K, nonce, HASH, nil)
# B constructs the payload: nonce || C

B: PUT /exchange-12345/response.status (content: <nonce-and-ciphertext>)
A: HEAD /exchange-12345/response.status (polling until 200 OK)
A: Observes Content-Length > 0 // Exchange is dead
A: GET /exchange-12345/response.status (reads payload) // OPTIONAL
A: Parses nonce and ciphertext from payload
A: Decrypts hash: HASH' = AEAD.Open(K, nonce, C, nil)
A: Looks up HASH' in a precomputed map of known error hashes
A: Finds match for SHA-256("GATEWAY_TIMEOUT") -> aborts exchange
]]></artwork>
</section>
</section>

<section anchor="appendix-b"><name>Example Implementations (Informative)</name>

<section anchor="generating-an-error-signal-bash"><name>Generating an Error Signal (Bash)</name>

<sourcecode type="bash"><![CDATA[#!/bin/bash
ERROR_CODE="GATEWAY_TIMEOUT"
AEAD_KEY_HEX="deadbeef..." # 32-byte key, securely provided
NONCE_HEX=$(openssl rand -hex 12)

# Compute the hash of the error string
ERROR_HASH=$(printf "%s" "$ERROR_CODE" | sha256sum | awk '{print $1}')

# Encrypt the hash using AES-256-GCM and get ciphertext + tag
# Note: This is a simplified example. Real implementations should 
# handle outputs carefully.
ENCRYPTED_OUTPUT=$(echo -n "$ERROR_HASH" | openssl enc -aes-256-gcm \
  -K "$AEAD_KEY_HEX" -iv "$NONCE_HEX" -A "" | xxd -p -c 256)
CIPHERTEXT=${ENCRYPTED_OUTPUT::-32}
TAG=${ENCRYPTED_OUTPUT: -32}

# The final payload is nonce || ciphertext || tag
printf "%s%s%s" "$NONCE_HEX" "$CIPHERTEXT" "$TAG" > error.status
]]></sourcecode>
</section>

<section anchor="verifying-an-error-signal-bash"><name>Verifying an Error Signal (Bash)</name>

<sourcecode type="bash"><![CDATA[#!/bin/bash
RECEIVED_PAYLOAD=$(cat error.status | xxd -p -c 256)
AEAD_KEY_HEX="deadbeef..." # 32-byte key, securely provided

# Parse the payload
NONCE_HEX=${RECEIVED_PAYLOAD:0:24}
CIPHERTEXT_HEX=${RECEIVED_PAYLOAD:24:-32}
TAG_HEX=${RECEIVED_PAYLOAD: -32}

# Attempt to decrypt
DECRYPTED_HASH=$(printf "%s" "$CIPHERTEXT_HEX" | xxd -r -p | openssl enc -d -aes-256-gcm -K "$AEAD_KEY_HEX" -iv "$NONCE_HEX" -A "" -T "$TAG_HEX")

# Precompute known error hashes
declare -A KNOWN_ERROR_HASHES
KNOWN_ERROR_HASHES[$(printf "%s" "GATEWAY_TIMEOUT" | sha256sum | awk '{print $1}')]="GATEWAY_TIMEOUT"
# ... add other known errors ...

# Check if the decrypted hash is a known error
if [[ -v KNOWN_ERROR_HASHES[$DECRYPTED_HASH] ]]; then
  echo "VERIFIED: The error code is '${KNOWN_ERROR_HASHES[$DECRYPTED_HASH]}'."
else
  echo "UNKNOWN_ERROR or AUTHENTICATION_FAILURE."
fi
]]></sourcecode>
</section>
</section>

<section anchor="changes-from-00"><name>Changes from -00</name>

<ul spacing="compact">
<li>Refined the security claims in the Security Considerations
section to more precisely attribute the protocol's security
benefits to its strict invariants rather than the static
artifact model itself.</li>
<li>Clarified the normative language for the
&quot;Prohibited Processing&quot; invariant to resolve an ambiguity.
The rule now explicitly applies to the SAE transport-level
state machine and does not prohibit content validation by
the higher-level application protocol.</li>
<li>Replaced the HMAC-based error signaling mechanism with a
more efficient AEAD-based design, based on feedback from
Eric Rescorla. This improves performance and conceals the
error type from passive observers.</li>
<li>General editorial and language improvements for clarity.</li>
</ul>
</section>

</back>

</rfc>
