/** * The §13.6/§13.10 validity-window currency rules for a timed signed artifact, in ONE place — * handle links and session grants both call this (SPEC 1778: session expiry follows the handle * rules), so a rule added or tightened later lands in every verifier by construction instead of * hand-copied blocks drifting apart: * * 1. `exp > iat` (an empty/backward window never verifies) * 2. `nbf ≤ exp` (a window that opens after it closes never verifies) * 3. the validity SPAN is measured from `min(iat, nbf)` and must fit the ceiling (an early * `nbf` or forward-dated `iat` cannot manufacture a longer window) * 4. no FUTURE `iat` (a forward-dated artifact never verifies, §13.10) * 5. `nbf ≤ now ≤ exp` (the window itself) * 6. `exp ≤ now + ceiling` (clock-anchored: a dated-in-the-future artifact cannot outlive * its ceiling even when its own span is in-bounds) * * `refusals` picks the refusal-code policy by WHERE the caller runs the check: "opaque" for a * verifier that checks currency BEFORE the signature (handle links — every refusal is * `permission-denied`, so a forged artifact learns nothing from the code), "post-signature" * for one that checks after identity is established (session grants — structural violations * are `contract-invalid`, an early presentation `failed-precondition`, a stale one `expired`). */ export declare function assertArtifactCurrency(t: { iat: number; nbf?: number; exp: number; }, a: { now: number; ceilingMs: number; what: string; ceilingName: string; refusals: "opaque" | "post-signature"; }): void; /** The §13.10 anchor roles: which artifact family a registered key may sign. */ export declare const ANCHOR_ROLES: readonly ["handles", "traits", "receipts", "resume", "sessions", "authz-slots", "obligations", "payments"]; export type AnchorRole = (typeof ANCHOR_ROLES)[number]; /** One resolved `signer.` anchor (§13.10), as the registry projection a verifier * consumes: the record's spec fields plus the status-side revocation. `scope` is the * per-role structured ceiling; a role listed in `roles` whose scope dimension is ABSENT is * CLOSED, not open (§13.10: "a key without a dimension ceiling has that dimension closed"). * For the `traits` role the entries are reverse-DNS DOMAIN prefixes the key may define and * attest traits under (third-party authorities register under their domain claim; the * space-operator key carries `ai.cotal`). */ export interface SignerAnchor { keyId: string; /** nkeys-encoded Ed25519 public key the artifact signature verifies against. */ publicKey: string; /** The principal or reverse-DNS domain the key belongs to. */ owner: string; /** The LIFECYCLE UID of the owning principal (§13.1: a principal is `(id, lifecycleUid)`, * so the record identifies its key's principal fully). Absent for a domain-owned key. * REQUIRED wherever a verifier must bind the key to a specific lifecycle (a child handle's * issuer, §13.6) — there, an absent binding FAILS CLOSED: owner text alone would let a * recycled alias re-register a key and issue off its predecessor's artifacts. */ ownerLifecycleUid?: string; roles: readonly AnchorRole[]; scope?: Partial>; /** Validity window, ms epoch, both inclusive. Rotation registers a successor and closes * this window; overlap is permitted for handoff. */ validFrom: number; validTo: number; /** Status-side revocation: immediate for NEW verifications (effected work is not * retroactively unwound). */ revoked?: boolean; } /** The fresh-resolution seam (§13.10: "a verifier resolves the artifact's keyId FRESH at * verification"): production reads the space's `signer.` record; a test supplies a * faithful map. `undefined` = unknown key (fail closed). Trust roots never merge across * spaces — the resolver IS the space binding. */ export type AnchorResolver = (keyId: string) => Promise | SignerAnchor | undefined; /** The D28 signature INPUT: UTF-8 bytes of the artifact's RFC 8785 canonical JSON with `sig` * absent. The strict canonical path throws on non-interchangeable values (lone surrogates, * undefined, non-finite numbers) — an artifact that cannot canonicalize cannot sign. */ export declare function signatureInput(artifact: Record): Uint8Array; /** Sign an artifact (D28): returns the artifact WITH its base64url unpadded `sig`. The * key pair is any nkeys KeyPair (the seed side); the matching public key is what the * anchor registry carries. */ export declare function signArtifact>(artifact: T, keyPair: { sign(input: Uint8Array): Uint8Array; }): T & { sig: string; }; /** Verify an artifact's D28 signature against a RESOLVED anchor's public key. Fails closed * (`permission-denied`): malformed/absent `sig`, a public key nkeys cannot parse, or a * signature that does not verify over the recomputed canonical form. Shape/binding checks * belong to the artifact's own verifier — this is exactly the signature step. */ export declare function verifyArtifactSignature(artifact: Record, anchor: SignerAnchor): void; /** * Resolve an anchor FRESH for one use and enforce the §13.10 gate (fail closed): unknown key, * revocation (immediate for new verifications), role mismatch, and window are all refusals. * `at` is the artifact's own signing time where it carries one (an attachment's `ts`), or the * verification time for timeless artifacts (a content-addressed definition): the WINDOW binds * the signing act; revocation binds the verification. Scope is enforced separately by the * artifact's verifier ({@link assertAnchorScopeCovers}) against its own dimension. */ export declare function resolveAnchorForUse(resolve: AnchorResolver, use: { keyId: string; role: AnchorRole; at: number; }): Promise; /** Enforce a role's scope ceiling on one subject under dot-prefix containment: an entry * covers `subject` iff it equals it or is a strict dot-prefix (`ai.cotal` covers * `ai.cotal.guarded`). An ABSENT scope dimension for the role is CLOSED, not open * (§13.10) — a key with the role but no ceiling entries authorizes nothing. */ export declare function assertAnchorScopeCovers(anchor: SignerAnchor, role: AnchorRole, subject: string, what: string): void; //# sourceMappingURL=endpoint-signing.d.ts.map