Skip to content

Repository files navigation

Ota Authority Protocol

Canonical, provider-neutral wire protocol for Ota crossing authority.

This crate publishes the versioned message model, framing rules, semantic identity helpers, and conformance vectors used by Ota Core, trusted launchers, and independently operated authority brokers. Cross-repository conformance becomes established only when those consumers pin and test the same immutable crate revision.

Boundary

This repository owns:

  • protocol version and message-kind constants;
  • exact serialized request, attestation, decision, lease, and consumption types;
  • additive runtime-boundary attestation v2 types and canonical protected-launcher profiles;
  • immutable principal-mapping, Ota process-posture, and systemd launcher-profile records used by the production protected-launcher adapter;
  • immutable systemd Launcher V3 and V4 profiles, where V4 retains the V3 procfs restriction and adds exact named listener and manager-opened read-only boot-ID descriptor roles;
  • an additive protected-launcher capability record binding one exact request, launcher installation, root service, systemd/cgroup invocation, unprivileged Ota subject, and the closed retained-descriptor set without carrying paths, file content, tokens, or provider responses;
  • closed administrator-authority, protected Launcher/Ota implementation-subject, and authority- context records, including a 256-bit administrator-generated authority-instance identifier, plus domain-separated invocation-nonce and non-nil canonical Linux boot identities for a future installer-owned capability context;
  • closed challenge, public capability-observation projection, and administrator-installed verifier records that bind one fresh workflow invocation without publishing the raw protected-capability identity or its transitive private correlation inputs;
  • a closed protected Launcher-to-Attestor signing envelope that binds the exact private capability, public payload, producer binding, verifier, and projection identity while returning only the signed public projection, with cross-record reconciliation against the retained request;
  • a closed same-execution secret-delivery transaction-binding exchange. Core sends the exact Launcher request identity retained in its startup continuation, not caller-reconstructed request content. Protocol reconciles that request to the retained continuation before protected derivation, signing, or replay mutation. Launcher then privately reconciles capability evidence before returning the private binding and signed public projection; Core separately reconciles that response against its retained request and independently loaded verifier and installation identities before signature policy;
  • a closed private protected-authority snapshot challenge, request, payload, and response, plus an additive snapshot-bound V2 transaction-binding exchange. The snapshot binds exact selected-child request/startup/session, protected store descriptor metadata and bytes, and the current signed verifier/bundle state; Core treats transferred bytes as untrusted semantic input and must independently reconstruct its selected Step 1-6 truth. V1 remains immutable. Protocol neither opens stores nor verifies their live provenance, reserves replay state, parses provider bindings, contacts a provider, or activates delivery or execution;
  • an additive snapshot-bound V3 transaction-binding exchange that preserves V2 unchanged and binds one exact transport-dependency-record identity into both the request and private binding. Protocol validates only that closed identity relationship. Core retains ownership of the complete expected dependency graph and record, Cargo resolution, semantic comparison, and candidate derivation; the V3 exchange grants no installation authority and opens no transport or provider path;
  • additive V2 protected-authority snapshot records that retain descriptor-bound verifier and binding stores only as canonical raw bytes, avoiding V1's duplicate parsed carriers while retaining the fixed one-frame bound. Protocol structurally decodes and reconciles those records only; it does not verify the bundle signature, load stores, compare administrator dependency expectations, or authorize a V4 transaction, network request, provider operation, delivery, or execution;
  • additive V4 transaction-binding records that require the exact V2 snapshot identity, schema, and kind across request, private binding, and response, while retaining V3's same-child and transport-dependency reconciliation. These are structural records; Launcher and Core still own their respective authority, signature, candidate, and one-use runtime checks;
  • closed protected secret-delivery verifier-store and binding-bundle records. The store admits exactly one verifier and pins exactly one current signed bundle generation; the bundle binds an opaque, bounded payload identity and domain-separated Ed25519 signature envelope without making provider bindings, paths, or secret material public;
  • the bounded Linux systemd-launcher client/service request, output, and terminal frames;
  • bounded four-byte big-endian framing;
  • JCS plus SHA-256 message identities; and
  • compatibility and adversarial conformance tests.

