<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type='text/xsl' href='rfc2629.xslt' ?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     category="std"
     docName="draft-hebbar-zeropath-vpn-protocol-01"
     ipr="trust200902"
     obsoletes=""
     updates=""
     submissionType="IETF"
     xml:lang="en"
     tocInclude="true"
     tocDepth="4"
     symRefs="true"
     sortRefs="true"
     version="3">

  <!-- ============================================================ -->
  <!--  FRONT MATTER                                                 -->
  <!-- ============================================================ -->
  <front>
    <title abbrev="ZeroPath VPN Protocol Suite">
      ZeroPath VPN: Hop-Bound Secure Packet Validation with State-Bound
      Ephemeral Sessions, Cryptographic Attestation, and Opcode-Driven
      Control Architecture
    </title>

    <seriesInfo name="Internet-Draft"
                value="draft-hebbar-zeropath-vpn-protocol-01"/>

    <author fullname="Sripad Rama Hebbar" initials="S. R." surname="Hebbar">
      <organization>Independent Researcher</organization>
      <address>
        <postal>
          <country>India</country>
        </postal>
        <email>sripadkarthik@gmail.com</email>
        <uri>https://github.com/sripad2020/Zeropath-vpn</uri>
      </address>
    </author>

    <date year="2026" month="September"/>

    <area>ART</area>
    <workgroup>DISPATCH Working Group</workgroup>

    <keyword>VPN</keyword>
    <keyword>zero-trust</keyword>
    <keyword>HBSPV</keyword>
    <keyword>SGCP</keyword>
    <keyword>SCSWP</keyword>
    <keyword>hop-bound</keyword>
    <keyword>attestation</keyword>
    <keyword>ephemeral session</keyword>
    <keyword>opcode</keyword>
    <keyword>SOCKS5</keyword>
    <keyword>forward secrecy</keyword>
    <keyword>trust scoring</keyword>

    <abstract>
      <t>
        This document specifies the complete ZeroPath VPN protocol suite,
        comprising three coordinated sub-protocols:
      </t>
      <t>
        HBSPV (Hop-Bound Secure Packet Validation) -- a three-domain packet
        framing model that isolates payload decryption to the authorized
        egress node while allowing intermediate hops to validate forwarding
        context without accessing payload content.
      </t>
      <t>
        SGCP (State Graph Cryptographic Protocol) -- a three-message
        cryptographically attested handshake enforcing mutual authentication
        and device posture verification before any session is established.
      </t>
      <t>
        SCSWP (Secure Cryptographic Session Workspace Protocol) -- a
        continuous session state mechanism providing tamper-evident hash
        chain continuity, epoch-bound forward secrecy, and four-dimensional
        trust scoring across the full session lifetime.
      </t>
      <t>
        This document additionally specifies a complete opcode architecture
        governing all control-plane and data-plane message types, providing
        a machine-parseable, extensible message dispatch framework.
      </t>
      <t>
        The protocol suite is implemented as a pure Python reference
        implementation at
        <eref target="https://github.com/sripad2020/Zeropath-vpn"/>.
      </t>
    </abstract>
  </front>

  <!-- ============================================================ -->
  <!--  MIDDLE                                                       -->
  <!-- ============================================================ -->
  <middle>

    <!-- ========================================================= -->
    <!-- Section 1: Introduction                                    -->
    <!-- ========================================================= -->
    <section anchor="intro" numbered="true" toc="default">
      <name>Introduction</name>
      <t>
        The challenge of securing network sessions in a zero-trust
        architecture <xref target="NIST-ZT"/> requires satisfying several properties simultaneously:
      </t>
      <ol type="(%c)">
        <li>
          Per-hop payload isolation: intermediate routing nodes MUST be
          able to validate forwarding context without accessing the
          inner payload.  This is not satisfied by standard VPN tunnels,
          where any compromised hop can access all traffic.
        </li>
        <li>
          Pre-data cryptographic attestation: no application data SHOULD
          flow until both parties have proven their identity and device
          posture through a signed, freshness-checked exchange.
        </li>
        <li>
          State chain continuity: a tamper-evident record of every
          session operation MUST exist such that replaying, omitting, or
          reordering operations breaks the chain.
        </li>
        <li>
          Forward secrecy at event granularity: each significant session
          event (activation, migration, recovery) MUST produce fresh key
          material with mandatory erasure of the previous key, not merely
          at session boundaries.
        </li>
        <li>
          Continuous trust evaluation: the system MUST continuously
          assess device posture, network stability, protocol compliance,
          and session behavioral patterns, and MUST be able to suspend a
          session mid-flight without full teardown.
        </li>
        <li>
          Machine-parseable message dispatch: all control and data plane
          messages MUST be identifiable by a compact, versioned opcode
          to support efficient parsing, extension, and interoperability.
        </li>
      </ol>
      <t>
        ZeroPath VPN is designed to satisfy all six properties.
      </t>

      <section anchor="intro-philosophy" numbered="true" toc="default">
        <name>Design Philosophy</name>
        <t>
          The protocol is designed around the principle that security
          properties should be enforced by the protocol structure itself,
          not by access control lists applied to a protocol that does not
          enforce them intrinsically.
        </t>
        <t>
          Domain 3 payload isolation (property a) is architectural: the
          structure of the three-domain frame ensures that an intermediate
          hop cannot decrypt the payload even if it is compromised, because
          it does not possess the egress key.
        </t>
        <t>
          State chain continuity (property c) is enforced by making every
          session operation produce a new hash that depends on all previous
          operations.  There is no "skip" operation that could hide a
          tampered history.
        </t>
        <t>
          Forward secrecy at event granularity (property d) is enforced by
          requiring key erasure before the new key reference is stored.
          The implementation cannot complete an epoch rotation without
          overwriting the old key reference.
        </t>
      </section>

      <section anchor="intro-related" numbered="true" toc="default">
        <name>Relationship to Existing Protocols</name>
        <t>
          HBSPV is complementary to IPsec <xref target="RFC4301"/> and TLS <xref target="RFC8446"/>.  Where TLS provides
          confidentiality and authentication of the channel between two
          endpoints, HBSPV provides per-hop authorization of forwarding
          decisions along a multi-hop path, without requiring each hop to
          terminate and re-originate TLS. Legacy TLS versions 1.0 and 1.1 MUST NOT be used <xref target="RFC8996"/>.
        </t>
        <t>
          SGCP's attested handshake shares goals with QUIC's connection
          establishment <xref target="RFC9000"/> but adds device attestation and an
          eight-step server-side validation pipeline that goes beyond
          certificate verification.
        </t>
        <t>
          SCSWP's state chain and DNAC mechanism share conceptual
          similarity with Certificate Transparency <xref target="RFC9162"/> logs, but
          operate per-session rather than globally.
        </t>
      </section>

      <section anchor="intro-impl" numbered="true" toc="default">
        <name>Implementation</name>
        <t>
          A complete reference implementation <xref target="IMPL"/> in Python (pure standard
          library, zero external dependencies) is published on PyPI <xref target="PYPI"/> and available on GitHub at:
          <eref target="https://github.com/sripad2020/Zeropath-vpn"/>
        </t>
        <t>
          The implementation includes: REST control plane server,
          asyncio tunnel forwarder, interactive client CLI, asyncio
          SOCKS5 proxy, and a real-time web monitoring dashboard.
        </t>
      </section>
    </section>

    <!-- ========================================================= -->
    <!-- Section 2: Conventions and Terminology                     -->
    <!-- ========================================================= -->
    <section anchor="terminology" numbered="true" toc="default">
      <name>Conventions and Terminology</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>
      <dl newline="false" spacing="normal">
        <dt>HBSPV</dt>
        <dd>Hop-Bound Secure Packet Validation. The three-domain packet framing sub-protocol.</dd>
        <dt>SGCP</dt>
        <dd>State Graph Cryptographic Protocol. The attested handshake sub-protocol.</dd>
        <dt>SCSWP</dt>
        <dd>Secure Cryptographic Session Workspace Protocol. The session state continuity sub-protocol.</dd>
        <dt>Zession</dt>
        <dd>An ephemeral session instance. Each Zession has a unique ZessionId of the form "ZESS_&lt;10 hex chars&gt;".</dd>
        <dt>Epoch</dt>
        <dd>A bounded cryptographic period associated with a specific K3 key. A new Epoch is derived on each rotation trigger. The old K3 is erased when the Epoch ends.</dd>
        <dt>Epoch ID</dt>
        <dd>Identifier of the form "&lt;ZessionId&gt;_EPOCH_&lt;NNN&gt;" where NNN is a zero-padded three-digit epoch counter.</dd>
        <dt>Capsule</dt>
        <dd>An Endpoint Capsule (Section 6). A short-lived, server-signed descriptor of the server's identity, reachable endpoints, and policy reference.</dd>
        <dt>Dissolver</dt>
        <dd>The client-side bootstrap validator (Section 7) that applies seven mandatory validation steps to a Capsule.</dd>
        <dt>.hbspv</dt>
        <dd>The file extension used for the client configuration bundle. Contains the Capsule, key references, initial state hash, path profile, and policy.</dd>
        <dt>DNAC</dt>
        <dd>Dynamic Nonce-Authenticated Chain. An independent hash chain that advances in parallel with the state chain.</dd>
        <dt>K1</dt>
        <dd>Session Root Key reference. Established at provisioning time. Never stored as raw key material.</dd>
        <dt>K2</dt>
        <dd>Workspace Authentication Key reference. Derived from K1 with policy and path context.</dd>
        <dt>K3</dt>
        <dd>Epoch Key reference. Derived from K1, K2, and fresh entropy. Rotated on every epoch boundary event. Old K3 MUST be erased before the new K3 is stored.</dd>
        <dt>TOFU</dt>
        <dd>Trust On First Use. The initial fingerprint pinning strategy used by the Dissolver when no pre-configured trust anchor exists.</dd>
        <dt>Opcode</dt>
        <dd>A 2-byte big-endian unsigned integer identifying the type of a control-plane or data-plane message.</dd>
        <dt>Frame</dt>
        <dd>An HBSPV packet comprising three security domains.</dd>
        <dt>ZessionId</dt>
        <dd>Unique session identifier. Format: "ZESS_" + 10 random uppercase hex characters.</dd>
        <dt>ClientId</dt>
        <dd>Unique client identifier. Format: "CLT_" + 10 random uppercase hex characters.</dd>
        <dt>PathScore</dt>
        <dd>A floating-point value in [0, 100] indicating the quality of an authorized path profile.</dd>
        <dt>TrustScore</dt>
        <dd>A floating-point value in [0, 100] representing the composite four-dimensional trust evaluation for a Zession.</dd>
        <dt>Freshness Window</dt>
        <dd>The maximum age of a signed message that the server will accept. RECOMMENDED: 300 seconds.</dd>
      </dl>
    </section>

    <!-- ========================================================= -->
    <!-- Section 3: Protocol Architecture                           -->
    <!-- ========================================================= -->
    <section anchor="architecture" numbered="true" toc="default">
      <name>Protocol Architecture: Six Planes</name>
      <t>
        The ZeroPath VPN protocol suite is organized into six logical
        planes. Each plane is responsible for a distinct aspect of the protocol.
      </t>

      <section anchor="arch-planes" numbered="true" toc="default">
        <name>Plane Definitions</name>
        <table anchor="plane-table">
          <name>Six Logical Planes</name>
          <thead>
            <tr><th>Plane</th><th>Responsibility</th></tr>
          </thead>
          <tbody>
            <tr><td>Control Plane</td><td>Session lifecycle management. Exposes a REST API on TCP/3000. Handles provisioning, attestation, activation, migration, recovery, disconnect, and status.</td></tr>
            <tr><td>Bootstrap Plane</td><td>Endpoint Capsule delivery and Dissolver-based validation. Clients MUST complete bootstrap before entering the attestation plane.</td></tr>
            <tr><td>Attestation Plane</td><td>SGCP three-message handshake. No Zession is established without a completed handshake.</td></tr>
            <tr><td>State Plane</td><td>SCSWP authenticated hash chain, DNAC, K1/K2/K3 key hierarchy, and D/N/P/S trust scoring.</td></tr>
            <tr><td>Path Validation Plane</td><td>HBSPV three-domain packet framing and hop validation. Each packet carries its own forwarding authorization.</td></tr>
            <tr><td>Data Plane</td><td>SOCKS5 tunnel forwarder. Bidirectional TCP forwarding on TCP/4444 with ZessionId token authentication.</td></tr>
          </tbody>
        </table>
      </section>

      <section anchor="arch-phases" numbered="true" toc="default">
        <name>Plane Interaction and Phase Ordering</name>
        <t>A client MUST complete the following phases in strict order:</t>
        <dl newline="true" spacing="normal">
          <dt>Phase 1 -- Bootstrap:</dt>
          <dd>Obtain a Capsule from the server's Control Plane. Run the Dissolver seven-step validation. Initialize the local SCSWP state mirror.</dd>
          <dt>Phase 2 -- Attestation:</dt>
          <dd>Run the SGCP three-message attested handshake. All eight server-side validation pipeline steps MUST pass. Transcript hash stored by both parties.</dd>
          <dt>Phase 3 -- Activation:</dt>
          <dd>Register the ZessionId with the server's tunnel forwarder. Receive: assigned VPN IP, EpochId, TunnelPort. First epoch rotation is triggered at this point. K3 derived and stored; K3(prev) erased.</dd>
          <dt>Phase 4 -- Data:</dt>
          <dd>Start local SOCKS5 proxy (loopback only). Route browser traffic through proxy to server forwarder. Forwarder validates ZessionId token for every connection.</dd>
        </dl>
      </section>

      <section anchor="arch-ports" numbered="true" toc="default">
        <name>Port Assignments</name>
        <t>
          The following default port assignments apply. All are
          configurable via operator parameters or environment variables.
        </t>
        <ul>
          <li>TCP/3000 -- Control Plane REST API</li>
          <li>TCP/4444 -- Data Plane Tunnel Forwarder</li>
          <li>TCP/1080 -- Client-side SOCKS5 Proxy (loopback only)</li>
        </ul>
      </section>
    </section>

    <!-- ========================================================= -->
    <!-- Section 4: Client Lifecycle State Machine                  -->
    <!-- ========================================================= -->
    <section anchor="lifecycle" numbered="true" toc="default">
      <name>Client Lifecycle State Machine</name>
      <t>
        Each client progresses through the following states. These states
        are represented by the ClientStatus enumeration in the reference implementation.
      </t>

      <section anchor="lifecycle-states" numbered="true" toc="default">
        <name>States</name>
        <table anchor="state-table">
          <name>Client States</name>
          <thead>
            <tr><th>State</th><th>Meaning</th></tr>
          </thead>
          <tbody>
            <tr><td>PROVISIONED</td><td>Client record created on server. No Capsule generated yet.</td></tr>
            <tr><td>PACKAGE_READY</td><td>Capsule and client configuration bundle (.hbspv file) generated and available for download.</td></tr>
            <tr><td>DOWNLOADED</td><td>Client has received the .hbspv bundle.</td></tr>
            <tr><td>ATTESTING</td><td>SGCP handshake in progress.</td></tr>
            <tr><td>CONNECTED</td><td>Handshake complete, tunnel active, HBSPV path validated.</td></tr>
            <tr><td>DISCONNECTED</td><td>Transport dropped. Zession state retained. Recovery possible without re-provisioning.</td></tr>
            <tr><td>RECOVERING</td><td>Section 15 session recovery underway.</td></tr>
            <tr><td>TERMINATED</td><td>Zession dissolved. All key material erased.</td></tr>
          </tbody>
        </table>
      </section>

      <section anchor="lifecycle-events" numbered="true" toc="default">
        <name>SCSWP State Events Linked to Lifecycle</name>
        <t>Every lifecycle transition appends a record to the SCSWP state chain:</t>
        <ul>
          <li>OP_PROVISION -- Client created.</li>
          <li>OP_HANDSHAKE -- Attested handshake complete.</li>
          <li>OP_ACTIVATE -- Tunnel activated.</li>
          <li>OP_PACKET -- Each HBSPV test packet transmitted.</li>
          <li>OP_MIGRATE -- Path migration completed.</li>
          <li>OP_RECOVER -- Session recovery completed.</li>
          <li>OP_DISCONNECT -- Tunnel disconnected.</li>
          <li>OP_TERMINATE -- Session terminated and all keys erased.</li>
        </ul>
      </section>
    </section>

    <!-- ========================================================= -->
    <!-- Section 5: Five-Stage Trust Decision Model                 -->
    <!-- ========================================================= -->
    <section anchor="trust-model" numbered="true" toc="default">
      <name>Five-Stage Trust Decision Model</name>
      <t>
        Trust decisions in ZeroPath VPN are organized into five sequential
        stages. Each stage MUST be satisfied before the next stage is evaluated.
      </t>
      <dl newline="true" spacing="normal">
        <dt>Stage 1 -- IDENTITY</dt>
        <dd>Is the client identity recognized and valid? ClientId matches a provisioned record. Identity email format matches stored identity.</dd>
        <dt>Stage 2 -- DEVICE_TRUST</dt>
        <dd>Is the client device the one that was registered? Device reference ID matches stored device reference. Platform hash within acceptable variance. Device fingerprint change penalty applied if mismatch.</dd>
        <dt>Stage 3 -- ATTESTED_CONNECTION</dt>
        <dd>Has the SGCP handshake been completed successfully? All eight server-side validation steps passed. Ed25519 signatures verified on all three messages. Transcript hash stored and consistent.</dd>
        <dt>Stage 4 -- ZESSION_AUTHORIZATION</dt>
        <dd>Is the current Zession in a valid state for this operation? ZessionId matches. Trust score above suspension threshold (&gt; 10.0). Session not in TERMINATED or SUSPENDED state.</dd>
        <dt>Stage 5 -- PATH_AUTHORIZATION + HBSPV_HOP_VALIDATION</dt>
        <dd>Is the requested path authorized and are packets valid? PathProfileId is in the server's authorized path set. Policy compliance flag is TRUE for chosen path. HBSPV frame epoch matches current epoch. Packet sequence number is strictly monotonically increasing.</dd>
      </dl>
    </section>

    <!-- ========================================================= -->
    <!-- Section 6: Endpoint Capsule Structure                      -->
    <!-- ========================================================= -->
    <section anchor="capsule" numbered="true" toc="default">
      <name>Endpoint Capsule Structure</name>
      <t>
        The Endpoint Capsule is the server-signed descriptor that a client
        MUST validate through the Dissolver before connecting. It is the
        primary bootstrap trust anchor.
      </t>

      <section anchor="capsule-fields" numbered="true" toc="default">
        <name>Capsule Fields</name>
        <dl newline="true" spacing="normal">
          <dt>capsule_id (string, REQUIRED)</dt>
          <dd>A unique identifier for this specific capsule instance. Format: "CAP_" followed by random hex characters.</dd>
          <dt>zession_id (string, REQUIRED)</dt>
          <dd>The ZessionId for the session this capsule governs.</dd>
          <dt>server_identity (string, REQUIRED)</dt>
          <dd>A human-readable label identifying the server. Format: "sgcp-control.&lt;hostname&gt;". MUST NOT be a bare IP address.</dd>
          <dt>server_fqdn (string, REQUIRED)</dt>
          <dd>The Fully Qualified Domain Name of the server. A client MUST NOT connect if this field contains a bare IP.</dd>
          <dt>authorized_endpoints (array of strings, REQUIRED)</dt>
          <dd>Each element is an "&lt;IP&gt;:&lt;port&gt;" string. MUST contain at least one element. The client MUST NOT connect to any endpoint not in this list.</dd>
          <dt>transport_type (string, REQUIRED)</dt>
          <dd>The transport protocol. RECOMMENDED value: "TCP-ATTESTED".</dd>
          <dt>public_key_fingerprint (string, REQUIRED)</dt>
          <dd>The server's public key fingerprint. Format: "SHA256:&lt;base64url-encoded-SHA256-hash-of-public-key&gt;". Length of the hash portion MUST be at least 43 characters.</dd>
          <dt>policy_id (string, REQUIRED)</dt>
          <dd>The policy template governing this Zession. RECOMMENDED values: "POL_ZERO_TRUST_STRICT", "POL_ENTERPRISE_SPLIT", "POL_CLASSIFIED".</dd>
          <dt>nonce (string, REQUIRED)</dt>
          <dd>A unique random value preventing Capsule replay. MUST be at least 128 bits of random data (32 hex characters).</dd>
          <dt>expiration (string, REQUIRED)</dt>
          <dd>ISO 8601 UTC timestamp after which the Capsule is invalid. RECOMMENDED expiry window: 300 seconds from issuance.</dd>
          <dt>attestation_context_reference (string, REQUIRED)</dt>
          <dd>A SHA256 hash reference linking this Capsule to the client's device attestation context. Used in SGCP SYN message.</dd>
          <dt>signed_manifest_hash (string, REQUIRED)</dt>
          <dd>SHA256 hash of the full client configuration bundle.</dd>
          <dt>authentication_data (string, REQUIRED)</dt>
          <dd>A server-computed authentication credential over the Capsule fields.</dd>
        </dl>
      </section>

      <section anchor="capsule-delivery" numbered="true" toc="default">
        <name>Capsule Delivery</name>
        <t>
          The Capsule is delivered as part of the .hbspv JSON bundle via
          POST /api/clients/:id/package. The entire bundle is saved to disk
          (default: client_config.hbspv). The Capsule is validated by the
          Dissolver before any connection.
        </t>
      </section>

      <section anchor="capsule-validity" numbered="true" toc="default">
        <name>Capsule Validity Window</name>
        <t>
          The RECOMMENDED expiration window is 300 seconds from the time
          of generation. This short window limits the risk of a stolen
          Capsule being used to impersonate the legitimate client.
          Implementations that require longer validity windows for operational
          reasons SHOULD document their threat model rationale.
        </t>
      </section>
    </section>

    <!-- ========================================================= -->
    <!-- Section 7: Dissolver Bootstrap Validator                   -->
    <!-- ========================================================= -->
    <section anchor="dissolver" numbered="true" toc="default">
      <name>Dissolver Bootstrap Validator</name>
      <t>
        The Dissolver is the client-side engine that validates the Endpoint
        Capsule before any connection attempt. All seven steps MUST pass.
        Failure at any step MUST cause the client to refuse connection and
        SHOULD emit a diagnostic message identifying the failing step.
      </t>

      <section anchor="dissolver-s1" numbered="true" toc="default">
        <name>Step 1 -- Credential Recognition</name>
        <t>CONDITION: The publicKeyFingerprint field MUST be present and MUST NOT be empty.</t>
        <t>ON FAILURE: Reject connection with diagnostic "Credential Recognition FAILED -- fingerprint field absent or empty."</t>
      </section>

      <section anchor="dissolver-s2" numbered="true" toc="default">
        <name>Step 2 -- Certificate / Public Key Validation</name>
        <t>CONDITION: The publicKeyFingerprint MUST match the pattern: "SHA256:" followed by at least 32 characters.</t>
        <t>ON FAILURE: Reject with "Certificate Validation FAILED -- fingerprint format invalid."</t>
      </section>

      <section anchor="dissolver-s3" numbered="true" toc="default">
        <name>Step 3 -- Trust Anchor Selection</name>
        <t>CONDITION: If a pinned fingerprint exists, the Capsule's publicKeyFingerprint MUST match the pinned value. If no pinned fingerprint exists, the Capsule's fingerprint is accepted and pinned (TOFU).</t>
        <t>ON FAILURE: Reject with "Trust Anchor FAILED -- fingerprint does not match pinned value."</t>
      </section>

      <section anchor="dissolver-s4" numbered="true" toc="default">
        <name>Step 4 -- Identity Binding</name>
        <t>CONDITION: The serverIdentity field MUST consist of at least two components separated by a period. It MUST NOT be an IP address.</t>
        <t>ON FAILURE: Reject with "Identity Binding FAILED -- server identity malformed or bare IP."</t>
      </section>

      <section anchor="dissolver-s5" numbered="true" toc="default">
        <name>Step 5 -- Endpoint Validation</name>
        <t>CONDITION: The authorizedEndpoints array MUST be non-empty. The client MUST only attempt connections to endpoints listed in this array.</t>
        <t>ON FAILURE: Reject with "Endpoint Validation FAILED -- no authorized endpoints."</t>
      </section>

      <section anchor="dissolver-s6" numbered="true" toc="default">
        <name>Step 6 -- Server FQDN Validation</name>
        <t>CONDITION: The serverFQDN field MUST be present and MUST NOT be a bare IP address.</t>
        <t>ON FAILURE: Reject with "FQDN Validation FAILED -- serverFQDN absent or is a bare IP address."</t>
      </section>

      <section anchor="dissolver-s7" numbered="true" toc="default">
        <name>Step 7 -- Bootstrap Policy Validation</name>
        <t>CONDITION: All three of the following MUST be true: (a) expiration timestamp MUST be in the future; (b) nonce field MUST be present and non-empty; (c) attestationContextReference MUST be present and non-empty.</t>
        <t>ON FAILURE (expiry): If the server is reachable, the client SHOULD automatically delete the expired Capsule, request a new one, and re-run all seven steps.</t>
        <t>ON FAILURE (nonce or attestRef absent): Reject with "Bootstrap Policy FAILED -- nonce or attestationRef missing."</t>
      </section>
    </section>

    <!-- ========================================================= -->
    <!-- Section 8: SGCP Attested Handshake                         -->
    <!-- ========================================================= -->
    <section anchor="sgcp" numbered="true" toc="default">
      <name>SGCP: Attested Handshake</name>
      <t>
        The SGCP attested handshake is a three-message exchange that MUST
        complete before any Zession is considered established. It provides
        mutual authentication, device posture verification, nonce-based replay
        protection, timestamp freshness enforcement, an eight-step server-side
        validation pipeline, and transcript binding.
      </t>

      <section anchor="sgcp-syn" numbered="true" toc="default">
        <name>Attested SYN (Client to Server)</name>
        <t>The client builds the Attested SYN using the SGCPEngine. Fields include:</t>
        <dl newline="true" spacing="normal">
          <dt>client_id (string, REQUIRED)</dt>
          <dd>The client's identity string (email format preferred).</dd>
          <dt>device_identity_reference (string, REQUIRED)</dt>
          <dd>An opaque reference to the client's device identity record (DeviceRefId).</dd>
          <dt>device_context_reference (string, REQUIRED)</dt>
          <dd>SHA256(platform description string). Allows the server to detect device changes.</dd>
          <dt>client_nonce (string, REQUIRED)</dt>
          <dd>A 128-bit (32 hex character) cryptographically random value. MUST be unique across all sessions.</dd>
          <dt>timestamp (string, REQUIRED)</dt>
          <dd>ISO 8601 UTC timestamp. MUST be within the Freshness Window (RECOMMENDED: 300 seconds).</dd>
          <dt>connection_context (string, REQUIRED)</dt>
          <dd>SHA256("CONN_CTX:" + clientId + ":" + zessionId + ":" + unix_timestamp_float).</dd>
          <dt>protocol_version (string, REQUIRED)</dt>
          <dd>"HBSPV/2.0-SGCP/2.0"</dd>
          <dt>attestation_context (string, REQUIRED)</dt>
          <dd>The attestationContextReference from the Endpoint Capsule.</dd>
          <dt>digital_signature (string, REQUIRED)</dt>
          <dd>Ed25519 signature over pipe-delimited concatenation of all above fields. Format: "SIG_ED25519:&lt;32-hex-chars&gt;".</dd>
        </dl>
      </section>

      <section anchor="sgcp-pipeline" numbered="true" toc="default">
        <name>Server Eight-Step Validation Pipeline</name>
        <t>Upon receipt of the Attested SYN, the server MUST execute all eight steps in sequence. Failure at any step MUST terminate the handshake.</t>
        <ol>
          <li>Parse Attestation Context: verify all required fields are present and well-formed.</li>
          <li>Client ID Lookup: match client_id to the provisioned client record. Stored identity MUST exactly match.</li>
          <li>Certificate Check: verify client's publicKeyFingerprint is present and in correct format.</li>
          <li>Digital Signature Verification: reconstruct the signature payload and verify using client's stored public key reference with constant-time comparison.</li>
          <li>Device Context Check: verify device_identity_reference matches stored device reference.</li>
          <li>Nonce Validation and Replay Protection: if client_nonce already seen, MUST reject. If fresh, add to used-nonce set.</li>
          <li>Timestamp Freshness Check: reject if |current_UTC - syn.timestamp| &gt; 300 seconds.</li>
          <li>Policy Evaluation: verify client's assigned policy allows the requested connection context.</li>
        </ol>
      </section>

      <section anchor="sgcp-synack" numbered="true" toc="default">
        <name>Attested SYN-ACK (Server to Client)</name>
        <t>If all eight steps pass, the server constructs the Attested SYN-ACK containing: server_identity, server_certificate_reference, client_nonce_reference (echo of SYN nonce), server_nonce (fresh 128-bit random), timestamp, connection_context, attestation_context, digital_signature, and validation_pipeline (array of all eight step results).</t>
      </section>

      <section anchor="sgcp-ack" numbered="true" toc="default">
        <name>Attested ACK (Client to Server)</name>
        <t>The client verifies the SYN-ACK server signature, then builds the Attested ACK containing a transcript proof:</t>
        <t>transcript_reference = SHA256(syn.client_nonce | syn_ack.server_nonce | syn.connection_context | client_identity)</t>
        <t>This hash binds the ACK irrevocably to the specific three-way exchange. On success, AttestState transitions to HANDSHAKE_COMPLETE and the transcript_hash is stored. On failure, the Zession is NOT established and the client MUST delete the local Capsule and re-provision.</t>
      </section>
    </section>

    <!-- ========================================================= -->
    <!-- Section 9: SCSWP Session State Engine                      -->
    <!-- ========================================================= -->
    <section anchor="scswp" numbered="true" toc="default">
      <name>SCSWP: Session State Engine</name>
      <t>
        The SCSWP state engine maintains three parallel structures for
        each Zession: a K1/K2/K3 key hierarchy, a state hash chain, and
        a DNAC (Dynamic Nonce-Authenticated Chain).
      </t>

      <section anchor="scswp-keys" numbered="true" toc="default">
        <name>K1/K2/K3 Key Hierarchy</name>
        <t>K1 (Session Root Key): K1 = SHA256("K1:" + zessionId + ":" + sessionRootContext)[:16] + "...". Established once at provisioning time. Does not rotate within the Zession lifetime.</t>
        <t>K2 (Workspace Authentication Key): K2 = SHA256("K2:" + K1_ref + ":" + policyId + ":" + pathId)[:16] + "...". MUST be re-derived if the policy or authorized path profile changes.</t>
        <t>K3 (Epoch Key): fresh_nonce = random 128-bit value; K3 = SHA256("K3:" + K1_ref + ":" + K2_ref + ":EPOCH_" + epoch_counter + ":" + fresh_nonce)[:16] + "...". Derived fresh on each epoch rotation.</t>
        <t>When K3 is rotated, the previous K3 reference MUST be overwritten in storage before the new K3 reference is written. Production implementations MUST also erase the raw key material and zero the memory before overwriting.</t>
      </section>

      <section anchor="scswp-chain" numbered="true" toc="default">
        <name>State Hash Chain</name>
        <t>Initial state: state_hash(0) = SHA256("INIT:" + zessionId + ":" + timestamp)</t>
        <t>Subsequent states: state_hash(N) = SHA256(state_hash(N-1) + ":" + sequence_number + ":" + event_description + ":" + ISO8601_timestamp)</t>
        <t>Every Zession operation appends a new ScswpStateRecord to the chain. The chain is cryptographically linked; each record depends on all previous records.</t>
      </section>

      <section anchor="scswp-dnac" numbered="true" toc="default">
        <name>DNAC: Dynamic Nonce-Authenticated Chain</name>
        <t>The DNAC is a second, independent hash chain that advances in parallel with the state chain.</t>
        <t>Initialization: dnac(0) = "GENESIS"</t>
        <t>Advancement: dnac(N) = SHA256(dnac(N-1) + ":" + zessionId + ":" + operationId + ":" + workspaceState + ":" + ISO8601_timestamp)</t>
        <t>Session recovery (Section 15) MUST validate both the state hash and the DNAC value before resuming. An implementation MUST NOT allow recovery that resets the DNAC chain to a previous value.</t>
      </section>

      <section anchor="scswp-trust" numbered="true" toc="default">
        <name>Trust Scoring: D/N/P/S Model</name>
        <t>The trust score is a floating-point value in [0.0, 100.0] evaluated on every session operation across four dimensions:</t>
        <ul>
          <li>D -- Device Trust: device characteristics vs. those at session establishment.</li>
          <li>N -- Network Trust: IP address stability. A change triggers PENALTY_NETWORK_CHANGE (-15.0).</li>
          <li>P -- Protocol Trust: nonce freshness, timestamp validity, signature correctness, protocol version match.</li>
          <li>S -- Session Trust: operation rate and sequence number monotonicity. Rapid operations (&gt;20/10s) trigger PENALTY_RAPID_OPS (-5.0).</li>
        </ul>
        <table anchor="trust-table">
          <name>Trust Score Penalty and Reward Constants</name>
          <thead>
            <tr><th>Event</th><th>Delta</th><th>Constant</th></tr>
          </thead>
          <tbody>
            <tr><td>Network IP change</td><td>-15.0</td><td>PENALTY_NETWORK_CHANGE</td></tr>
            <tr><td>Device fingerprint change</td><td>-60.0</td><td>PENALTY_DEVICE_CHANGE</td></tr>
            <tr><td>Rapid operations (&gt;20/10s)</td><td>-5.0</td><td>PENALTY_RAPID_OPS</td></tr>
            <tr><td>Authentication failure</td><td>-25.0</td><td>PENALTY_AUTH_FAIL</td></tr>
            <tr><td>Stable operation (no issues)</td><td>+0.5</td><td>REWARD_STABLE_TRUST</td></tr>
          </tbody>
        </table>
        <t>If trust_score &lt;= TRUST_SUSPENSION (10.0): is_suspended = True; the server MUST refuse further requests.</t>
      </section>
    </section>

    <!-- ========================================================= -->
    <!-- Section 10: Security Epoch System                          -->
    <!-- ========================================================= -->
    <section anchor="epoch" numbered="true" toc="default">
      <name>Security Epoch System</name>
      <t>
        The Security Epoch System binds cryptographic key material to the
        authenticated session state. An epoch cannot be constructed without
        the current SCSWP state hash.
      </t>

      <section anchor="epoch-derivation" numbered="true" toc="default">
        <name>Epoch Derivation</name>
        <t>EpochId = ZessionId + "_EPOCH_" + zero_padded_epoch_number (e.g., "ZESS_A3B5C7D9E1_EPOCH_000").</t>
        <t>state_bound_hash = SHA256(prev_state_hash + ":" + fresh_entropy + ":" + session_transcript_ref + ":" + authorized_path_context)</t>
        <t>fresh_entropy MUST be at least 128 bits of cryptographically random data generated fresh for each epoch.</t>
      </section>

      <section anchor="epoch-triggers" numbered="true" toc="default">
        <name>Epoch Rotation Triggers</name>
        <t>An epoch MUST rotate on any of the following events:</t>
        <ul>
          <li>TRIGGER_ACTIVATION: client completes Phase 3 (tunnel activation).</li>
          <li>TRIGGER_MIGRATION: client migrates to a different authorized path profile.</li>
          <li>TRIGGER_RECOVERY: session recovery (Section 15) completes.</li>
          <li>TRIGGER_SCHEDULED: rekey interval elapsed (RECOMMENDED: 1800 seconds).</li>
        </ul>
      </section>

      <section anchor="epoch-erasure" numbered="true" toc="default">
        <name>Key Erasure Procedure</name>
        <t>The following procedure MUST be executed on each epoch rotation:</t>
        <ol>
          <li>Derive the new K3 reference from K1, K2, and fresh_entropy for the new epoch.</li>
          <li>Store the new K3 reference in a temporary variable.</li>
          <li>Overwrite the storage location of the old K3 reference with the new K3 reference value.</li>
          <li>Zero the temporary variable.</li>
          <li>Increment the epoch sequence number.</li>
          <li>Add an OP_ACTIVATE, OP_MIGRATE, or OP_RECOVER record to the SCSWP state chain, referencing the new EpochId.</li>
        </ol>
        <t>In production systems, Step 3 MUST use a memory barrier to prevent compiler or CPU reordering of the zero-write.</t>
      </section>
    </section>

    <!-- ========================================================= -->
    <!-- Section 11: HBSPV Three-Domain Packet Frame                -->
    <!-- ========================================================= -->
    <section anchor="hbspv" numbered="true" toc="default">
      <name>HBSPV: Three-Domain Packet Frame</name>
      <t>
        HBSPV defines a packet frame comprising three security domains.
        The architectural guarantee: "An intermediate authorized hop can
        validate all information it needs to make a forwarding decision
        without possessing the key material needed to decrypt the inner payload."
      </t>

      <section anchor="hbspv-d1" numbered="true" toc="default">
        <name>Domain 1: Outer Authenticated Forwarding Header</name>
        <t>Domain 1 is visible to and processable by ALL authorized hops. Key fields include: protocolVersion, compactZessionReference, packetSequenceNumber (monotonically increasing 64-bit, starting at 10001), securityEpochReference, currentHopReference, nextHopReference, validationStateReference, pathContextReference, attestationContextReference, deviceContextReference, and outerAuthTag (HMAC-SHA256(K2_ref, sequence_number + ":" + epochId)[:16]).</t>
        <t>All hops MUST verify the outerAuthTag. Hops MUST reject packets whose epoch reference does not match the currently expected epoch. Hops MUST reject any packet with a sequence number &lt;= the last accepted value.</t>
      </section>

      <section anchor="hbspv-d2" numbered="true" toc="default">
        <name>Domain 2: Protected Routing and Policy Context</name>
        <t>Domain 2 carries routing authorization evidence. Fields include: pathAuthorizationReference (full PathProfileId), policyReference, trustContextReference ("TRUST_SCORE:&lt;float&gt;"), routeConstraints (array: "NO_UNAUTHENTICATED_HOPS", "STRICT_EPOCH_MATCH", "STRICT_EGRESS_MATCH"), and routingAuthEvidence (Ed25519 signature over Domain 1 + Domain 2 fields).</t>
      </section>

      <section anchor="hbspv-d3" numbered="true" toc="default">
        <name>Domain 3: End-to-End Protected Inner Payload</name>
        <t>Domain 3 carries the actual application payload, encrypted such that ONLY the authorized egress gateway can decrypt it. Fields include: decryptionStatusAtIntermediateHops ("PROTECTED_CIPHERTEXT -- NOT DECRYPTED AT INTERMEDIATE HOPS"), targetDestination, innerProtocol, encryptedPayloadHex (AES-256-GCM ciphertext), and innerPayloadIntegrityTag (POLY1305 authentication tag).</t>
      </section>

      <section anchor="hbspv-hop-records" numbered="true" toc="default">
        <name>Hop Validation Records</name>
        <t>Each hop that processes an HBSPV frame appends a HopRecord to the frame's hop_validation_chain. Fields: hop_id, zession_reference, packet_sequence_reference, security_epoch, path_context_reference, validation_result ("HOP_VALIDATED", "FINAL_VALIDATED", or "REJECTED"), freshness_context, authenticated_validation_evidence, and inner_payload_decrypted (boolean, MUST be False at all hops except the authorized egress).</t>
      </section>

      <section anchor="hbspv-roles" numbered="true" toc="default">
        <name>Hop Processing Rules by Role</name>
        <t>Entry Gateway: MUST validate Domain 1 outerAuthTag, epoch, sequence number, Domain 2 routeConstraints and routingAuthEvidence. MUST NOT attempt to decrypt Domain 3. MUST set HopRecord.inner_payload_decrypted = False.</t>
        <t>Infrastructure Hop: MUST validate Domain 1 outerAuthTag and epoch. MUST NOT access Domain 2 or Domain 3 or modify any domain.</t>
        <t>Egress Gateway: MUST validate all Domain 1 and Domain 2 fields including "STRICT_EGRESS_MATCH". MUST decrypt Domain 3 using the Zession's egress key (K3-derived) and verify innerPayloadIntegrityTag before forwarding plaintext. MUST set HopRecord.inner_payload_decrypted = True and HopRecord.validation_result = "FINAL_VALIDATED".</t>
      </section>
    </section>

    <!-- ========================================================= -->
    <!-- Section 12: Opcode Architecture                            -->
    <!-- ========================================================= -->
    <section anchor="opcodes" numbered="true" toc="default">
      <name>Opcode Architecture</name>
      <t>
        The opcode architecture provides a compact, versioned, machine-parseable
        identifier for every message type exchanged in the ZeroPath VPN protocol suite.
      </t>

      <section anchor="opcode-encoding" numbered="true" toc="default">
        <name>Opcode Encoding</name>
        <t>Each message MUST begin with a 16-byte Opcode Header:</t>
        <artwork name="" type="ascii-art" align="left"><![CDATA[
  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |          Opcode (16 bits)     |   Version (8 bits)            |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |          Flags (8 bits)       |    Payload Length (32 bits)   |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |           Payload Length continued (MSB to LSB)               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                      Session ID (64 bits)                     |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                  Payload (variable, JSON encoded)             |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        ]]></artwork>
        <t>Flags bits: Bit 7 (ENCRYPTED), Bit 6 (SIGNED), Bit 5 (FRAGMENTED), Bit 4 (LAST_FRAG). Bits 3-0 Reserved, MUST be zero. Version 0x02 corresponds to "HBSPV/2.0-SGCP/2.0".</t>
        <table anchor="opcode-ranges">
          <name>Opcode Ranges</name>
          <thead><tr><th>Range</th><th>Category</th></tr></thead>
          <tbody>
            <tr><td>0x0001-0x00FF</td><td>Control Plane: Lifecycle Opcodes</td></tr>
            <tr><td>0x0100-0x01FF</td><td>Control Plane: Session Management Opcodes</td></tr>
            <tr><td>0x0200-0x02FF</td><td>Control Plane: Bootstrap Opcodes</td></tr>
            <tr><td>0x0300-0x03FF</td><td>Data Plane: Tunnel Opcodes</td></tr>
            <tr><td>0x0400-0x04FF</td><td>State Opcodes</td></tr>
            <tr><td>0x0500-0x05FF</td><td>Error Opcodes</td></tr>
            <tr><td>0x0600-0xEFFF</td><td>Reserved for future use</td></tr>
            <tr><td>0xF000-0xFFFF</td><td>Vendor/Experimental. Not to be standardized.</td></tr>
          </tbody>
        </table>
      </section>

      <section anchor="opcode-control" numbered="true" toc="default">
        <name>Control Plane Opcodes</name>
        <t>0x0001 OP_PROVISION_REQUEST (C-&gt;S): Request provisioning. Payload: identity, department, device_name, platform, policy_id.</t>
        <t>0x0002 OP_PROVISION_RESPONSE (S-&gt;C): Return client_id and zession_id.</t>
        <t>0x0003 OP_PACKAGE_REQUEST (C-&gt;S): Request .hbspv bundle download.</t>
        <t>0x0004 OP_PACKAGE_RESPONSE (S-&gt;C, ENCRYPTED|SIGNED): Deliver complete .hbspv client configuration bundle.</t>
        <t>0x0005 OP_ATTEST_SYN (C-&gt;S, SIGNED): Carry the Attested SYN (Section 8.1).</t>
        <t>0x0006 OP_ATTEST_SYNACK (S-&gt;C, SIGNED): Carry the Attested SYN-ACK and pipeline results (Section 8.3).</t>
        <t>0x0007 OP_ATTEST_ACK (C-&gt;S, SIGNED): Carry the Attested ACK with transcript proof (Section 8.4).</t>
        <t>0x0008 OP_ATTEST_COMPLETE (S-&gt;C): Confirm handshake completion. Payload: status, transcript_hash, validation_pipeline.</t>
        <t>0x0009 OP_ACTIVATE_REQUEST (C-&gt;S, SIGNED): Request tunnel activation.</t>
        <t>0x000A OP_ACTIVATE_RESPONSE (S-&gt;C, ENCRYPTED): Confirm activation; deliver assigned_ip, epoch_id, tunnel_port, trust_score, state_hash.</t>
        <t>0x000B OP_DISCONNECT_REQUEST (C-&gt;S): Signal voluntary disconnection.</t>
        <t>0x000C OP_DISCONNECT_RESPONSE (S-&gt;C): Confirm disconnection with final state_hash and epoch_id.</t>
      </section>

      <section anchor="opcode-data" numbered="true" toc="default">
        <name>Data Plane Opcodes</name>
        <t>0x0300 OP_TUNNEL_CONNECT (C-&gt;S): Initiate tunneled connection. Wire: 4-byte big-endian length prefix + JSON payload: {type, host, port, token (ZessionId)}.</t>
        <t>0x0301 OP_TUNNEL_CONNECT_ACK (S-&gt;C): Confirm connection success. After this opcode, both sides enter raw TCP forwarding mode.</t>
        <t>0x0302 OP_TUNNEL_UNAUTHORIZED (S-&gt;C): Reject tunnel connection. Server MUST close TCP connection immediately after sending.</t>
        <t>0x0303 OP_TUNNEL_DATA (bidirectional, ENCRYPTED|SIGNED): Carry HBSPV-framed application data. Defined for future per-packet framing implementations.</t>
        <t>0x0304 OP_TUNNEL_CLOSE (bidirectional): Signal graceful tunnel teardown. Reason: "CLIENT_CLOSE", "SERVER_CLOSE", or "TIMEOUT".</t>
      </section>

      <section anchor="opcode-state" numbered="true" toc="default">
        <name>State Opcodes</name>
        <t>0x0400 OP_MIGRATE_REQUEST (C-&gt;S, SIGNED): Request migration to different path profile.</t>
        <t>0x0401 OP_MIGRATE_RESPONSE (S-&gt;C, ENCRYPTED): Confirm migration; deliver new epoch_id, state_hash, trust_score, path_profile.</t>
        <t>0x0402 OP_RECOVER_REQUEST (C-&gt;S, SIGNED): Request session recovery. Payload includes current_state_hash for server-side validation.</t>
        <t>0x0403 OP_RECOVER_RESPONSE (S-&gt;C, ENCRYPTED): Confirm recovery; deliver recovered_epoch, state_hash, trust_score=100.</t>
        <t>0x0404 OP_EPOCH_ROTATE (S-&gt;C, ENCRYPTED|SIGNED): Notify client of scheduled epoch rotation.</t>
        <t>0x0405 OP_STATUS_REQUEST (C-&gt;S): Request current session status.</t>
        <t>0x0406 OP_STATUS_RESPONSE (S-&gt;C): Return full session status including trust_score, epoch_id, state_hash, dnac_length, capabilities.</t>
      </section>

      <section anchor="opcode-error" numbered="true" toc="default">
        <name>Error Opcodes</name>
        <t>0x0500 OP_ERROR_GENERIC (S-&gt;C): General error response. Payload: error_code, error_message, opcode_ref.</t>
        <t>0x0501 OP_ERROR_AUTH_FAIL (S-&gt;C): Authentication or signature verification failure. Payload: step, trust_score (after PENALTY_AUTH_FAIL), detail.</t>
        <t>0x0502 OP_ERROR_REPLAY (S-&gt;C): Nonce replay or sequence number violation. Payload: replay_type ("NONCE_REPLAY" or "SEQ_REPLAY"), rejected_nonce, expected_seq, received_seq.</t>
        <t>0x0503 OP_ERROR_CAPSULE_EXPIRED (S-&gt;C or local Dissolver): Capsule expiry notification. Payload: expired_at, capsule_id, action ("AUTO_REPROVISION" if applicable).</t>
        <t>0x0504 OP_ERROR_TRUST_SUSPENDED (S-&gt;C): Session suspended due to trust score collapse. Payload: trust_score (&lt;= 10.0), suspension_at, reason.</t>
        <t>0x0505 OP_ERROR_EPOCH_MISMATCH (hop to sending node): Epoch mismatch detected in HBSPV frame. Payload: expected_epoch, received_epoch, hop_id.</t>
      </section>
    </section>

    <!-- ========================================================= -->
    <!-- Section 13: Authorized Path Selection                      -->
    <!-- ========================================================= -->
    <section anchor="path-selection" numbered="true" toc="default">
      <name>Authorized Path Selection</name>
      <t>
        A client MUST only use paths that appear in its provisioned PathProfile
        and that satisfy all three conditions: Authorized, Reachable, and Policy-Compliant.
      </t>
      <t>A path is authorized if: (a) the PathProfileId appears in the server's known path profiles; (b) policy_compliant == True for the client's assigned policy; (c) the path score is above the policy's minimum path score.</t>
      <t>Unauthorized path selection MUST be rejected by the server at migration time and by the egress at packet validation time.</t>
      <t>Each PathProfile contains: profile_id, name, ordered hops array (each hop with hop_id, ip, role, region, validation_status), path_score ([0.0, 100.0]), latency_ms, loss_rate, gateway_load, trust_level, and policy_compliant (boolean).</t>
    </section>

    <!-- ========================================================= -->
    <!-- Section 14: Data Plane SOCKS5 Tunnel Forwarder             -->
    <!-- ========================================================= -->
    <section anchor="data-plane" numbered="true" toc="default">
      <name>Data Plane: SOCKS5 Tunnel Forwarder</name>
      <t>
        The data plane uses an extended SOCKS5 protocol <xref target="RFC1928"/> with
        a ZessionId-based authentication handshake. The client SOCKS5 proxy
        MUST listen on 127.0.0.1 (IPv4 loopback only). MUST NOT listen on 0.0.0.0 or any non-loopback interface.
      </t>
      <t>
        When a browser sends a SOCKS5 CONNECT with a domain name target (ATYP=0x03), the proxy MUST forward the domain name in the "host" field of OP_TUNNEL_CONNECT without resolving it locally. The forwarder resolves the domain on the server side, preventing DNS leaks to the client's local resolver or ISP.
      </t>
      <t>
        The tunnel handshake uses 4-byte big-endian length-prefixed JSON framing. After the server sends OP_TUNNEL_CONNECT_ACK, both parties enter raw TCP forwarding mode.
      </t>
      <t>
        The server forwarder maintains an in-memory set of active ZessionIds. Token validation MUST use a constant-time comparison to prevent timing-based token enumeration. A ZessionId is removed from this set when the session is disconnected, revoked by an operator, or suspended due to trust score collapse.
      </t>
    </section>

    <!-- ========================================================= -->
    <!-- Section 15: Session Recovery                               -->
    <!-- ========================================================= -->
    <section anchor="recovery" numbered="true" toc="default">
      <name>Session Recovery</name>
      <t>
        Session recovery allows a client to resume a disconnected Zession
        without re-provisioning. The following invariants MUST be maintained:
      </t>
      <ul>
        <li>Invariant 1 (State Continuity): client's SCSWP state hash MUST match the server's stored state hash before recovery is permitted.</li>
        <li>Invariant 2 (No Key Reuse): recovery MUST derive a new K3 using fresh entropy. Old K3 MUST be erased before new K3 is stored.</li>
        <li>Invariant 3 (DNAC Continuity): DNAC chain MUST advance on recovery. An implementation MUST NOT allow recovery that resets the DNAC chain to a previous value.</li>
      </ul>
      <t>Recovery procedure (7 steps): (1) client sends OP_RECOVER_REQUEST with current_state_hash; (2) server validates state hash with constant-time comparison; (3) server derives new K3 and epoch; (4) server advances SCSWP state chain; (5) server returns OP_RECOVER_RESPONSE; (6) server resets trust score to 100.0; (7) client stores new epoch ID and state hash and may re-activate the tunnel.</t>
    </section>

    <!-- ========================================================= -->
    <!-- Section 16: Path Migration                                 -->
    <!-- ========================================================= -->
    <section anchor="migration" numbered="true" toc="default">
      <name>Path Migration</name>
      <t>
        Path migration allows a CONNECTED client to switch to a different
        authorized path profile without re-attesting or re-provisioning.
        Migration triggers a mandatory epoch rotation.
      </t>
      <t>Migration procedure (6 steps): (1) client sends OP_MIGRATE_REQUEST with target PathProfileId; (2) server validates authorization (profile exists, policy_compliant == True, trust score above TRUST_SUSPENSION); (3) server rotates K3 and epoch with trigger "Path Migration: &lt;old&gt; -&gt; &lt;new&gt;"; (4) server updates session state (OP_MIGRATE record, DNAC advance); (5) server returns OP_MIGRATE_RESPONSE; (6) client stores new epoch ID, state hash, and updates active path profile. Client MUST NOT use old epoch for any further packets.</t>
    </section>

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

      <section anchor="sec-replay" numbered="true" toc="default">
        <name>Replay Attack Prevention</name>
        <t>Client nonces are tracked in a per-ZessionId used-nonce set persisting for the lifetime of the Zession. In production deployments, this set MUST be persisted to durable storage to survive server restarts. Packet sequence numbers provide replay protection at the data plane; hops MUST reject any packet with a sequence number &lt;= the last accepted value.</t>
      </section>

      <section anchor="sec-fs" numbered="true" toc="default">
        <name>Forward Secrecy</name>
        <t>Forward secrecy is provided at epoch granularity. Compromise of the current K3 does not expose traffic encrypted under previous K3 values, provided that erasure was correctly performed. Each K3 incorporates fresh entropy not present in previous derivations. Production implementations SHOULD use HKDF <xref target="RFC5869"/> with os.urandom() as the entropy source.</t>
      </section>

      <section anchor="sec-d3" numbered="true" toc="default">
        <name>Domain 3 Confidentiality</name>
        <t>The Domain 3 payload isolation guarantee holds under the following assumptions: (a) the egress decryption key is not shared with intermediate hops; (b) intermediate hop implementations do not attempt to buffer and decrypt Domain 3 out-of-band; (c) the AES-256-GCM implementation is correct. Production deployments MUST place entry gateways, infrastructure hops, and egress gateways on separate, isolated physical or virtual hosts.</t>
      </section>

      <section anchor="sec-trust" numbered="true" toc="default">
        <name>Trust Score Manipulation</name>
        <t>An adversary may attempt to inflate the trust score by flooding stable operations. The maximum score is capped at 100.0. A more practical attack is to force session suspension by triggering rapid operations or network changes. Implementations SHOULD rate-limit external inputs that could trigger penalties.</t>
      </section>

      <section anchor="sec-hash" numbered="true" toc="default">
        <name>State Hash Forgery</name>
        <t>The state hash chain uses SHA256, which is currently collision-resistant. Implementations SHOULD monitor for future weaknesses and plan migration to SHA3-256 if collision attacks emerge.</t>
      </section>

      <section anchor="sec-opcode" numbered="true" toc="default">
        <name>Opcode Injection</name>
        <t>The control plane REST API MUST be protected by TLS in production. All API endpoints MUST require ZessionId or ClientId validation. In environments without TLS, an attacker on the same network could inject crafted opcodes.</t>
      </section>

      <section anchor="sec-socks5" numbered="true" toc="default">
        <name>SOCKS5 Proxy Scope</name>
        <t>The SOCKS5 proxy MUST bind only to 127.0.0.1. Binding to 0.0.0.0 or a non-loopback interface would allow other hosts to use the proxy without authentication. On Windows, implementations MUST use the explicit IP address string "127.0.0.1" when binding to avoid IPv6 ambiguity with "localhost".</t>
      </section>

      <section anchor="sec-capsule" numbered="true" toc="default">
        <name>Capsule Theft</name>
        <t>A stolen Capsule cannot complete a handshake from a different device because: (a) Step 5 (Device Context Check) will fail if the device reference does not match; and (b) Step 4 (Signature Verification) will fail because the attacker does not have the client's private key. The 300-second expiry window limits the window of opportunity.</t>
      </section>

      <section anchor="sec-primitives" numbered="true" toc="default">
        <name>Cryptographic Primitive Recommendations</name>
        <t>Production implementations MUST: use real Ed25519 <xref target="RFC8032"/> for all digital signatures; use AES-256-GCM for Domain 3 encryption; use HKDF <xref target="RFC5869"/> for all key derivations; use a CSPRNG (os.urandom()) for all random value generation; use constant-time comparison (hmac.compare_digest) for all cryptographic value comparisons.</t>
      </section>

      <section anchor="sec-termination" numbered="true" toc="default">
        <name>Session Termination and Secret Destruction</name>
        <t>When a Zession is terminated, the implementation MUST: erase K3, K2, and K1 references; zero the state hash buffer; remove the ZessionId from the active session token set. Only ArchivedEpoch records (without key material) are retained for audit purposes.</t>
      </section>
    </section>

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

      <section anchor="iana-ports" numbered="true" toc="default">
        <name>Port Number Registrations</name>
        <t>This document requests registration of the following TCP port numbers in the IANA Service Name and Transport Protocol Port Number Registry:</t>
        <table anchor="port-table">
          <name>Port Registration Requests</name>
          <thead><tr><th>Service Name</th><th>Port</th><th>Transport</th><th>Description</th></tr></thead>
          <tbody>
            <tr><td>zeropath-ctrl</td><td>3000</td><td>TCP</td><td>ZeroPath VPN Control Plane REST API (HBSPV/SGCP)</td></tr>
            <tr><td>zeropath-tunnel</td><td>4444</td><td>TCP</td><td>ZeroPath VPN Data Plane Tunnel Forwarder (HBSPV)</td></tr>
          </tbody>
        </table>
      </section>

      <section anchor="iana-version" numbered="true" toc="default">
        <name>Protocol Version String Registry</name>
        <t>This document requests creation of a new IANA registry "ZeroPath VPN Protocol Version Strings". Initial registration: HBSPV/2.0-SGCP/2.0 -- ZeroPath VPN version 2.0 -- This document.</t>
      </section>

      <section anchor="iana-opcodes" numbered="true" toc="default">
        <name>Opcode Registry</name>
        <t>This document requests creation of a new IANA registry "ZeroPath VPN Opcode Registry". Policy: Specification Required for range 0x0001-0xEFFF. First Come First Served for range 0xF000-0xFFFF.</t>
        <table anchor="opcode-registry">
          <name>Initial Opcode Registry</name>
          <thead><tr><th>Value</th><th>Name</th><th>Section</th></tr></thead>
          <tbody>
            <tr><td>0x0001</td><td>OP_PROVISION_REQUEST</td><td><xref target="opcode-control"/></td></tr>
            <tr><td>0x0002</td><td>OP_PROVISION_RESPONSE</td><td><xref target="opcode-control"/></td></tr>
            <tr><td>0x0003</td><td>OP_PACKAGE_REQUEST</td><td><xref target="opcode-control"/></td></tr>
            <tr><td>0x0004</td><td>OP_PACKAGE_RESPONSE</td><td><xref target="opcode-control"/></td></tr>
            <tr><td>0x0005</td><td>OP_ATTEST_SYN</td><td><xref target="opcode-control"/></td></tr>
            <tr><td>0x0006</td><td>OP_ATTEST_SYNACK</td><td><xref target="opcode-control"/></td></tr>
            <tr><td>0x0007</td><td>OP_ATTEST_ACK</td><td><xref target="opcode-control"/></td></tr>
            <tr><td>0x0008</td><td>OP_ATTEST_COMPLETE</td><td><xref target="opcode-control"/></td></tr>
            <tr><td>0x0009</td><td>OP_ACTIVATE_REQUEST</td><td><xref target="opcode-control"/></td></tr>
            <tr><td>0x000A</td><td>OP_ACTIVATE_RESPONSE</td><td><xref target="opcode-control"/></td></tr>
            <tr><td>0x000B</td><td>OP_DISCONNECT_REQUEST</td><td><xref target="opcode-control"/></td></tr>
            <tr><td>0x000C</td><td>OP_DISCONNECT_RESPONSE</td><td><xref target="opcode-control"/></td></tr>
            <tr><td>0x0300</td><td>OP_TUNNEL_CONNECT</td><td><xref target="opcode-data"/></td></tr>
            <tr><td>0x0301</td><td>OP_TUNNEL_CONNECT_ACK</td><td><xref target="opcode-data"/></td></tr>
            <tr><td>0x0302</td><td>OP_TUNNEL_UNAUTHORIZED</td><td><xref target="opcode-data"/></td></tr>
            <tr><td>0x0303</td><td>OP_TUNNEL_DATA</td><td><xref target="opcode-data"/></td></tr>
            <tr><td>0x0304</td><td>OP_TUNNEL_CLOSE</td><td><xref target="opcode-data"/></td></tr>
            <tr><td>0x0400</td><td>OP_MIGRATE_REQUEST</td><td><xref target="opcode-state"/></td></tr>
            <tr><td>0x0401</td><td>OP_MIGRATE_RESPONSE</td><td><xref target="opcode-state"/></td></tr>
            <tr><td>0x0402</td><td>OP_RECOVER_REQUEST</td><td><xref target="opcode-state"/></td></tr>
            <tr><td>0x0403</td><td>OP_RECOVER_RESPONSE</td><td><xref target="opcode-state"/></td></tr>
            <tr><td>0x0404</td><td>OP_EPOCH_ROTATE</td><td><xref target="opcode-state"/></td></tr>
            <tr><td>0x0405</td><td>OP_STATUS_REQUEST</td><td><xref target="opcode-state"/></td></tr>
            <tr><td>0x0406</td><td>OP_STATUS_RESPONSE</td><td><xref target="opcode-state"/></td></tr>
            <tr><td>0x0500</td><td>OP_ERROR_GENERIC</td><td><xref target="opcode-error"/></td></tr>
            <tr><td>0x0501</td><td>OP_ERROR_AUTH_FAIL</td><td><xref target="opcode-error"/></td></tr>
            <tr><td>0x0502</td><td>OP_ERROR_REPLAY</td><td><xref target="opcode-error"/></td></tr>
            <tr><td>0x0503</td><td>OP_ERROR_CAPSULE_EXPIRED</td><td><xref target="opcode-error"/></td></tr>
            <tr><td>0x0504</td><td>OP_ERROR_TRUST_SUSPENDED</td><td><xref target="opcode-error"/></td></tr>
            <tr><td>0x0505</td><td>OP_ERROR_EPOCH_MISMATCH</td><td><xref target="opcode-error"/></td></tr>
          </tbody>
        </table>
      </section>
    </section>

  </middle>

  <!-- ============================================================ -->
  <!--  BACK MATTER                                                  -->
  <!-- ============================================================ -->
  <back>
    <references>
      <name>References</name>

      <references>
        <name>Normative References</name>

        <reference anchor="RFC1928" target="https://www.rfc-editor.org/rfc/rfc1928">
          <front>
            <title>SOCKS Protocol Version 5</title>
            <author initials="M." surname="Leech" fullname="M. Leech"/>
            <date year="1996" month="March"/>
          </front>
          <seriesInfo name="RFC" value="1928"/>
        </reference>

        <reference anchor="RFC2119" target="https://www.rfc-editor.org/rfc/rfc2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author initials="S." surname="Bradner" fullname="S. Bradner"/>
            <date year="1997" month="March"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
        </reference>

        <reference anchor="RFC5869" target="https://www.rfc-editor.org/rfc/rfc5869">
          <front>
            <title>HMAC-based Extract-and-Expand Key Derivation Function (HKDF)</title>
            <author initials="H." surname="Krawczyk" fullname="H. Krawczyk"/>
            <author initials="P." surname="Eronen" fullname="P. Eronen"/>
            <date year="2010" month="May"/>
          </front>
          <seriesInfo name="RFC" value="5869"/>
        </reference>

        <reference anchor="RFC8032" target="https://www.rfc-editor.org/rfc/rfc8032">
          <front>
            <title>Edwards-Curve Digital Signature Algorithm (EdDSA)</title>
            <author initials="S." surname="Josefsson" fullname="S. Josefsson"/>
            <author initials="I." surname="Liusvaara" fullname="I. Liusvaara"/>
            <date year="2017" month="January"/>
          </front>
          <seriesInfo name="RFC" value="8032"/>
        </reference>

        <reference anchor="RFC8174" target="https://www.rfc-editor.org/rfc/rfc8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author initials="B." surname="Leiba" fullname="B. Leiba"/>
            <date year="2017" month="May"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
        </reference>

        <reference anchor="RFC8446" target="https://www.rfc-editor.org/rfc/rfc8446">
          <front>
            <title>The Transport Layer Security (TLS) Protocol Version 1.3</title>
            <author initials="E." surname="Rescorla" fullname="E. Rescorla"/>
            <date year="2018" month="August"/>
          </front>
          <seriesInfo name="RFC" value="8446"/>
        </reference>
      </references>

      <references>
        <name>Informative References</name>

        <reference anchor="RFC4301" target="https://www.rfc-editor.org/rfc/rfc4301">
          <front>
            <title>Security Architecture for the Internet Protocol</title>
            <author initials="S." surname="Kent" fullname="S. Kent"/>
            <author initials="K." surname="Seo" fullname="K. Seo"/>
            <date year="2005" month="December"/>
          </front>
          <seriesInfo name="RFC" value="4301"/>
        </reference>

        <reference anchor="RFC9000" target="https://www.rfc-editor.org/rfc/rfc9000">
          <front>
            <title>QUIC: A UDP-Based Multiplexed and Secure Transport</title>
            <author initials="J." surname="Iyengar" fullname="J. Iyengar"/>
            <author initials="M." surname="Thomson" fullname="M. Thomson"/>
            <date year="2021" month="May"/>
          </front>
          <seriesInfo name="RFC" value="9000"/>
        </reference>

        <reference anchor="RFC9162" target="https://www.rfc-editor.org/rfc/rfc9162">
          <front>
            <title>Certificate Transparency Version 2.0</title>
            <author initials="B." surname="Laurie" fullname="B. Laurie"/>
            <date year="2021" month="December"/>
          </front>
          <seriesInfo name="RFC" value="9162"/>
        </reference>

        <reference anchor="RFC8996" target="https://www.rfc-editor.org/rfc/rfc8996">
          <front>
            <title>Deprecating TLS 1.0 and TLS 1.1</title>
            <author initials="K." surname="Moriarty" fullname="K. Moriarty"/>
            <author initials="S." surname="Farrell" fullname="S. Farrell"/>
            <date year="2021" month="March"/>
          </front>
          <seriesInfo name="RFC" value="8996"/>
        </reference>

        <reference anchor="NIST-ZT" target="https://doi.org/10.6028/NIST.SP.800-207">
          <front>
            <title>Zero Trust Architecture</title>
            <author initials="S." surname="Rose" fullname="S. Rose"/>
            <author initials="O." surname="Borchert" fullname="O. Borchert"/>
            <author initials="S." surname="Mitchell" fullname="S. Mitchell"/>
            <author initials="S." surname="Connelly" fullname="S. Connelly"/>
            <date year="2020" month="August"/>
          </front>
          <seriesInfo name="NIST SP" value="800-207"/>
        </reference>

        <reference anchor="IMPL" target="https://github.com/sripad2020/Zeropath-vpn">
          <front>
            <title>ZeroPath VPN Reference Implementation</title>
            <author initials="S. R." surname="Hebbar" fullname="Sripad Rama Hebbar"/>
            <date year="2026"/>
          </front>
        </reference>

        <reference anchor="PYPI" target="https://pypi.org/project/zeropath-vpn/1.0.0/">
          <front>
            <title>zeropath-vpn PyPI Package (v1.0.0)</title>
            <author initials="S. R." surname="Hebbar" fullname="Sripad Rama Hebbar"/>
            <date year="2026"/>
          </front>
        </reference>
      </references>
    </references>

    <section anchor="acknowledgements" numbered="false" toc="default">
      <name>Acknowledgements</name>
      <t>
        The author thanks the open-source Python community and the IETF
        community for providing the standards and tools on which this
        work is built.
      </t>
    </section>

  </back>
</rfc>
