<?xml version="1.0" encoding="utf-8"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     category="exp"
     docName="draft-hebbar-hiremani-scswp-00"
     ipr="trust200902"
     submissionType="independent"
     xml:lang="en"
     version="3">

  <front>
    <title abbrev="SCSWP">Secure Collaborative State Workspace Protocol (SCSWP)</title>
    <seriesInfo name="Internet-Draft" value="draft-hebbar-hiremani-scswp-00"/>

    <author fullname="Sripad Hebbar" initials="S." surname="Hebbar">
      <organization>Independent</organization>
      <address><email>sripadkarthik@gmail.com</email></address>
    </author>

    <author fullname="Sharan Hiremani" initials="S." surname="Hiremani">
      <organization>Independent</organization>
      <address><email>sharanrhiremani@gmail.com</email></address>
    </author>

    <date year="2026" month="August" day="22"/>
    <area>Security</area>
    <workgroup>Independent Submission</workgroup>
    <keyword>secure workspace</keyword>
    <keyword>continuous authentication</keyword>
    <keyword>ECDH</keyword>
    <keyword>AES-GCM</keyword>
    <keyword>collaborative protocol</keyword>

    <abstract>
      <t>This document specifies the Secure Collaborative State Workspace Protocol (SCSWP),
      a stateful, continuously authenticated protocol that enables multiple clients, operating
      from heterogeneous networks, to securely access and collaboratively manage a shared file
      workspace hosted on a central authoritative server.</t>
      <t>SCSWP defines a complete protocol lifecycle encompassing client provisioning via a
      Key-Dissolving bootstrap mechanism, mutual X.509 certificate-based identity authentication,
      ephemeral Elliptic-Curve Diffie-Hellman (ECDH) key exchange producing a three-level
      cryptographic key hierarchy (K1, K2, K3), continuous Dynamic Network and Access (D/N/P/S)
      trust evaluation, per-client capability-based authorization, workspace-aware congestion
      control with a dynamic worker-pool scheduler, concurrent file-operation management via
      mutual exclusion locks and optimistic version control, idempotent operation execution,
      a hash-chained audit ledger, and session continuity and recovery through the Dynamic
      Network and Access Continuity (DNAC) mechanism.</t>
      <t>The fundamental security principle of SCSWP is that client trust is not established
      permanently at login time. Instead, identity, device state, network context, session
      state, authorization state, resource state, and workspace state are evaluated continuously
      and cryptographically throughout the full lifetime of every connection.</t>
    </abstract>
  </front>

  <middle>

    <!-- ============================================================ -->
    <section anchor="introduction" numbered="true" toc="default">
      <name>Introduction</name>
      <t>Contemporary distributed systems increasingly require multiple clients, operating from
      geographically separated and organizationally distinct networks, to collaboratively access
      and modify shared files through a central authoritative server. Existing approaches address
      either the security plane (e.g., TLS-protected file servers) or the collaborative
      concurrency plane (e.g., distributed version control systems) independently. No single
      protocol addresses both planes together with continuous trust evaluation as a first-class
      protocol requirement.</t>
      <t>The Secure Collaborative State Workspace Protocol (SCSWP) fills this gap by unifying
      the following capabilities into a single, coherent protocol:</t>
      <ol type="a">
        <li><t><strong>Client Provisioning:</strong> Centrally managed, server-authorized client
        creation using a Key-Dissolving bootstrap mechanism that controls protocol entry without
        replacing cryptographic authentication.</t></li>
        <li><t><strong>Mutual Authentication:</strong> X.509 certificate-based identity validation
        in both directions, establishing that both the server and the client are who they claim to
        be before any key material is derived.</t></li>
        <li><t><strong>Cryptographic Key Hierarchy:</strong> A three-level key hierarchy (K1, K2, K3)
        derived through HKDF <xref target="RFC5869"/> over ECDH <xref target="RFC8422"/> shared
        secrets, providing forward secrecy, purpose separation, and epoch-based key rotation.</t></li>
        <li><t><strong>Continuous Trust Evaluation:</strong> A Dynamic Network and Access (D/N/P/S)
        trust model in which the client's Device context, Network context, Port context, and
        Socket/Session context are continuously authenticated and evaluated. Trust is not a binary
        post-login state; it is a continuously scored signal that drives rekeying, revalidation,
        and session suspension decisions.</t></li>
        <li><t><strong>Per-Client Capability Authorization:</strong> Fine-grained, server-issued
        capability bits (READ, WRITE, APPEND, CREATE, DELETE, RENAME, LOCK, ADMIN) that govern
        which file operations each client may request within each workspace.</t></li>
        <li><t><strong>Workspace-Aware Congestion Control:</strong> A two-layer congestion model
        combining transport-level flow control with an application-level priority-scheduled worker
        pool that prevents any single client from exhausting shared server resources.</t></li>
        <li><t><strong>File Concurrency Management:</strong> Mutual exclusion locks, optimistic
        version control with configurable conflict policies (REJECT, RETRY, MERGE, REBASE,
        CONFLICT VERSION), and operation idempotency via deduplication identifiers.</t></li>
        <li><t><strong>Hash-Chained Audit Ledger:</strong> Every significant operation produces
        an authenticated, hash-chained audit record incorporating the operation identifier,
        client and session identifiers, file identifier, previous and new versions, key epoch,
        trust state, and DNAC hash.</t></li>
        <li><t><strong>DNAC Session Continuity:</strong> The Dynamic Network and Access Continuity
        mechanism provides cryptographic session recovery after disconnection. Upon reconnection,
        the client presents its last DNAC digest; the server validates the chain and, if valid,
        restores the session with a fresh K3 key epoch.</t></li>
      </ol>

      <section anchor="scope" numbered="true" toc="default">
        <name>Scope</name>
        <t>This document specifies:</t>
        <ul>
          <li>The normative protocol message format and OpCode space.</li>
          <li>The normative cryptographic procedures for K1, K2, and K3 derivation.</li>
          <li>The normative DNAC construction and validation procedure.</li>
          <li>The normative file-state record and concurrency control rules.</li>
          <li>The normative audit record format and hash-chain construction.</li>
          <li>Security requirements and threat analysis.</li>
          <li>IANA registrations for the SCSWP OpCode registry and Capability Flags registry.</li>
        </ul>
        <t>This document does NOT specify:</t>
        <ul>
          <li>The internal server storage format for file data.</li>
          <li>UI implementation details for client or server administration.</li>
          <li>Deployment topology beyond the single-server model.</li>
          <li>Post-quantum key encapsulation mechanisms (noted as future scope).</li>
        </ul>
      </section>

      <section anchor="design-principles" numbered="true" toc="default">
        <name>Design Principles</name>
        <t>SCSWP is designed around the following core principles:</t>
        <dl>
          <dt>Continuous Authentication:</dt>
          <dd>Authentication is not a one-time gate. The protocol continuously re-evaluates
          the D/N/P/S context and adjusts trust accordingly.</dd>
          <dt>Defense in Depth:</dt>
          <dd>Security is maintained at the identity plane (X.509, bootstrap), the trust plane
          (D/N/P/S), the security plane (K1/K2/K3 with epoch rotation), the authorization plane
          (capability ACL), and the concurrency plane (locks, versions, idempotency) simultaneously.</dd>
          <dt>Cryptographic Separation:</dt>
          <dd>Each key level serves exactly one purpose. K1 roots session identity. K2 encodes
          workspace authorization. K3 provides active session subkeys separated by purpose
          (authentication, control, payload).</dd>
          <dt>Minimal Exposure:</dt>
          <dd>Sensitive protocol information is always contained inside an AES-256-GCM
          authenticated encrypted envelope. The transport-visible portion carries only
          information required for routing.</dd>
          <dt>Auditable State:</dt>
          <dd>Every meaningful state transition produces an immutable, hash-chained audit record.
          The audit ledger serves as both a compliance artifact and an input to DNAC recovery.</dd>
        </dl>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="conventions" numbered="true" toc="default">
      <name>Conventions and Definitions</name>
      <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
      "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" 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>
      <t>The following terms are used throughout this document:</t>
      <dl>
        <dt>Server:</dt>
        <dd>The SCSWP central authority. Maintains authoritative workspace state, issues client
        identities, performs continuous trust evaluation, and executes all file operations.</dd>
        <dt>Client:</dt>
        <dd>An SCSWP endpoint operating under a server-issued identity. Clients do not hold
        authoritative workspace state.</dd>
        <dt>Bootstrap Token:</dt>
        <dd>A server-generated, time-limited, single-use credential that controls protocol entry.
        Consumed on first use.</dd>
        <dt>Key-Dissolving:</dt>
        <dd>The property that a bootstrap token is irrevocably invalidated upon first successful
        use. Subsequent use of the same token MUST be rejected.</dd>
        <dt>K1:</dt>
        <dd>The session root key. Derived from ECDH shared secret via HKDF. Represents the
        identity plane of the session.</dd>
        <dt>K2:</dt>
        <dd>The workspace authorization key. Derived from K1 and the workspace authorization
        context via HKDF. Represents the authorization plane.</dd>
        <dt>K3:</dt>
        <dd>The active session key. Derived from K1, K2, a per-epoch nonce, and the epoch counter
        via HKDF. Expanded into three purpose-specific subkeys.</dd>
        <dt>Epoch:</dt>
        <dd>A monotonically increasing counter. Each K3 rotation increments the epoch. Old epoch
        keys MUST NOT be retained after rotation.</dd>
        <dt>D/N/P/S:</dt>
        <dd>The four dimensions of the dynamic trust context: Device, Network, Port, and
        Socket/Session.</dd>
        <dt>Trust Score:</dt>
        <dd>A floating-point value in [0, 100] representing the server's current confidence in
        the legitimacy of a client session.</dd>
        <dt>DNAC:</dt>
        <dd>Dynamic Network and Access Continuity. A cryptographic hash chain that accumulates
        the authenticated history of a session, used for session recovery after disconnection.</dd>
        <dt>Workspace:</dt>
        <dd>A named, server-managed directory to which one or more clients are authorized to
        perform file operations.</dd>
        <dt>File-ID:</dt>
        <dd>A globally unique identifier for a file within a workspace, formed as
        workspace_folder "/" filename.</dd>
        <dt>Operation-ID:</dt>
        <dd>A client-generated, globally unique identifier (UUID v4 <xref target="RFC4122"/>)
        assigned to each file operation request. Used to enforce idempotency.</dd>
        <dt>ABNF:</dt>
        <dd>Augmented Backus-Naur Form as defined in <xref target="RFC5234"/> and
        <xref target="RFC7405"/>.</dd>
      </dl>
    </section>

    <!-- ============================================================ -->
    <section anchor="overview" numbered="true" toc="default">
      <name>Protocol Overview and Architecture</name>
      <t>SCSWP operates between a single authoritative Server and one or more Clients. The
      server manages workspace files, client identities, cryptographic material, and session
      state. Clients access workspace files exclusively through the server; no peer-to-peer
      file transfer occurs.</t>
      <t>The protocol is organized into the following functional planes, processed in the
      order listed for every file operation:</t>
      <figure anchor="fig-planes"><name>SCSWP Processing Planes</name>
        <artwork align="center"><![CDATA[
Client Request
      |
      v
+-----------------------+
| IDENTITY PLANE        |  X.509 identity validation
+-----------------------+
      |
      v
+-----------------------+
| TRUST PLANE           |  D/N/P/S continuous evaluation
+-----------------------+
      |
      v
+-----------------------+
| SECURITY PLANE        |  K1 / K2 / K3 key hierarchy
+-----------------------+
      |
      v
+-----------------------+
| AUTHORIZATION PLANE   |  Capability / ACL check
+-----------------------+
      |
      v
+-----------------------+
| RESOURCE PLANE        |  Congestion + worker scheduling
+-----------------------+
      |
      v
+-----------------------+
| WORKSPACE PLANE       |  Lock / version / idempotency
+-----------------------+
      |
      v
+-----------------------+
| STORAGE PLANE         |  File I/O + version history
+-----------------------+
      |
      v
+-----------------------+
| AUDIT / STATE PLANE   |  Hash-chained audit + DNAC update
+-----------------------+
      |
      v
Client Response
        ]]></artwork>
      </figure>

      <section anchor="three-plane-arch" numbered="true" toc="default">
        <name>Three-Plane Architecture</name>
        <t>At the highest level of abstraction, SCSWP maintains three orthogonal security
        planes simultaneously:</t>
        <dl>
          <dt>IDENTITY PLANE:</dt>
          <dd>Controls WHO the client is. Anchored by X.509 certificates and the Key-Dissolving
          bootstrap mechanism.</dd>
          <dt>TRUST PLANE:</dt>
          <dd>Controls HOW MUCH the server trusts the current connection context. Driven by
          D/N/P/S signals evaluated every T_TRUST seconds (RECOMMENDED: 5 seconds).</dd>
          <dt>SECURITY PLANE:</dt>
          <dd>Controls HOW communication is protected. Implemented through the K1/K2/K3 key
          hierarchy, AES-256-GCM envelope encryption, and HMAC-SHA-256 message authentication.</dd>
        </dl>
        <t>These planes are independent but interact: trust plane events (e.g., suspicious
        D/N/P/S change) trigger security plane actions (e.g., K3 epoch rotation).</t>
      </section>

      <section anchor="lifecycle" numbered="true" toc="default">
        <name>Full Protocol Lifecycle</name>
        <t>The complete SCSWP lifecycle is as follows:</t>
        <dl>
          <dt>State 1: UNREGISTERED</dt>
          <dd>Client identity does not yet exist on the server.</dd>
          <dt>State 2: PROVISIONED</dt>
          <dd>Server creates a ClientIdentity record with a bootstrap_token and
          token_expires_at timestamp. Server issues a signed X.509 client certificate.</dd>
          <dt>State 3: BOOTSTRAP</dt>
          <dd>Client presents bootstrap_token in OP_PROVISION message. Token is validated
          and irrevocably consumed (Key-Dissolving).</dd>
          <dt>State 4: X.509 AUTHENTICATION</dt>
          <dd>Client and server perform mutual certificate validation. Client presents its
          ECDH ephemeral public key in OP_AUTH.</dd>
          <dt>State 5: KDF -&gt; K1</dt>
          <dd>Both parties derive K1 from ECDH shared secret.</dd>
          <dt>State 6: D/N/P/S TRUST EVALUATION (Layer-1 Complete)</dt>
          <dd>Client begins sending continuous D/N/P/S context signals. Server establishes
          initial trust score.</dd>
          <dt>State 7: WORKSPACE AUTHORIZATION -&gt; KDF -&gt; K2 -&gt; KDF -&gt; K3</dt>
          <dd>Server resolves client capabilities. K2 and K3 (epoch 1) are derived.</dd>
          <dt>State 8: ACTIVE SESSION</dt>
          <dd>File operations are processed through all planes in order. Trust evaluation
          continues every T_TRUST seconds. Heartbeats sent every T_HEARTBEAT seconds.</dd>
          <dt>Transition A:</dt>
          <dd>Trust score drops below REKEY_THRESHOLD (80) -&gt; K3 epoch rotation.</dd>
          <dt>Transition B:</dt>
          <dd>Trust score drops below SUSPEND_THRESHOLD (10) -&gt; Session suspended.</dd>
          <dt>Transition C:</dt>
          <dd>Disconnect detected -&gt; DNAC state persisted; all file locks released.</dd>
          <dt>State 9: RECOVERY</dt>
          <dd>Client reconnects and sends OP_DNAC_RECOVERY. If DNAC valid -&gt;
          SESSION_RESTORED with new K3 epoch. If DNAC invalid -&gt; return to State 3.</dd>
        </dl>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="provisioning" numbered="true" toc="default">
      <name>Client Provisioning and Bootstrap</name>

      <section anchor="identity-registration" numbered="true" toc="default">
        <name>Client Identity Registration</name>
        <t>Before a client can connect to the server, an authorized administrator MUST register
        the client identity through the server's administration interface. Registration produces
        the following server-side records:</t>
        <t><strong>Client Identity Record:</strong></t>
        <dl>
          <dt>client_id:</dt><dd>UUID v4 <xref target="RFC4122"/>, server-generated.</dd>
          <dt>common_name:</dt><dd>Human-readable client identifier.</dd>
          <dt>workspace_folder:</dt><dd>The workspace this client is authorized for.</dd>
          <dt>bootstrap_token:</dt><dd>Cryptographically random string, minimum 128 bits of
          entropy. MUST be generated using a CSPRNG conforming to <xref target="RFC4086"/>.</dd>
          <dt>token_expires_at:</dt><dd>UTC timestamp. RECOMMENDED maximum validity period:
          24 hours. Servers MUST NOT issue tokens without an expiration timestamp.</dd>
          <dt>is_active:</dt><dd>Boolean, initially FALSE. Set to TRUE on first successful
          OP_PROVISION exchange. A token with is_active=TRUE MUST be rejected on subsequent
          OP_PROVISION attempts.</dd>
          <dt>cert_pem:</dt><dd>PEM-encoded X.509 certificate signed by the server CA.</dd>
        </dl>
        <t><strong>Client Capability Record:</strong></t>
        <dl>
          <dt>client_id:</dt><dd>References the Client Identity Record.</dd>
          <dt>workspace_folder:</dt><dd>The workspace to which these capabilities apply.</dd>
          <dt>capability_bits:</dt><dd>Integer bitmask. See <xref target="capability-model"/>.</dd>
        </dl>
      </section>

      <section anchor="key-dissolving" numbered="true" toc="default">
        <name>Key-Dissolving Bootstrap Mechanism</name>
        <t>The Key-Dissolving bootstrap mechanism controls protocol entry. A client MUST
        successfully complete the bootstrap phase before proceeding to identity authentication.
        The bootstrap credential itself does not authenticate the client cryptographically;
        it merely gates entry to the authentication phase.</t>
        <t>The OP_PROVISION message carries:</t>
        <ul>
          <li>The bootstrap_token.</li>
          <li>The client's hostname (informational; not used for authentication).</li>
        </ul>
        <t>Upon receipt of OP_PROVISION, the server MUST:</t>
        <ol>
          <li>Look up the bootstrap_token in the client identity store.</li>
          <li>Verify that a matching record exists with is_active=FALSE.</li>
          <li>Verify that token_expires_at is in the future.</li>
          <li><t>If all checks pass:</t>
            <ol type="a">
              <li>Atomically set is_active=TRUE (Key-Dissolving step).</li>
              <li>Create a new SessionState record (session_id, initial trust score of 100.0).</li>
              <li>Load the Client Capability Record for this client.</li>
              <li>Respond with OP_ACK carrying client_id, cert_pem, and capability_bits.</li>
            </ol>
          </li>
          <li><t>If any check fails:</t>
            <ol type="a">
              <li>Respond with OP_ERROR carrying the appropriate error code.</li>
              <li>Increment a per-token failure counter. After three consecutive failures,
              the token MUST be permanently revoked.</li>
            </ol>
          </li>
        </ol>
        <t>Servers MUST use a constant-time string comparison when validating bootstrap tokens
        to prevent timing oracle attacks <xref target="RFC6151"/>.</t>
      </section>

      <section anchor="token-expiration" numbered="true" toc="default">
        <name>Bootstrap Token Expiration</name>
        <t>Bootstrap tokens MUST carry an expiration timestamp. A server MUST reject any token
        whose token_expires_at timestamp is less than or equal to the current UTC time at the
        moment of validation.</t>
        <!-- CORRECTION: TOKEN_EXPIRED is 0x02 per IANA error code registry (Section 14.4),
             not 0x09 as previously written in the text draft. -->
        <t>The error code TOKEN_EXPIRED (0x02) MUST be returned in the OP_ERROR payload.</t>
        <t>Re-issuance of a new token for the same client is a server administration action
        and is outside the scope of this protocol.</t>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="auth-key-establishment" numbered="true" toc="default">
      <name>Mutual Authentication and Key Establishment</name>

      <section anchor="x509-auth" numbered="true" toc="default">
        <name>X.509 Certificate Authentication</name>
        <t>SCSWP requires mutual X.509 <xref target="RFC5280"/> certificate authentication.</t>
        <dl>
          <dt>Server Certificate:</dt>
          <dd><t>The server operates a Certificate Authority (CA) using an ECDSA key pair over
          curve P-384 (secp384r1) <xref target="RFC8422"/>. The CA issues a self-signed
          certificate that serves as the trust anchor for all client connections. The CA private
          key MUST be stored securely in volatile memory and regenerated on each server start,
          or persisted in a hardware security module.</t>
          <t>The server CA certificate MUST include:</t>
          <ul>
            <li>Subject and Issuer: CN=SCSWP-CA (or a site-specific name).</li>
            <li>Validity: RECOMMENDED not to exceed 365 days.</li>
            <li>Key Usage: keyCertSign, digitalSignature.</li>
          </ul></dd>
          <dt>Client Certificate:</dt>
          <dd><t>During client provisioning (<xref target="identity-registration"/>), the server
          CA MUST issue a signed X.509 certificate to the client included in the OP_ACK
          response as cert_pem.</t>
          <t>The client certificate MUST include:</t>
          <ul>
            <li>Subject: CN=&lt;common_name of the client&gt;.</li>
            <li>Issuer: The server CA distinguished name.</li>
            <li>Validity: RECOMMENDED not to exceed 365 days.</li>
            <li>SubjectAlternativeName: DNSName=&lt;common_name&gt;.</li>
            <li>Key Usage: digitalSignature.</li>
          </ul></dd>
          <dt>Authentication Exchange:</dt>
          <dd>During OP_AUTH, the client presents its ECDH ephemeral public key. The server
          MUST verify the certificate was signed by the server CA before proceeding with key
          derivation. Clients MUST store and present cert_pem for any subsequent
          re-authentication.</dd>
        </dl>
      </section>

      <section anchor="ecdh-exchange" numbered="true" toc="default">
        <name>ECDH Key Exchange</name>
        <t>After successful certificate validation, the client and server perform an ephemeral
        Elliptic-Curve Diffie-Hellman (ECDH) key exchange <xref target="RFC8422"/>.</t>
        <dl>
          <dt>Key Generation:</dt>
          <dd>Both the client and the server MUST generate a fresh ephemeral ECDH key pair for
          each session. All ECDH operations MUST use curve P-384 (secp384r1). Support for P-256
          is OPTIONAL and NOT RECOMMENDED for new deployments.</dd>
          <dt>Exchange:</dt>
          <dd>The client sends its ephemeral public key (PEM-encoded) in the OP_AUTH request.
          The server responds with its public key in the OP_ACK response. The raw ECDH shared
          secret MUST NOT be used directly as a cryptographic key. It MUST be passed through
          HKDF as described in <xref target="k1-derivation"/>.</dd>
        </dl>
      </section>

      <section anchor="k1-derivation" numbered="true" toc="default">
        <name>K1 — Session Root Key Derivation</name>
        <t>K1 is the session root key, derived as follows:</t>
        <artwork align="left"><![CDATA[
IKM = ECDH(client_private_key, server_public_key)
    = ECDH(server_private_key, client_public_key)

K1 = HKDF-SHA256(
         IKM  = IKM,
         salt = nil,
         info = "SCSWP_K1:" || session_id,
         L    = 32 octets
     )
        ]]></artwork>
        <t>Where:</t>
        <ul>
          <li>HKDF-SHA256 is defined in <xref target="RFC5869"/> using HMAC-SHA-256
          <xref target="RFC2104"/>.</li>
          <li>session_id is the UUID v4 session identifier assigned during OP_PROVISION.</li>
          <li>The info string MUST be encoded as UTF-8 <xref target="RFC3629"/>.</li>
          <li>L=32 octets yields a 256-bit key.</li>
        </ul>
        <t>K1 MUST be retained in volatile memory only. K1 MUST NOT be written to persistent
        storage, transmitted over the network, or included in any log output. K1 is used solely
        as input to K2 derivation (<xref target="k2-derivation"/>) and MUST NOT be used directly
        as an encryption or MAC key.</t>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="trust-plane" numbered="true" toc="default">
      <name>Trust Plane — Dynamic D/N/P/S Evaluation</name>

      <section anchor="dnps-context" numbered="true" toc="default">
        <name>D/N/P/S Context Structure</name>
        <t>The D/N/P/S context is a structured representation of the client's current operating
        environment across four dimensions:</t>
        <dl>
          <dt>D — Device:</dt>
          <dd>A stable identifier for the client device, SHOULD be the server-provisioned
          client_id or a hardware-bound identifier.</dd>
          <dt>N — Network:</dt>
          <dd>The client's current network-layer source address as observed at the server.
          NAT mappings and mobile network handoffs cause legitimate address changes; the trust
          penalty for network changes is therefore lower than the penalty for device changes.</dd>
          <dt>P — Port:</dt>
          <dd>The client's staging port. Informational in the current epoch; future versions
          MAY use it for per-port isolation policy.</dd>
          <dt>S — Socket/Session:</dt>
          <dd>Session-layer context including session_id, current key epoch, and DNAC chain tip.</dd>
        </dl>
        <t>The D/N/P/S context MUST be encoded as a JSON object <xref target="RFC8259"/> with
        the following normative fields:</t>
        <sourcecode type="json"><![CDATA[
{
  "device_id":  <string>,
  "network_ip": <string>,
  "port":       <uint16>,
  "session_id": <string>,
  "epoch":      <uint32>,
  "dnac":       <string>
}
        ]]></sourcecode>
        <t>ABNF for the JSON object:</t>
        <sourcecode type="abnf"><![CDATA[
dnps-object = "{" SP
              %s"\"device_id\""  ":" SP json-string "," SP
              %s"\"network_ip\"" ":" SP json-string "," SP
              %s"\"port\""       ":" SP json-uint   "," SP
              %s"\"session_id\"" ":" SP json-string "," SP
              %s"\"epoch\""      ":" SP json-uint   "," SP
              %s"\"dnac\""       ":" SP json-string
              SP "}"
        ]]></sourcecode>
      </section>

      <section anchor="continuous-trust-eval" numbered="true" toc="default">
        <name>Continuous Trust Evaluation</name>
        <t>The client MUST send an OP_TRUST_EVAL message to the server at regular intervals.
        The RECOMMENDED interval is T_TRUST = 5 seconds. The OP_TRUST_EVAL message carries:</t>
        <ul>
          <li>The current D/N/P/S context object (<xref target="dnps-context"/>).</li>
          <li><t>An HMAC-SHA-256 <xref target="RFC2104"/> signature:</t>
            <artwork><![CDATA[
sig = HMAC-SHA256(key  = K3.auth_key,
                  data = canonical_JSON(dnps_object))
            ]]></artwork>
            <t>where canonical_JSON is a deterministic UTF-8 encoding with keys
            lexicographically sorted and no insignificant whitespace.</t>
          </li>
          <li>The current epoch number.</li>
        </ul>
        <t>The server MUST verify the HMAC signature before accepting the D/N/P/S context.
        An invalid signature MUST result in OP_ERROR code SIGNATURE_INVALID (0x0B) and an
        incremental trust penalty.</t>
      </section>

      <section anchor="trust-scoring" numbered="true" toc="default">
        <name>Trust Scoring and Policy Actions</name>
        <t>The server maintains a Trust Score T in [0, 100] for each active session. The
        initial Trust Score on session establishment is 100.0.</t>
        <t><strong>Trust Penalties:</strong></t>
        <table align="left">
          <thead><tr><th>Signal</th><th>Penalty (ΔT)</th></tr></thead>
          <tbody>
            <tr><td>Network address change</td><td>-15.0</td></tr>
            <tr><td>Device identifier change</td><td>-60.0</td></tr>
            <tr><td>Operation rate &gt; R_MAX in W_RATE</td><td>-5.0 per evaluation</td></tr>
            <tr><td>HMAC signature invalid</td><td>-25.0</td></tr>
            <tr><td>Authentication failure</td><td>-25.0</td></tr>
          </tbody>
        </table>
        <t>where R_MAX = 20 operations and W_RATE = 10 seconds.</t>
        <t><strong>Trust Healing:</strong> If no anomalies are detected, the Trust Score SHOULD
        be increased by H_TRUST (RECOMMENDED: 0.5) up to the maximum of 100.0.</t>
        <t><strong>Policy Actions Triggered by Trust Score:</strong></t>
        <dl>
          <dt>T &lt; REKEY_THRESHOLD (RECOMMENDED: 80.0):</dt>
          <dd>The server MUST initiate a K3 epoch rotation (<xref target="k3-derivation"/>).
          The server MUST include rekey=true and the new epoch_nonce_b64 in the OP_TRUST_EVAL
          ACK response.</dd>
          <!-- CORRECTION: SESSION_SUSPENDED is 0x09 per IANA error code registry, not 0x0C -->
          <dt>T &lt;= SUSPEND_THRESHOLD (RECOMMENDED: 10.0):</dt>
          <dd>The server MUST set the session is_suspended flag. All subsequent file operation
          requests MUST be rejected with OP_ERROR code SESSION_SUSPENDED (0x09). The session
          MUST be recorded in the audit ledger with result "SUSPENDED".</dd>
          <dt>T &lt;= 0:</dt>
          <dd>The server MUST terminate the connection immediately. All file locks held by
          this session MUST be released.</dd>
        </dl>
        <t>The Trust Score MUST be included in every audit record produced during the session
        (<xref target="audit-record-structure"/>).</t>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="authorization-plane" numbered="true" toc="default">
      <name>Authorization Plane and Workspace Key Derivation</name>

      <section anchor="capability-model" numbered="true" toc="default">
        <name>Per-Client Capability Model</name>
        <t>SCSWP uses a capability-based authorization model. Each client is issued a set of
        capabilities that govern which operations it may perform within its assigned workspace.
        The capability set is represented as an integer bitmask:</t>
        <table align="left">
          <thead><tr><th>Bit</th><th>Name</th><th>Value</th><th>Description</th></tr></thead>
          <tbody>
            <tr><td>0</td><td>READ</td><td>1</td><td>Download and retrieve file content.</td></tr>
            <tr><td>1</td><td>WRITE</td><td>2</td><td>Upload and overwrite file content.</td></tr>
            <tr><td>2</td><td>APPEND</td><td>4</td><td>Append data to an existing file.</td></tr>
            <tr><td>3</td><td>CREATE</td><td>8</td><td>Create new files within the workspace.</td></tr>
            <tr><td>4</td><td>DELETE</td><td>16</td><td>Delete files from the workspace.</td></tr>
            <tr><td>5</td><td>RENAME</td><td>32</td><td>Rename files within the workspace.</td></tr>
            <tr><td>6</td><td>LOCK</td><td>64</td><td>Acquire and release file locks.</td></tr>
            <tr><td>7</td><td>ADMIN</td><td>128</td><td>All of the above plus server-level operations.</td></tr>
          </tbody>
        </table>
        <t>A client with ADMIN capability MUST be treated as having all other capabilities
        regardless of individual bit states.</t>
        <!-- CORRECTION: PERMISSION_DENIED is 0x08 per IANA error code registry, not 0x0A -->
        <t>If a client requests an operation for which it lacks the corresponding capability bit,
        the server MUST reject the request with OP_ERROR code PERMISSION_DENIED (0x08) and record
        the attempt in the audit ledger.</t>
        <t><strong>Predefined Capability Presets:</strong></t>
        <table align="left">
          <thead><tr><th>Preset</th><th>Bits Set</th><th>Effective Value</th></tr></thead>
          <tbody>
            <tr><td>READ_ONLY</td><td>READ</td><td>1</td></tr>
            <tr><td>READ_WRITE</td><td>READ|WRITE|CREATE|LOCK</td><td>75</td></tr>
            <tr><td>FULL</td><td>All bits set</td><td>255</td></tr>
          </tbody>
        </table>
      </section>

      <section anchor="k2-derivation" numbered="true" toc="default">
        <name>K2 — Workspace Authorization Key Derivation</name>
        <t>K2 encodes the cryptographic binding between the session root (K1) and the workspace
        authorization context. K2 is derived independently by both the client and the server
        without transmission:</t>
        <artwork align="left"><![CDATA[
K2 = HKDF-SHA256(
         IKM  = K1,
         salt = nil,
         info = "SCSWP_K2:" || workspace_folder || ":" || session_id,
         L    = 32 octets
     )
        ]]></artwork>
        <t>K2 MUST NOT be transmitted. It MUST be retained in volatile memory only. K2 is used
        solely as input to K3 derivation (<xref target="k3-derivation"/>). A client MUST NOT
        attempt to access a different workspace using the same K2 value.</t>
      </section>

      <section anchor="k3-derivation" numbered="true" toc="default">
        <name>K3 — Active Session Key Derivation and Epoch System</name>
        <t>K3 is the active session key, expanded from a 96-octet HKDF output into three
        32-octet purpose-specific subkeys:</t>
        <artwork align="left"><![CDATA[
K3_material = HKDF-SHA256(
                 IKM  = K1 || K2,
                 salt = epoch_nonce,
                 info = "SCSWP_K3:epoch:" || epoch,
                 L    = 96 octets
             )

K3.auth_key    = K3_material[0:32]    ; HMAC-SHA-256 over D/N/P/S
K3.ctrl_key    = K3_material[32:64]   ; AES-256-GCM for control msgs
K3.payload_key = K3_material[64:96]   ; AES-256-GCM for file payloads
        ]]></artwork>
        <t>Where epoch_nonce is a 16-octet CSPRNG value generated freshly for each epoch by
        the server; epoch is the ASCII decimal epoch counter (starting at 1).</t>
        <t>A new epoch MUST be initiated when any of the following occur:</t>
        <ol type="a">
          <li>The Trust Score T falls below REKEY_THRESHOLD.</li>
          <li>The server receives an explicit OP_REKEY request from the client.</li>
          <li>Session recovery via DNAC (<xref target="dnac-recovery"/>) completes.</li>
          <li>The epoch counter reaches EPOCH_MAX (RECOMMENDED: 2^32 - 1), requiring full
          re-authentication.</li>
        </ol>
        <t>Upon epoch rotation, the previous epoch's K3 material MUST be securely erased from
        memory. The new epoch and epoch_nonce_b64 MUST be communicated in the OP_ACK or
        OP_TRUST_EVAL ACK.</t>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="transport" numbered="true" toc="default">
      <name>Secure Transport and Message Envelope</name>

      <section anchor="transport-layer" numbered="true" toc="default">
        <name>Transport Layer</name>
        <t>SCSWP messages MUST be carried over a reliable, ordered, full-duplex transport.
        RECOMMENDED transport: WebSocket <xref target="RFC6455"/> over TLS 1.3
        <xref target="RFC8446"/>. The WebSocket connection MUST be established to the server's
        protocol endpoint, conventionally at path "/protocol".</t>
        <t>Future deployments MAY use QUIC <xref target="RFC9000"/> as the transport layer.
        If TLS is not available at the transport layer, implementations MUST rely on the SCSWP
        application-layer AES-256-GCM envelope (<xref target="secure-envelope"/>) to provide
        confidentiality and integrity. TLS is STRONGLY RECOMMENDED regardless.</t>
      </section>

      <section anchor="message-format" numbered="true" toc="default">
        <name>Protocol Message Format</name>
        <t>All SCSWP messages are encoded as JSON objects <xref target="RFC8259"/>. The
        normative wire format is:</t>
        <sourcecode type="json"><![CDATA[
{
  "opcode":     <uint8>,
  "session_id": <string | null>,
  "epoch":      <uint32>,
  "payload":    <object>
}
        ]]></sourcecode>
        <t>ABNF for the message envelope:</t>
        <sourcecode type="abnf"><![CDATA[
scswp-message = "{" SP
                %s"\"opcode\""     ":" SP uint8  "," SP
                %s"\"session_id\"" ":" SP (json-string / "null") "," SP
                %s"\"epoch\""      ":" SP uint32 "," SP
                %s"\"payload\""    ":" SP json-object
                SP "}"

uint8  = 1*3DIGIT
uint32 = 1*10DIGIT
        ]]></sourcecode>
        <t>Unknown opcode values MUST result in an OP_ERROR response with error code
        UNKNOWN_OPCODE (0x0D). The total message length SHOULD NOT exceed 67108864 octets
        (64 MiB).</t>
      </section>

      <section anchor="secure-envelope" numbered="true" toc="default">
        <name>Secure Envelope</name>
        <t>File payload data included in OP_FILE_OP WRITE and READ responses MUST be protected
        using AES-256-GCM <xref target="NIST.SP.800-38D"/>.</t>
        <artwork align="left"><![CDATA[
Encryption:
  nonce    := CSPRNG(12 octets)
  ct || tag := AES-256-GCM-Encrypt(
                   key=K3.payload_key, nonce=nonce, aad=nil, pt=data)
  envelope := nonce || ct || tag
  data_b64 := BASE64URL(envelope)   ; RFC 4648 Section 5

Decryption:
  envelope := BASE64URL-DECODE(data_b64)
  nonce    := envelope[0:12]
  pt       := AES-256-GCM-Decrypt(
                   key=K3.payload_key, nonce=nonce, aad=nil,
                   ct=envelope[12:])
        ]]></artwork>
        <t>AES-256-GCM authentication tag length MUST be 128 bits (16 octets). If tag
        verification fails, the receiver MUST discard the message, increment a failure counter,
        apply a trust penalty (<xref target="trust-scoring"/>), and NOT process the decrypted
        data. Control messages SHOULD use K3.ctrl_key for envelope protection.</t>
      </section>

      <section anchor="opcode-registry-section" numbered="true" toc="default">
        <name>OpCode Registry</name>
        <t>The following opcodes are defined in this specification:</t>
        <table align="left">
          <thead><tr><th>Value</th><th>Name</th><th>Direction</th><th>Description</th></tr></thead>
          <tbody>
            <tr><td>0x01</td><td>OP_PROVISION</td><td>C-&gt;S</td><td>Bootstrap / Key-Dissolving</td></tr>
            <tr><td>0x02</td><td>OP_AUTH</td><td>C-&gt;S</td><td>ECDH identity authentication</td></tr>
            <tr><td>0x03</td><td>OP_TRUST_EVAL</td><td>C-&gt;S</td><td>D/N/P/S context signal</td></tr>
            <tr><td>0x04</td><td>OP_WORKSPACE_AUTH</td><td>C-&gt;S</td><td>Workspace authorization ack</td></tr>
            <tr><td>0x05</td><td>OP_FILE_OP</td><td>C-&gt;S</td><td>File operation (LIST/READ/WRITE)</td></tr>
            <tr><td>0x06</td><td>OP_LOCK</td><td>C-&gt;S</td><td>Acquire file write lock</td></tr>
            <tr><td>0x07</td><td>OP_UNLOCK</td><td>C-&gt;S</td><td>Release file write lock</td></tr>
            <tr><td>0x08</td><td>OP_DNAC_RECOVERY</td><td>C-&gt;S</td><td>Session recovery via DNAC</td></tr>
            <tr><td>0x09</td><td>OP_REKEY</td><td>C-&gt;S</td><td>Explicit K3 epoch rotation request</td></tr>
            <tr><td>0x0A</td><td>OP_HEARTBEAT</td><td>C-&gt;S</td><td>Keep-alive</td></tr>
            <tr><td>0x0B</td><td>OP_ACK</td><td>S-&gt;C</td><td>Generic success response</td></tr>
            <tr><td>0x0C</td><td>OP_ERROR</td><td>S-&gt;C</td><td>Error response</td></tr>
            <tr><td>0x0D</td><td>OP_NACK</td><td>S-&gt;C</td><td>Negative acknowledgement</td></tr>
          </tbody>
        </table>
        <t>OP_FILE_OP Sub-Operations (carried in payload "op" field): LIST, READ, WRITE, APPEND.
        See <xref target="iana-opcode"/> for IANA registration of these opcodes.</t>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="congestion" numbered="true" toc="default">
      <name>Congestion Control and Resource Management</name>

      <section anchor="flow-control" numbered="true" toc="default">
        <name>Application-Level Flow Control</name>
        <t>SCSWP implements a two-layer congestion control model. Layer 1 is handled by the
        transport (TLS/WebSocket or QUIC). Layer 2 implements workspace-aware scheduling and
        backpressure above the transport layer.</t>
        <t>The server MUST maintain per-client resource metrics: outstanding_ops, resource_debt,
        op_rate, and queue_depth.</t>
        <!-- CORRECTION: SERVER_BUSY is 0x0A per IANA error code registry, not 0x0E -->
        <t>If outstanding_ops &gt;= MAX_OPS_PER_CLIENT (RECOMMENDED: 10), the server MUST
        reject the incoming operation with OP_ERROR code SERVER_BUSY (0x0A) and a RECOMMENDED
        retry_ms value of 500. The client MUST honor retry_ms before retransmitting.</t>
      </section>

      <section anchor="worker-pool" numbered="true" toc="default">
        <name>Dynamic Worker-Pool Scheduler</name>
        <t>The server MUST maintain a shared pool of N_WORKERS asynchronous workers
        (RECOMMENDED: N_WORKERS = 8). Each queued operation is assigned a priority score:</t>
        <artwork align="left"><![CDATA[
score = resource_debt(session_id)
        + op_weight(op_type)
        - wait_boost(wait_time)

op_weight:  READ=0  SYNC=5  APPEND=8  WRITE=10
wait_boost: min(wait_time_seconds * 2, 50)
        ]]></artwork>
        <t>Workers MUST be dispatched in ascending score order (lowest score = highest
        priority), RECOMMENDED to be implemented as a binary min-heap. When an operation
        completes, DEBT_INCREMENT (RECOMMENDED: 5.0) is added to resource_debt. On each
        scheduler cycle, resource_debt is multiplied by DEBT_DECAY (RECOMMENDED: 0.9).</t>
      </section>

      <section anchor="resource-debt" numbered="true" toc="default">
        <name>Per-Client Resource Debt</name>
        <t>Resource debt enforces scheduler fairness but MUST NOT affect authorization. A
        client's right to perform an operation is determined entirely by its capability bits
        (<xref target="capability-model"/>) and its trust score (<xref target="trust-scoring"/>).
        Resource debt determines only WHEN an authorized operation executes, not WHETHER it
        is permitted.</t>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="workspace-plane" numbered="true" toc="default">
      <name>Workspace Plane — File Concurrency and Version Control</name>

      <section anchor="file-state-record" numbered="true" toc="default">
        <name>File State Record</name>
        <t>The server MUST maintain a File State Record for every file operated on within a
        workspace, containing at minimum:</t>
        <table align="left">
          <thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead>
          <tbody>
            <tr><td>file_id</td><td>string</td><td>workspace_folder "/" filename</td></tr>
            <tr><td>file_name</td><td>string</td><td>The base file name.</td></tr>
            <tr><td>version</td><td>uint32</td><td>Monotonically increasing. Starts at 1; incremented by 1 on each successful WRITE or APPEND.</td></tr>
            <tr><td>lock_state</td><td>enum</td><td>UNLOCKED | WRITE_LOCK</td></tr>
            <tr><td>locked_by</td><td>string</td><td>session_id of the lock holder, or NULL.</td></tr>
            <tr><td>updated_at</td><td>datetime</td><td>UTC timestamp of last modification.</td></tr>
          </tbody>
        </table>
        <t>The server MUST retain the complete version history of each file as a sequence of
        records: file_id, version, data, written_by, written_at, size_bytes.</t>
      </section>

      <section anchor="mutual-exclusion" numbered="true" toc="default">
        <name>Mutual Exclusion Locking</name>
        <t>SCSWP uses server-side exclusive write locks to prevent concurrent WRITE or APPEND
        operations from producing an undefined result.</t>
        <dl>
          <dt>Lock Acquisition (OP_LOCK):</dt>
          <dd><t>A client MUST send OP_LOCK before issuing a WRITE or APPEND operation. The
          server MUST verify LOCK capability, atomically check lock_state, and respond with
          OP_ACK {status: "LOCKED"} if UNLOCKED, or OP_ERROR {error: "FILE_LOCKED"} if
          WRITE_LOCK is held by another session.</t></dd>
          <dt>Lock Release (OP_UNLOCK):</dt>
          <dd>After completing WRITE or APPEND, the client MUST send OP_UNLOCK. The server
          MUST verify locked_by == requesting session_id; releases by non-owners MUST be
          rejected.</dd>
          <dt>Automatic Lock Release on Disconnect:</dt>
          <dd>When a client connection terminates for any reason, the server MUST release all
          file locks held by that session atomically. Lock release on disconnect MUST be
          recorded in the audit ledger.</dd>
          <dt>Advisory vs. Mandatory Locking:</dt>
          <dd>SCSWP implements mandatory server-side locking. A WRITE request received for a
          file held by another session MUST be rejected with OP_ERROR code FILE_LOCKED (0x05),
          regardless of any client-side flag.</dd>
        </dl>
      </section>

      <section anchor="version-control" numbered="true" toc="default">
        <name>Optimistic Version Control and Conflict Policies</name>
        <t>A client MAY include an expected_version field in OP_FILE_OP WRITE or APPEND
        payloads. If the server's current version differs, a conflict is detected.</t>
        <t>The client MUST include a conflict_policy field. If absent, the server MUST apply
        REJECT. Defined policies:</t>
        <dl>
          <dt>REJECT:</dt>
          <dd>Server MUST NOT apply the write. Responds with OP_ERROR VERSION_CONFLICT. Client
          MUST re-fetch before retrying.</dd>
          <dt>RETRY:</dt>
          <dd>Server MUST NOT apply the write. Responds with OP_ERROR RETRY_REQUIRED. Client
          SHOULD re-fetch and re-submit.</dd>
          <dt>MERGE:</dt>
          <dd>Server MUST apply the write, recording it as a merge in the audit ledger.
          Implementations SHOULD perform three-way text merge for text/plain or application/json.
          Binary files MUST use the WRITE payload as authoritative.</dd>
          <dt>REBASE:</dt>
          <dd>Semantically equivalent to MERGE in this version. Future versions MAY define
          distinct behavior.</dd>
          <dt>CONFLICT VERSION:</dt>
          <dd>Server MUST NOT apply the write. Instead, it creates a new snapshot version record
          for the client's payload alongside the server's current version. Both versions exist
          until an authorized administrator resolves the conflict.</dd>
        </dl>
      </section>

      <section anchor="idempotency" numbered="true" toc="default">
        <name>Operation Idempotency</name>
        <t>Each file-modifying operation (WRITE, APPEND) MUST carry a client-generated
        operation_id (UUID v4 <xref target="RFC4122"/>). The server MUST maintain an idempotency
        record keyed on operation_id. If a record exists, the server MUST return the previously
        computed result without re-executing the operation, including idempotent: true in the
        OP_ACK payload. The idempotency record SHOULD be retained for a minimum of 24 hours.</t>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="dnac" numbered="true" toc="default">
      <name>DNAC — Dynamic Network and Access Continuity</name>

      <section anchor="dnac-construction" numbered="true" toc="default">
        <name>DNAC State Digest Construction</name>
        <t>The DNAC hash chain accumulates a cryptographic summary of the session's authenticated
        state. Each link is defined as:</t>
        <artwork align="left"><![CDATA[
DNAC_N = SHA-256(
             prev_dnac    ||
             session_id   ||
             operation_id ||
             state_digest ||
             timestamp
         )
        ]]></artwork>
        <t>Where prev_dnac is the hex-encoded SHA-256 of the previous link, or the ASCII string
        "GENESIS" for the first link. All fields are concatenated with the "|" separator before
        hashing. The DNAC chain MUST be initialized with DNAC_0 = "GENESIS".</t>
      </section>

      <section anchor="dnac-evolution" numbered="true" toc="default">
        <name>DNAC Chain Evolution</name>
        <t>The DNAC chain advances after every significant protocol event:</t>
        <table align="left">
          <thead><tr><th>Event</th><th>state_digest</th></tr></thead>
          <tbody>
            <tr><td>Successful bootstrap</td><td>"BOOTSTRAP"</td></tr>
            <tr><td>Successful authentication</td><td>"AUTH_OK"</td></tr>
            <tr><td>Successful WRITE v{N}</td><td>"&lt;file_id&gt;:v&lt;version&gt;"</td></tr>
            <tr><td>Successful READ</td><td>"READ:&lt;file_id&gt;"</td></tr>
            <tr><td>Trust evaluation</td><td>"TRUST:&lt;score&gt;"</td></tr>
          </tbody>
        </table>
        <t>The server MUST persist the DNAC chain tip (DNAC_N) and preceding link (DNAC_{N-1})
        to stable storage upon session termination to enable recovery.</t>
      </section>

      <section anchor="dnac-recovery" numbered="true" toc="default">
        <name>Session Recovery via DNAC</name>
        <t>When a client reconnects after disconnection, it MUST attempt DNAC-based session
        recovery before initiating full re-authentication.</t>
        <ol>
          <li><t>Client sends OP_DNAC_RECOVERY:</t>
            <sourcecode type="json"><![CDATA[
{ "client_id": "<client_id>", "last_dnac": "<DNAC_N_hex>" }
            ]]></sourcecode>
          </li>
          <li>Server looks up the most recently persisted DNAC tip for client_id.</li>
          <li><t>If last_dnac matches the persisted DNAC tip:</t>
            <ol type="a">
              <li>The server MUST NOT reuse the previous session's K3 keys.</li>
              <li>The server MUST generate a fresh epoch_nonce and rotate K3 to a new epoch.</li>
              <li><t>The server responds:</t>
                <sourcecode type="json"><![CDATA[
OP_ACK {
  "status": "SESSION_RESTORED",
  "session_id": "<id>",
  "epoch": <new_epoch>,
  "epoch_nonce_b64": "<base64url_nonce>"
}
                ]]></sourcecode>
              </li>
            </ol>
          </li>
          <li><t>If last_dnac does NOT match, the server responds:</t>
            <sourcecode type="json"><![CDATA[
OP_ERROR { "error": "DNAC_MISMATCH_REAUTHENTICATE" }
            ]]></sourcecode>
            <t>The client MUST perform full re-authentication starting from OP_PROVISION.</t>
          </li>
        </ol>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="audit" numbered="true" toc="default">
      <name>Audit and State Ledger</name>

      <section anchor="audit-record-structure" numbered="true" toc="default">
        <name>Audit Record Structure</name>
        <t>Every significant protocol event MUST produce an audit record containing:</t>
        <table align="left">
          <thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead>
          <tbody>
            <tr><td>operation_id</td><td>string</td><td>UUID v4; unique audit record identifier.</td></tr>
            <tr><td>client_id</td><td>string</td><td>UUID v4; identifies the client.</td></tr>
            <tr><td>session_id</td><td>string</td><td>UUID v4; identifies the session.</td></tr>
            <tr><td>file_id</td><td>string</td><td>"&lt;workspace&gt;/&lt;filename&gt;", or NULL.</td></tr>
            <tr><td>operation_type</td><td>string</td><td>Event name (see below).</td></tr>
            <tr><td>timestamp</td><td>datetime</td><td>UTC timestamp of record creation.</td></tr>
            <tr><td>result</td><td>string</td><td>"SUCCESS", "FAILED", "SUSPENDED", "DISCONNECTED", or error code.</td></tr>
            <tr><td>trust_score</td><td>float</td><td>Trust Score T at record creation time.</td></tr>
            <tr><td>key_epoch</td><td>uint32</td><td>Current K3 epoch at record creation time.</td></tr>
            <tr><td>prev_version</td><td>uint32</td><td>File version before operation, or NULL.</td></tr>
            <tr><td>new_version</td><td>uint32</td><td>File version after operation, or NULL.</td></tr>
            <tr><td>prev_hash</td><td>string</td><td>Hex SHA-256 of the previous audit record.</td></tr>
            <tr><td>record_hash</td><td>string</td><td>Hex SHA-256 of this record's chain link.</td></tr>
            <tr><td>dnac</td><td>string</td><td>DNAC chain tip at record creation time.</td></tr>
          </tbody>
        </table>
        <t>Operation type values: BOOTSTRAP, AUTH, TRUST_EVAL, WORKSPACE_AUTH, LIST, READ,
        WRITE, APPEND, LOCK, UNLOCK, REKEY, DNAC_RECOVERY, HEARTBEAT, DISCONNECT.</t>
      </section>

      <section anchor="hash-chain" numbered="true" toc="default">
        <name>Hash-Chained Ledger</name>
        <t>Audit records MUST be chained to form a tamper-evident ledger:</t>
        <artwork align="left"><![CDATA[
prev_hash   = record_hash of the preceding record ("GENESIS" for first).

record_hash = SHA-256(prev_hash || operation_id || result)
              (fields concatenated with "|" separator; output hex-encoded)
        ]]></artwork>
        <t>An auditor verifying the ledger MUST start from the record with prev_hash = "GENESIS"
        and verify each record_hash in sequence. A mismatch indicates tampering at that record.
        The audit ledger SHOULD be exportable in CSV <xref target="RFC4180"/> format.</t>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="reference-implementation" numbered="true" toc="default">
      <name>Reference Implementation</name>
      <t>A reference implementation of the SCSWP protocol, including both the authoritative server and a compatible client, is available as an open-source Python package.</t>
      <t>The source code and packaging details can be found at the following URL: <eref target="https://github.com/sripad2020/Secure-Collaborative-State-Workspace-Protocol"/></t>
      <t>The published package is available on PyPI: <eref target="https://pypi.org/project/scswp/"/></t>
      <t>The reference implementation includes the min-heap priority scheduler, ECDH-based key hierarchy, DNAC hash-chain construction, and SQLite-backed audit ledger as specified in this document.</t>
    </section>

    <!-- ============================================================ -->
    <section anchor="security" numbered="true" toc="default">
      <name>Security Considerations</name>

      <section anchor="sec-crypto-alg" numbered="true" toc="default">
        <name>Cryptographic Algorithm Security</name>
        <ul>
          <li><strong>Elliptic Curve: P-384.</strong> Provides 192 bits of security strength
          <xref target="RFC8422"/>, exceeding the NIST 128-bit minimum <xref target="NIST.SP.800-57"/>.
          P-256 MUST NOT be used where long-term security is required.</li>
          <li><strong>Key Derivation: HKDF-SHA256 <xref target="RFC5869"/>.</strong> The info
          field MUST include a purpose-specific prefix.</li>
          <li><strong>Symmetric Encryption: AES-256-GCM <xref target="NIST.SP.800-38D"/>.</strong>
          GCM nonce MUST be 96 bits (12 octets) generated from a CSPRNG per encryption call.
          Nonce reuse is a catastrophic failure. K3 MUST be rotated before 2^32 encryptions.</li>
          <li><strong>Message Authentication: HMAC-SHA-256 <xref target="RFC2104"/> using
          K3.auth_key.</strong></li>
          <li><strong>Digest: SHA-256 <xref target="FIPS.PUB.180-4"/>.</strong></li>
        </ul>
      </section>

      <section anchor="sec-key-handling" numbered="true" toc="default">
        <name>Key Material Handling</name>
        <t>K1, K2, K3, and their subkeys MUST be stored exclusively in volatile memory.
        Implementations MUST NOT write key material to disk, log it in diagnostic output,
        transmit K1 or K2 in any protocol message, or retain previous-epoch K3 material
        after key rotation. On session termination, all key material MUST be securely erased.</t>
      </section>

      <section anchor="sec-bootstrap" numbered="true" toc="default">
        <name>Bootstrap Token Security</name>
        <t>Tokens MUST contain a minimum of 128 bits of entropy <xref target="RFC4086"/>.
        Validation MUST use constant-time string comparison <xref target="RFC6151"/>. Tokens
        MUST expire within a server-configured window (RECOMMENDED maximum: 24 hours). Tokens
        are single-use. After three consecutive failed validation attempts, the token MUST be
        permanently revoked.</t>
      </section>

      <section anchor="sec-trust-manip" numbered="true" toc="default">
        <name>Trust Score Manipulation</name>
        <t>All OP_TRUST_EVAL messages are HMAC-signed with K3.auth_key; invalid HMACs MUST be
        rejected and penalized. The server MUST treat the absence of OP_TRUST_EVAL for more than
        T_TRUST_TIMEOUT seconds (RECOMMENDED: 15 seconds) as suspicious and apply a trust
        penalty. Replayed messages from a previous epoch carry an outdated epoch value and
        MUST be rejected.</t>
      </section>

      <section anchor="sec-lock" numbered="true" toc="default">
        <name>File Lock Security</name>
        <t>Clients without LOCK capability MUST NOT be able to acquire or release locks.
        Servers SHOULD implement a maximum lock duration (RECOMMENDED: 300 seconds) after
        which the lock is forcibly released and a trust penalty applied.</t>
      </section>

      <section anchor="sec-audit" numbered="true" toc="default">
        <name>Audit Ledger Integrity</name>
        <t>The audit store SHOULD be append-only. Periodic ledger hash checkpoints SHOULD be
        published to an external, immutable log. The DNAC chain and the audit chain are
        independent; an attacker must tamper with both to conceal an operation.</t>
      </section>

      <section anchor="sec-conflict" numbered="true" toc="default">
        <name>Version Conflict Policies and Data Integrity</name>
        <t>Deployments where data integrity is paramount SHOULD restrict all clients to the
        REJECT conflict policy. The CONFLICT VERSION policy is the safest option for multi-client
        scenarios as it preserves all versions pending administrator resolution.</t>
      </section>

      <section anchor="sec-dos" numbered="true" toc="default">
        <name>Session Suspension and Denial of Service</name>
        <t>Network change penalties are intentionally lower than device change penalties to
        accommodate mobile clients. Administrators SHOULD be able to manually restore a
        suspended session after out-of-band verification.</t>
      </section>

      <section anchor="sec-pqc" numbered="true" toc="default">
        <name>Post-Quantum Cryptography Considerations</name>
        <t>SCSWP's K1 derivation relies on the security of ECDH over P-384, which could be
        broken by a cryptographically relevant quantum computer <xref target="SHOR1994"/>.
        Future versions SHOULD incorporate a hybrid key establishment mechanism combining ECDH
        with a PQ-KEM <xref target="NIST.PQC.FIPS.203"/>:</t>
        <artwork><![CDATA[
IKM_hybrid = ECDH_secret || PQ-KEM_secret
        ]]></artwork>
        <t>This IKM_hybrid replaces the ECDH_secret input to HKDF in K1 derivation. The rest
        of the key hierarchy (K2, K3) is unchanged.</t>
      </section>

      <section anchor="sec-privacy" numbered="true" toc="default">
        <name>Privacy Considerations</name>
        <t>D/N/P/S signals MUST never be transmitted without K3.auth_key HMAC protection.
        D/N/P/S data MUST NOT appear in the audit ledger in cleartext. Administrators MUST be
        informed that D/N/P/S data constitutes personal data under applicable privacy
        regulations.</t>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="iana" numbered="true" toc="default">
      <name>IANA Considerations</name>

      <section anchor="iana-opcode" numbered="true" toc="default">
        <name>SCSWP OpCode Registry</name>
        <t>IANA is requested to create a new registry titled "SCSWP OpCode Registry" under the
        "Secure Collaborative State Workspace Protocol (SCSWP)" registry group. Registration
        Policy: Specification Required <xref target="RFC8126"/>.</t>
        <table align="left">
          <thead><tr><th>Value</th><th>Name</th><th>Reference</th></tr></thead>
          <tbody>
            <tr><td>0x01</td><td>OP_PROVISION</td><td><xref target="key-dissolving"/></td></tr>
            <tr><td>0x02</td><td>OP_AUTH</td><td><xref target="ecdh-exchange"/></td></tr>
            <tr><td>0x03</td><td>OP_TRUST_EVAL</td><td><xref target="continuous-trust-eval"/></td></tr>
            <tr><td>0x04</td><td>OP_WORKSPACE_AUTH</td><td><xref target="capability-model"/></td></tr>
            <tr><td>0x05</td><td>OP_FILE_OP</td><td><xref target="workspace-plane"/></td></tr>
            <tr><td>0x06</td><td>OP_LOCK</td><td><xref target="mutual-exclusion"/></td></tr>
            <tr><td>0x07</td><td>OP_UNLOCK</td><td><xref target="mutual-exclusion"/></td></tr>
            <tr><td>0x08</td><td>OP_DNAC_RECOVERY</td><td><xref target="dnac-recovery"/></td></tr>
            <tr><td>0x09</td><td>OP_REKEY</td><td><xref target="k3-derivation"/></td></tr>
            <tr><td>0x0A</td><td>OP_HEARTBEAT</td><td><xref target="lifecycle"/></td></tr>
            <tr><td>0x0B</td><td>OP_ACK</td><td><xref target="opcode-registry-section"/></td></tr>
            <tr><td>0x0C</td><td>OP_ERROR</td><td><xref target="opcode-registry-section"/></td></tr>
            <tr><td>0x0D</td><td>OP_NACK</td><td><xref target="opcode-registry-section"/></td></tr>
            <tr><td>0x0E</td><td>OP_CHUNK</td><td>Reserved; future use</td></tr>
            <tr><td>0x0F</td><td>OP_SYNC</td><td>Reserved; future use</td></tr>
            <tr><td>0x10-0xEF</td><td>Unassigned</td><td></td></tr>
            <tr><td>0xF0-0xFF</td><td>Private Use</td><td></td></tr>
          </tbody>
        </table>
      </section>

      <section anchor="iana-caps" numbered="true" toc="default">
        <name>SCSWP Capability Flags Registry</name>
        <t>IANA is requested to create a new registry titled "SCSWP Capability Flags Registry"
        under the "SCSWP" registry group. Registration Policy: Specification Required
        <xref target="RFC8126"/>.</t>
        <table align="left">
          <thead><tr><th>Bit</th><th>Name</th><th>Value</th><th>Reference</th></tr></thead>
          <tbody>
            <tr><td>0</td><td>READ</td><td>1</td><td><xref target="capability-model"/></td></tr>
            <tr><td>1</td><td>WRITE</td><td>2</td><td><xref target="capability-model"/></td></tr>
            <tr><td>2</td><td>APPEND</td><td>4</td><td><xref target="capability-model"/></td></tr>
            <tr><td>3</td><td>CREATE</td><td>8</td><td><xref target="capability-model"/></td></tr>
            <tr><td>4</td><td>DELETE</td><td>16</td><td><xref target="capability-model"/></td></tr>
            <tr><td>5</td><td>RENAME</td><td>32</td><td><xref target="capability-model"/></td></tr>
            <tr><td>6</td><td>LOCK</td><td>64</td><td><xref target="capability-model"/></td></tr>
            <tr><td>7</td><td>ADMIN</td><td>128</td><td><xref target="capability-model"/></td></tr>
            <tr><td>8-31</td><td>Unassigned</td><td></td><td></td></tr>
          </tbody>
        </table>
      </section>

      <section anchor="iana-conflict" numbered="true" toc="default">
        <name>SCSWP Conflict Policy Registry</name>
        <t>IANA is requested to create a new registry titled "SCSWP Conflict Policy Registry"
        under the "SCSWP" registry group. Registration Policy: Specification Required
        <xref target="RFC8126"/>.</t>
        <table align="left">
          <thead><tr><th>Name</th><th>Reference</th></tr></thead>
          <tbody>
            <tr><td>REJECT</td><td><xref target="version-control"/></td></tr>
            <tr><td>RETRY</td><td><xref target="version-control"/></td></tr>
            <tr><td>MERGE</td><td><xref target="version-control"/></td></tr>
            <tr><td>REBASE</td><td><xref target="version-control"/></td></tr>
            <tr><td>CONFLICT_VERSION</td><td><xref target="version-control"/></td></tr>
          </tbody>
        </table>
      </section>

      <section anchor="iana-errors" numbered="true" toc="default">
        <name>SCSWP Error Code Registry</name>
        <t>IANA is requested to create a new registry titled "SCSWP Error Code Registry" under
        the "SCSWP" registry group. Registration Policy: Specification Required
        <xref target="RFC8126"/>.</t>
        <table align="left">
          <thead><tr><th>Code</th><th>Name</th><th>Description</th></tr></thead>
          <tbody>
            <tr><td>0x01</td><td>INVALID_BOOTSTRAP_TOKEN</td><td>Token not found or already used.</td></tr>
            <tr><td>0x02</td><td>TOKEN_EXPIRED</td><td>Token validity period elapsed.</td></tr>
            <tr><td>0x03</td><td>AUTH_FAILED</td><td>ECDH or certificate verification failed.</td></tr>
            <tr><td>0x04</td><td>NO_SESSION</td><td>session_id not found.</td></tr>
            <tr><td>0x05</td><td>FILE_LOCKED</td><td>File held by another session.</td></tr>
            <tr><td>0x06</td><td>VERSION_CONFLICT</td><td>expected_version mismatch.</td></tr>
            <tr><td>0x07</td><td>RETRY_REQUIRED</td><td>Client should re-fetch and retry.</td></tr>
            <tr><td>0x08</td><td>PERMISSION_DENIED</td><td>Client lacks required capability.</td></tr>
            <tr><td>0x09</td><td>SESSION_SUSPENDED</td><td>Trust score at or below threshold.</td></tr>
            <tr><td>0x0A</td><td>SERVER_BUSY</td><td>outstanding_ops limit reached.</td></tr>
            <tr><td>0x0B</td><td>SIGNATURE_INVALID</td><td>HMAC verification failed.</td></tr>
            <tr><td>0x0C</td><td>DNAC_MISMATCH</td><td>DNAC recovery hash mismatch.</td></tr>
            <tr><td>0x0D</td><td>UNKNOWN_OPCODE</td><td>Received opcode not recognized.</td></tr>
            <tr><td>0x0E</td><td>FILE_NOT_FOUND</td><td>Requested file does not exist.</td></tr>
            <tr><td>0x0F</td><td>WORKSPACE_NOT_FOUND</td><td>Workspace folder does not exist.</td></tr>
          </tbody>
        </table>
      </section>
    </section>

  </middle>

  <back>
    <references>
      <name>References</name>
      <references>
        <name>Normative References</name>
        <reference anchor="RFC2104" target="https://www.rfc-editor.org/info/rfc2104">
          <front><title>HMAC: Keyed-Hashing for Message Authentication</title>
          <author initials="H." surname="Krawczyk"/><author initials="M." surname="Bellare"/>
          <author initials="R." surname="Canetti"/><date month="February" year="1997"/></front>
          <seriesInfo name="RFC" value="2104"/></reference>
        <reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119">
          <front><title>Key words for use in RFCs to Indicate Requirement Levels</title>
          <author initials="S." surname="Bradner"/><date month="March" year="1997"/></front>
          <seriesInfo name="BCP" value="14"/><seriesInfo name="RFC" value="2119"/></reference>
        <reference anchor="RFC3629" target="https://www.rfc-editor.org/info/rfc3629">
          <front><title>UTF-8, a transformation format of ISO 10646</title>
          <author initials="F." surname="Yergeau"/><date month="November" year="2003"/></front>
          <seriesInfo name="STD" value="63"/><seriesInfo name="RFC" value="3629"/></reference>
        <reference anchor="RFC4086" target="https://www.rfc-editor.org/info/rfc4086">
          <front><title>Randomness Requirements for Security</title>
          <author initials="D." surname="Eastlake 3rd"/><author initials="J." surname="Schiller"/>
          <author initials="S." surname="Crocker"/><date month="June" year="2005"/></front>
          <seriesInfo name="BCP" value="106"/><seriesInfo name="RFC" value="4086"/></reference>
        <reference anchor="RFC4122" target="https://www.rfc-editor.org/info/rfc4122">
          <front><title>A Universally Unique IDentifier (UUID) URN Namespace</title>
          <author initials="P." surname="Leach"/><author initials="M." surname="Mealling"/>
          <author initials="R." surname="Salz"/><date month="July" year="2005"/></front>
          <seriesInfo name="RFC" value="4122"/></reference>
        <reference anchor="RFC4648" target="https://www.rfc-editor.org/info/rfc4648">
          <front><title>The Base16, Base32, and Base64 Data Encodings</title>
          <author initials="S." surname="Josefsson"/><date month="October" year="2006"/></front>
          <seriesInfo name="RFC" value="4648"/></reference>
        <reference anchor="RFC5234" target="https://www.rfc-editor.org/info/rfc5234">
          <front><title>Augmented BNF for Syntax Specifications: ABNF</title>
          <author initials="D." surname="Crocker" role="editor"/>
          <author initials="P." surname="Overell"/><date month="January" year="2008"/></front>
          <seriesInfo name="STD" value="68"/><seriesInfo name="RFC" value="5234"/></reference>
        <reference anchor="RFC5280" target="https://www.rfc-editor.org/info/rfc5280">
          <front><title>Internet X.509 Public Key Infrastructure Certificate and CRL Profile</title>
          <author initials="D." surname="Cooper"/><author initials="S." surname="Santesson"/>
          <author initials="S." surname="Farrell"/><author initials="S." surname="Boeyen"/>
          <author initials="R." surname="Housley"/><author initials="W." surname="Polk"/>
          <date month="May" year="2008"/></front>
          <seriesInfo name="RFC" value="5280"/></reference>
        <reference anchor="RFC5869" target="https://www.rfc-editor.org/info/rfc5869">
          <front><title>HMAC-based Extract-and-Expand Key Derivation Function (HKDF)</title>
          <author initials="H." surname="Krawczyk"/><author initials="P." surname="Eronen"/>
          <date month="May" year="2010"/></front>
          <seriesInfo name="RFC" value="5869"/></reference>
        <reference anchor="RFC5952" target="https://www.rfc-editor.org/info/rfc5952">
          <front><title>A Recommendation for IPv6 Address Text Representation</title>
          <author initials="S." surname="Kawamura"/><author initials="M." surname="Kawashima"/>
          <date month="August" year="2010"/></front>
          <seriesInfo name="RFC" value="5952"/></reference>
        <reference anchor="RFC7405" target="https://www.rfc-editor.org/info/rfc7405">
          <front><title>Case-Sensitive String Support in ABNF</title>
          <author initials="P." surname="Kyzivat"/><date month="December" year="2014"/></front>
          <seriesInfo name="RFC" value="7405"/></reference>
        <reference anchor="RFC8126" target="https://www.rfc-editor.org/info/rfc8126">
          <front><title>Guidelines for Writing an IANA Considerations Section in RFCs</title>
          <author initials="M." surname="Cotton"/><author initials="B." surname="Leiba"/>
          <author initials="T." surname="Narten"/><date month="June" year="2017"/></front>
          <seriesInfo name="BCP" value="26"/><seriesInfo name="RFC" value="8126"/></reference>
        <reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174">
          <front><title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
          <author initials="B." surname="Leiba"/><date month="May" year="2017"/></front>
          <seriesInfo name="BCP" value="14"/><seriesInfo name="RFC" value="8174"/></reference>
        <reference anchor="RFC8259" target="https://www.rfc-editor.org/info/rfc8259">
          <front><title>The JavaScript Object Notation (JSON) Data Interchange Format</title>
          <author initials="T." surname="Bray" role="editor"/><date month="December" year="2017"/></front>
          <seriesInfo name="STD" value="90"/><seriesInfo name="RFC" value="8259"/></reference>
        <reference anchor="RFC8422" target="https://www.rfc-editor.org/info/rfc8422">
          <front><title>ECC Cipher Suites for TLS Versions 1.2 and Earlier</title>
          <author initials="Y." surname="Nir"/><author initials="S." surname="Josefsson"/>
          <author initials="M." surname="Pegourie-Gonnard"/><date month="August" year="2018"/></front>
          <seriesInfo name="RFC" value="8422"/></reference>
        <reference anchor="RFC8446" target="https://www.rfc-editor.org/info/rfc8446">
          <front><title>The Transport Layer Security (TLS) Protocol Version 1.3</title>
          <author initials="E." surname="Rescorla"/><date month="August" year="2018"/></front>
          <seriesInfo name="RFC" value="8446"/></reference>
        <reference anchor="NIST.SP.800-38D" target="https://doi.org/10.6028/NIST.SP.800-38D">
          <front><title>Recommendation for Block Cipher Modes of Operation: GCM and GMAC</title>
          <author initials="M." surname="Dworkin"/><date month="November" year="2007"/></front>
          <seriesInfo name="NIST Special Publication" value="800-38D"/></reference>
        <reference anchor="FIPS.PUB.180-4" target="https://doi.org/10.6028/NIST.FIPS.180-4">
          <front><title>Secure Hash Standard (SHS)</title>
          <author><organization>NIST</organization></author>
          <date month="August" year="2015"/></front>
          <seriesInfo name="FIPS PUB" value="180-4"/></reference>
      </references>
      <references>
        <name>Informative References</name>
        <reference anchor="RFC4180" target="https://www.rfc-editor.org/info/rfc4180">
          <front><title>Common Format and MIME Type for CSV Files</title>
          <author initials="Y." surname="Shafranovich"/><date month="October" year="2005"/></front>
          <seriesInfo name="RFC" value="4180"/></reference>
        <reference anchor="RFC6151" target="https://www.rfc-editor.org/info/rfc6151">
          <front><title>Updated Security Considerations for the MD5 Message-Digest and HMAC-MD5</title>
          <author initials="S." surname="Turner"/><author initials="L." surname="Chen"/>
          <date month="March" year="2011"/></front>
          <seriesInfo name="RFC" value="6151"/></reference>
        <reference anchor="RFC6455" target="https://www.rfc-editor.org/info/rfc6455">
          <front><title>The WebSocket Protocol</title>
          <author initials="I." surname="Fette"/><author initials="A." surname="Melnikov"/>
          <date month="December" year="2011"/></front>
          <seriesInfo name="RFC" value="6455"/></reference>
        <reference anchor="RFC9000" target="https://www.rfc-editor.org/info/rfc9000">
          <front><title>QUIC: A UDP-Based Multiplexed and Secure Transport</title>
          <author initials="J." surname="Iyengar" role="editor"/>
          <author initials="M." surname="Thomson" role="editor"/><date month="May" year="2021"/></front>
          <seriesInfo name="RFC" value="9000"/></reference>
        <reference anchor="NIST.SP.800-57" target="https://doi.org/10.6028/NIST.SP.800-57pt1r5">
          <front><title>Recommendation for Key Management: Part 1 - General</title>
          <author initials="E." surname="Barker"/><date month="May" year="2020"/></front>
          <seriesInfo name="NIST Special Publication" value="800-57 Part 1 Rev. 5"/></reference>
        <reference anchor="NIST.PQC.FIPS.203" target="https://doi.org/10.6028/NIST.FIPS.203">
          <front><title>Module-Lattice-Based Key-Encapsulation Mechanism Standard</title>
          <author><organization>NIST</organization></author><date month="August" year="2024"/></front>
          <seriesInfo name="FIPS" value="203"/></reference>
        <reference anchor="SHOR1994">
          <front><title>Algorithms for Quantum Computation: Discrete Logarithms and Factoring</title>
          <author initials="P.W." surname="Shor"/><date year="1994"/></front>
          <refcontent>Proceedings of the 35th Annual Symposium on Foundations of Computer Science, pp. 124-134</refcontent>
        </reference>
      </references>
    </references>

    <!-- ============================================================ -->
    <section anchor="appendix-state-machine" numbered="true" toc="default">
      <name>Protocol State Machine</name>
      <figure anchor="fig-state-machine"><name>SCSWP Session State Machine</name>
        <artwork align="center"><![CDATA[
+-------------+  OP_PROVISION (valid token)  +-------------+
| UNREGISTERED|----------------------------->| BOOTSTRAP   |
+-------------+                              +------+------+
                                                    |
                                     OP_AUTH (ECDH) |
                                                    v
                                           +--------+--------+
                                           | AUTHENTICATING  |
                                           +--------+--------+
                                                    |
                                       K1 derived   |
                                                    v
                                           +--------+--------+
                                           |   K1 READY      |
                                           +--------+--------+
                                                    |
                                   K2, K3 derived   |
                                                    v
                                           +--------+--------+
                    +--------------------->|     ACTIVE      |<----+
                    |                      +--+---+---+------+     |
                    |                         |   |   |            |
                    | trust < REKEY_THRESHOLD |   |   |            |
                    |  +----------------------+   |   |            |
                    |  v                          |   |            |
                    | +-----------+  trust<=SUSP  |   | disconnect |
                    | |  REKEYING |  +------------+   |            |
                    | | (new K3)  |  |                |            |
                    | +-----+-----+  v                v            |
                    |       |  +----------+  +----------------+    |
                    +-------+  | SUSPENDED|  |  DISCONNECTED  |    |
                               +----------+  +-------+--------+    |
                                                     |             |
                                        DNAC valid   |             |
                                         +-----------+             |
                                         |   DNAC invalid          |
                                         v                         |
                                +--------+--------+                |
                                |    RECOVERED    +----------------+
                                | (new K3 epoch)  |
                                +-----------------+
        ]]></artwork>
      </figure>
    </section>

    <!-- ============================================================ -->
    <section anchor="appendix-crypto-rationale" numbered="true" toc="default">
      <name>Cryptographic Algorithm Rationale</name>
      <section anchor="rationale-p384" numbered="true" toc="default">
        <name>Choice of P-384</name>
        <t>P-384 provides 192 bits of security, significantly exceeding the NIST 128-bit minimum
        <xref target="NIST.SP.800-57"/>. The workspace domain model involves persistent client
        identities and long-lived shared workspaces, making the higher security margin appropriate.
        P-384 is performant on modern hardware and supported natively in all major cryptographic
        libraries.</t>
      </section>
      <section anchor="rationale-hkdf" numbered="true" toc="default">
        <name>Choice of HKDF-SHA256 for K1/K2/K3</name>
        <t>HKDF <xref target="RFC5869"/> provides domain separation through the info parameter;
        the "SCSWP_K1:", "SCSWP_K2:", and "SCSWP_K3:" prefixes ensure key material derived for
        different purposes cannot be confused. It also supports arbitrary output lengths, enabling
        a single HKDF call for K3 to produce all three subkeys simultaneously.</t>
      </section>
      <section anchor="rationale-aesgcm" numbered="true" toc="default">
        <name>Choice of AES-256-GCM</name>
        <t>AES-256-GCM provides authenticated encryption (confidentiality and integrity in a
        single pass), is hardware-accelerated via AES-NI on all major CPU architectures, and is
        the standard cipher suite in TLS 1.3 <xref target="RFC8446"/>.</t>
      </section>
      <section anchor="rationale-keysep" numbered="true" toc="default">
        <name>Key Separation and Purpose Binding</name>
        <t>The three K3 subkeys enforce cryptographic purpose separation. auth_key is used
        exclusively for HMAC-SHA-256 over D/N/P/S signals and MUST NOT be used for encryption.
        ctrl_key is used for AES-256-GCM encryption of control messages and MUST NOT be used
        for file payload encryption. payload_key is used for AES-256-GCM encryption of file
        content and MUST NOT be used for control messages. This separation ensures that a
        compromise of one subkey does not affect the security of the others.</t>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="appendix-message-flows" numbered="true" toc="default">
      <name>Example Message Flows</name>
      <section anchor="flow-initial" numbered="true" toc="default">
        <name>Initial Connection Flow</name>
        <figure anchor="fig-flow-initial"><name>Initial Connection Message Flow</name>
          <artwork align="center"><![CDATA[
Client                                          Server
------                                          ------
OP_PROVISION {bootstrap_token, hostname} ------>
                                          [Validate token]
                                          [Set is_active=TRUE]
                                          [Create session]
                                          [Load ACL]
      <----- OP_ACK {client_id, cert_pem, capabilities, session_id}

OP_AUTH {public_key_pem} -------------------->
                                          [ECDH exchange]
                                          [Derive K1, K2, K3]
      <--- OP_ACK {server_public_key, epoch=1, epoch_nonce_b64}

OP_TRUST_EVAL {dnps, sig, epoch=1} ---------->
                                          [Verify HMAC-sig]
                                          [Evaluate D/N/P/S]
      <------ OP_ACK {trust_score=100.0, rekey=false, epoch=1}
          ]]></artwork>
        </figure>
      </section>
      <section anchor="flow-write" numbered="true" toc="default">
        <name>File Write Flow (with Lock and Conflict Detection)</name>
        <figure anchor="fig-flow-write"><name>File Write Message Flow</name>
          <artwork align="center"><![CDATA[
Client                                          Server
------                                          ------
OP_LOCK {folder, filename} ------------------>
                                          [Check ACL: LOCK cap]
      <----------- OP_ACK {status="LOCKED", file_id}

OP_FILE_OP {op="WRITE", data_b64,
            expected_version=5,
            conflict_policy="REJECT",
            operation_id} ----------------->
                                          [ACL: WRITE cap check]
                                          [Idempotency check]
                                          [Version: server=5, OK]
                                          [Worker pool dispatch]
                                          [AES-256-GCM decrypt]
                                          [Write to disk + audit]
                                          [Advance DNAC]
      <---- OP_ACK {op="WRITE", filename, version=6}

OP_UNLOCK {folder, filename} -------------->
      <--------- OP_ACK {status="UNLOCKED"}
          ]]></artwork>
        </figure>
      </section>
      <section anchor="flow-recovery" numbered="true" toc="default">
        <name>DNAC Session Recovery Flow</name>
        <figure anchor="fig-flow-recovery"><name>DNAC Session Recovery Message Flow</name>
          <artwork align="center"><![CDATA[
Client                                          Server
------                                          ------
[reconnect after disconnect]
OP_DNAC_RECOVERY {client_id, last_dnac} ------>
                                          [Look up DNAC tip]
                                          [Compare hashes]
                                          [Rotate K3 to epoch N+1]
      <--- OP_ACK {status="SESSION_RESTORED",
                   epoch=N+1, epoch_nonce_b64}

[Client derives new K3; session resumes]
          ]]></artwork>
        </figure>
      </section>
      <section anchor="flow-rekey" numbered="true" toc="default">
        <name>Trust Score Rekey Flow</name>
        <figure anchor="fig-flow-rekey"><name>Trust Score Rekey Message Flow</name>
          <artwork align="center"><![CDATA[
Client                                          Server
------                                          ------
OP_TRUST_EVAL {dnps={network_ip changed},
               sig, epoch=3} --------------->
                                          [Apply -15 network penalty]
                                          [trust=85 -> below 80: YES]
                                          [Rotate K3 to epoch 4]
      <--- OP_ACK {trust_score=85, rekey=true,
                   epoch=4, epoch_nonce_b64="..."}

[Client derives K3 for epoch 4; all subsequent
 messages use epoch=4 and new K3 subkeys]
          ]]></artwork>
        </figure>
      </section>
    </section>

  </back>
</rfc>