It defines canonical projection and binding-bundle signature bytes but does not own repository contracts, semantic-scope derivation, admission policy, signing keys, challenge replay persistence, signature verification policy, protected-store loading, approval workflows, broker persistence, transport credentials, execution, receipt creation, protected archive storage, or semantic archive verification. Those remain with Ota Core, the authority launcher, and the chosen broker implementation. A structurally valid public projection is neither authority nor evidence of provider contact, delivery, execution approval, or cleanup. The authority-context records are canonical structural truth only: Protocol does not install them, establish filesystem ownership, observe procfs, generate runtime nonces, or reconcile installed executables. A structurally valid binding bundle is likewise not provider authority and does not establish cryptographic verification, current protected-store bytes, replay state, provider contact, delivery, execution approval, receipt, or assurance.

Wire sequence

sequenceDiagram
    autonumber
    participant Core as Ota Core
    participant Launcher as Trusted launcher
    participant Attestor as Protected attestation producer
    participant Broker as Authority broker

    Core->>Core: Freeze contract, semantic scope, work unit, and nonce commitment
    Core->>Launcher: challenge_request
    Launcher->>Attestor: Submit challenge-bound observed claims
    Attestor-->>Launcher: attestation_response (signed)
    Launcher-->>Core: Relay signed attestation
    Core->>Core: Verify challenge, scope, work unit, origin, and freshness

    Core->>Launcher: authorization_request
    Launcher->>Broker: Relay exact-scope request
    Broker-->>Launcher: authorization_decision (signed)
    Launcher-->>Core: Relay signed decision
    Core-->>Launcher: authorization_decision_admission (identity-bound acknowledgement)

    alt Authorization is allowed
        Broker-->>Launcher: lease_issuance (signed)
        Launcher-->>Core: Relay signed one-use lease
        Core->>Core: Create pending crossing transaction
        Core->>Launcher: lease_consume
        Launcher->>Broker: Atomically validate and consume lease
        Broker-->>Launcher: lease_consume_response (signed)
        Launcher-->>Core: Relay transaction-bound consumption result
        alt Lease is verified as consumed
            Core->>Core: Execute only the exact authorized work unit
            Core->>Core: Finalize crossing transaction and receipt
            Core->>Launcher: execution_completion
            Launcher->>Launcher: Persist exact completion before child exit
            Launcher-->>Core: execution_completion_persistence
            Core-->>Launcher: Exit after receipt/archive work
            Launcher->>Launcher: Reap child and remove exact scope/cgroup/active slot
            Launcher-->>Core: Terminal finalization is emitted to the outer client
        else Consumption is refused or ambiguous
            Core->>Core: Refuse before governed execution
        end
    else Authorization is denied, stale, or ambiguous
        Core->>Core: Refuse before governed execution
    end

    opt Consume acknowledgement is uncertain
        Core->>Launcher: Fresh challenge_request
        Launcher-->>Core: Fresh attestation_response (signed)
        Core->>Launcher: lease_consumption_query
        Launcher->>Broker: Query exact prior consume request
        Broker-->>Launcher: lease_consumption_status (signed)
        Launcher-->>Core: Relay status and original signed consume response when consumed
        Core->>Core: Finalize old work unit as incomplete and never resume its execution
    end
Loading

The seven authority-exchange messages, in order, are challenge_request, attestation_response, authorization_request, authorization_decision, lease_issuance, lease_consume, and lease_consume_response. The protected local launcher session additionally carries authorization_decision_admission: a Core-authored acknowledgement that binds the exact verified signed decision before the launcher journals relay evidence. It is integrity evidence, not a second authority decision and not a lease. Recovery adds lease_consumption_query and lease_consumption_status. Ota may execute the governed work unit only after it verifies a signed lease_consume_response bound to the pending crossing transaction. Recovery never resumes that old work unit: it reconciles the broker result, finalizes the abandoned local transaction as incomplete, and requires a new authorization for any later execution.

Protected history sequence

sequenceDiagram
    autonumber
    participant Operator as Installed non-root client
    participant History as Protected history service
    participant Store as Launcher-owned catalog
    participant Core as Ota Core verifier

    Operator->>History: Nonce-bound query with optional archive identity
    History->>History: Verify pidfd, executable, process posture, and repository mapping
    History->>Store: Freeze ordered catalog snapshot
    Store-->>History: Archive, immutable contract snapshot, and signed sidecar
    History-->>Operator: Manifest with operator, repository, and catalog identities
    loop Each selected catalog entry
        History-->>Operator: Entry and three ordered content-addressed objects
        History-->>Operator: Bounded identity-checked chunks
    end
    History->>History: Reverify the complete operator session
    History-->>Operator: Completed manifest terminal
    Operator->>Core: Exact reconstructed objects and protected selection evidence
    Core->>Core: Re-derive contract, scope, authority, transaction, cleanup, and archive truth
Loading

The first protected-history profile is one complete bounded snapshot with no pagination. A pre-query refusal carries no invented query or manifest identity; a valid-query refusal carries no manifest identity; a successful terminal requires the exact query and manifest identities. Object identities derive from manifest, entry ordinal, catalog, kind, content identity, length, and chunk count before the entry binds the three object identities, avoiding a circular hash dependency. Repository and protected storage paths never cross this wire boundary.

For the protected systemd carrier, selected execution adds two private Core-to-launcher messages. launcher_execution_completion binds the terminal crossing transaction, receipt posture, exact work unit, and consumed-lease admission. The launcher durably journals that record before replying with launcher_execution_completion_persistence. After Core exits, the launcher reaps the exact child, removes the exact scope and cgroup, removes the active slot, and emits one LauncherExecutionFinalizationV1 inside the outer terminal frame. Completion is not cleanup evidence. A live finalization is valid only when all four removal checks are true and the launcher- observed child exit matches Core's completion. Schema v2 can instead record recovered_absent_completion_bound after a launcher restart: it binds verified child absence to Core's durable completion while explicitly carrying no observed exit code and no child-reaped claim. Selected execution additionally uses an identity-bound terminal persistence acknowledgement; the launcher must retain and replay the exact terminal until that acknowledgement is received.

Runtime-boundary attestation

The original LauncherAttestationPayload and v1 response domain remain immutable. They prove a fresh launcher session bound to the challenge, work unit, and semantic scope, but they do not prove strong runtime separation.

The additive LauncherAttestationPayloadV2 uses the distinct ota-crossing-broker/attestation-response/v2 response domain and ota.crossing-broker.attestation.v2\0 identity domain. It carries one signed runtime-boundary record with a stable profile ID, content-addressed profile identity, protected-launcher attestor identity, launcher-session binding, and an ordered closed set of observations.

This crate publishes two canonical profile definitions:

  • ota.runtime-boundary.protected-launcher/v1 requires eleven launcher and runtime-separation observations.
  • ota.runtime-boundary.protected-launcher-image/v1 adds bound runner-image and hardening-profile identities.

Every required observation must be represented with its profile-defined evidence method. The profile also requires bounded semantic identities for launcher binary/config measurements and, for the image profile, image/hardening-profile measurements; it forbids arbitrary identities on the remaining observations. Core, not this wire crate, owns trust-root selection, signature verification, refusal semantics, and archive reconciliation. Provider attestation is not part of these profiles.

The distinct LauncherAttestationPayloadV3 uses ota-crossing-broker/attestation-response/v3 only for systemd_protected_launcher/v1. It carries a complete, content-addressed SystemdProtectedLauncherInstanceEvidenceV2; its identity helper refuses a missing, substituted, incomplete, or non-verified instance. V3 does not reinterpret v1 or v2 archives.

V3 production signing uses two additional launcher-to-producer envelopes. The launcher derives LauncherAttestationClaimsV3 from the frozen challenge and complete observed instance, then binds those JCS-normalized claims under ota.authority-launcher.attestation-claims.v3\0 in one LauncherAttestationSigningRequestV1. The producer returns one LauncherAttestationSigningResponseV1 that binds the exact request, claims identity, and signed V3 attestation. Projecting the signed response back to launcher claims removes only producer-owned freshness and signature-wrapper fields. These protocol records neither authenticate the launcher peer nor own signing-key, clock, replay-state, or transport policy; the protected producer must enforce those runtime boundaries. The protected producer binding carries the public verification key and its identity, key interval, and both producer and verifier maximum-age bounds so launcher and producer independently derive the same narrowest validity window without exposing signing credentials.

Every JSON payload is carried in one frame: a four-byte unsigned big-endian payload length followed by at most 64 KiB of UTF-8 JSON. Signed-message and identity domains are fixed protocol constants; this crate canonicalizes bytes and publishes profile identities but does not select trust roots.

Production launcher records

The implemented systemd_protected_launcher/v1 adapter keeps broker semantics unchanged. This crate publishes only the immutable records that Core and the launcher must agree on before that adapter can execute:

  • LauncherPrincipalMappingV1 binds one protected job-peer identity to one distinct execution identity plus the fixed job-principal profile and launcher-session binding. Its identity is used as the existing broker runner_principal, so authorization covers the complete mapping rather than one caller label. The outer instance evidence separately binds the launcher profile.
  • OtaProcessPostureV1 is an adapter-local pre-authority record for measured no_new_privs, non-dumpable, and ptracer-clear posture. A launcher must corroborate it; the Ota-authored record is never sufficient authority by itself.
  • SystemdProtectedLauncherInstanceEvidenceV1 carries the immutable mapping, process posture, fixed profile identities, and bounded invocation identities. The additive SystemdProtectedLauncherInstanceEvidenceV2 binds that V1 record to the complete ordered launcher and job-principal observation sets. Its identity derivation rejects missing, reordered, failed, substituted, or unrecognized observations before an attestation can claim the closed profile.
  • ota.authority-launcher.systemd/v1 fixes the ordered service/socket hardening semantics and evidence sources for the legacy launcher-owned attestor credential posture. Its profile identity is sha256:32c49f19799e065d341c900a4ce0d7756669c0c0d4e990ffe81bbcda06291930.
  • ota.authority-launcher.systemd/v2 preserves those evidence sources while moving signing credentials exclusively into the separately protected producer service. The launcher binds only producer socket metadata and the public verifier set. Its profile identity is sha256:c816a49e01120bf1f793aedcfec094ca0f23a8ee80f1c7e5bed4c2d9c797cb42.
  • ota.authority-launcher.systemd/v3 preserves the separated producer boundary, adds bounded CAP_SYS_PTRACE for protected job and stopped-child inspection, and grants only ambient CAP_SETUID for the launcher's verified transition to the non-root target principal. That transition clears the ambient capability before selected code can execute. The profile also makes effective systemd runtime configuration read-only inside the launcher boundary and replaces /proc/net/unix path observation with protected socket metadata and descriptor identity. Its profile identity is sha256:1d0ef44c24b6ec21dc0c462edd52c5197ae35a4a1728a98cd93b92d6f106dfaf.
  • ota.authority-launcher.systemd/v4 preserves V3's procfs restrictions and adds exactly one manager-opened read-only boot-ID descriptor plus one canonical launcher-listener descriptor name. Its profile identity is sha256:bdac5f965aa56d44de8581e194ac0364b2d4c98183fff0cbb223574fd78197a8.
  • ota.authority-job-principal.systemd/v1 fixes the ordered job-peer, execution-principal, privilege, process-containment, and process-inspection requirements. Its profile identity is sha256:e69ef375070bbb4f5616ba46b6f29b9a987372909016d1a1dfa40a5d4daae93d.
  • ota.authority-job-principal.systemd/v2 permits only the protected primary GID when systemd represents that GID in the kernel supplementary-group vector. Every additional group remains a refusal, and V1 retains its original archive meaning. Its profile identity is sha256:ee6ea951aff4a80f8a4f93c576a93e3b29245b87d162726c2401c124a7a78659.

These definitions do not implement systemd, inspect a host, hold an attestor key, or create a provider claim. Core and authority-launcher must pin the same immutable protocol revision and independently verify their respective boundaries before the adapter can be enabled.

ProtectedLauncherCapabilityV1 is an additive protocol foundation for that independent verification. It canonicalizes exactly one launcher-session socket, verifier store, binding store, and invocation-cgroup descriptor; binds each store to a role-specific protected content identity; and derives the cgroup identity from the exact retained descriptor and systemd scope. It is not authority, does not prove that the descriptors were securely opened, and does not activate OIDC, provider contact, secret delivery, or execution. This protocol revision includes a semantic reconciliation API over independently observed launcher records and store bytes. No released or current authority-launcher emits the record, and no released or current Core/runtime consumes it. Those implementations and their hosted proof remain separate subsequent work.

Systemd launcher service frames

ota-authority-launcher/systemd/v1 adds the local client/service envelope for the Linux-only adapter. A client sends one launcher_invocation_request containing only an authority label, bounded Ota arguments, and an absolute logical repository path. It is an untrusted proposal, not authority: the root-owned service derives the Unix peer, chooses the configured mapping, and mints the invocation identity. After exact process-posture admission, an identity-bound launcher_startup_continuation binds the exact invocation, child, working directory, process posture, and principal mapping while unlocking CLI parsing only; it is not crossing authority. The service returns ordered binary-safe launcher_output frames followed by exactly one launcher_terminal frame. New V1 terminals may add a typed stage that distinguishes refusal before boundary creation, posture admission followed by exact boundary removal, authority refusal followed by exact boundary removal, pre-authorization protocol refusal followed by exact boundary removal, V3 attestation admission before authorization followed by exact boundary removal, selected execution completion/failure/interruption followed by exact boundary removal, and boundary failure. Selected-execution terminals require an identity-bound finalization record; refusal terminals cannot carry one. The field is additive so legacy V1 terminals remain readable; consumers must require the specific stage needed for any stronger proof claim rather than inferring it from an exit code.

The protocol also publishes content-addressed identities for that exact request, the retained working-directory device/inode, the stopped fixed-binary child, and its exact non-delegated transient systemd scope. Those identities let the launcher durably reconcile preparation and cleanup without treating a PID, path string, or caller request as authority. They do not represent systemd-scope admission, execution, or broker authorization.

The envelope carries no broker credential, caller identity assertion, semantic scope, or grant. Core and the launcher establish those values through the protected session and signed broker protocol after the service has admitted the request.

Consume and verify

Ota Core and Authority Launcher must use the same reviewed immutable revision. The Ota v1.6.26 carrier pins protocol implementation commit 04a199a1eddd72b5b61958e0fe7f2d4e662e05cf:

ota-authority-protocol = { git = "https://github.com/ota-run/authority-protocol.git", rev = "04a199a1eddd72b5b61958e0fe7f2d4e662e05cf" }

Changing that pin is a protocol compatibility change and requires both consumers to be repinned and revalidated together. Verify this crate with Rust 1.95.0:

cargo fmt --check
cargo check --locked --all-targets
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked --all-targets

Status

The protocol used by the bounded Linux/systemd carrier is implemented and conformance-tested across Ota Core and Ota Authority Launcher. This crate is currently source-distributed rather than published as a stable crate release. Consumers must pin the exact immutable revision used by both peers; branch references do not establish protocol compatibility.

The public operator model and deployment boundaries are documented in the Broker Crossing Authority reference. Provider attestation, hosted approval operation, and non-Linux carriers remain outside this protocol release posture.

License

Apache License 2.0. See LICENSE.

About

Canonical wire protocol, signed message model, and conformance vectors for Ota crossing authority

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages