Transparency (DOCS-ATTEST-74-002)
Last updated: 2026-07-17
Purpose
StellaOps uses transparency logs (Sigstore Rekor v2 or equivalent) to provide tamper-evident, timestamped anchoring for DSSE bundles.
This document freezes the offline verification inputs used by Attestor in sealed/air-gapped operation and points to the canonical schema for rekor-receipt.json.
Local Transparency Primary (Air-Gap Default)
Attestor now treats a Stella-owned local transparency log as the default primary anchor:
- Primary log URL:
stellaops://attestor/local-transparency. - Leaf-ledger persistence:
attestor.local_transparency_entries, created by Attestor startup migrations. It stores the canonical entry JSON, digests, deterministic UUID/index, and RFC 6962 leaf hash. - Submission-proof persistence: canonical
attestor.entriesrows store the proof/checkpoint descriptor in theirproofJSONB column. Deduplicated submission/handoff retries reuse this durable descriptor. - Origin:
stellaops.local-transparency.v1unless overridden byattestor:transparency:local:origin. - Runtime proof shape:
LocalTransparencyRekorClientderives the current Merkle root and orientedL:/R:audit path from the ordered leaf ledger; the returned proof/checkpoint is persisted with the canonical Attestor entry, not as columns onattestor.local_transparency_entries.
The local log is intentionally self-contained. It does not require public Sigstore, GCP, Tessera, or any internet service to sign, anchor, verify, or replay Stella Ops evidence inside an air-gapped deployment.
Submission remains behind the Attestor attestor:* authorization policies. Those policies accept either a real Stella Ops bearer token with the matching scope or a request from a configured service-to-service bypass network. Local compose uses the bypass path for trusted in-network services such as Findings Ledger; public callers still receive the normal authorization challenge.
Existing rekorLogIndex and rekorEntryId fields remain as compatibility fields for Console/API callers. When the primary log URL is stellaops://attestor/local-transparency, those fields identify the local transparency entry rather than a public Rekor entry.
External Rekor or equivalent log publication is an optional sync concern. In sealed mode operators keep the local log authoritative; when internet access is available, Attestor can mirror local entries to an operator-approved external log and record the external receipt alongside the local receipt. That sync path must be non-GCP-bound by default and must not weaken local verification if the external endpoint is unavailable.
External Mirror Postures
External transparency mirroring is additive. It never replaces the Stella local receipt and it never makes public Rekor, private Rekor, Tessera, GCP, or any internet endpoint a prerequisite for local signing, anchoring, replay, or verification.
Attestor supports three operator postures:
| Posture | Network shape | Operator files | Result |
|---|---|---|---|
| Sealed mode | No external network path. | None. | Local receipts are authoritative; mirror status remains local_only. |
| Connected-window sync | Operator opens a bounded network path from Attestor to an approved external log. | Optional run report. | Attestor mirrors selected local entries and stores per-target mirror receipts. |
| Manual exchange | Sealed site never opens direct egress. A connected relay handles external publication. | Schedule file out, import file back. | Sealed site validates and imports mirror receipts after removable-media transfer. |
Operator-facing terms:
- Local receipt: the UUID/index from
attestor.local_transparency_entriesplus the proof/checkpoint descriptor on the corresponding canonicalattestor.entriesrow. ExistingrekorEntryIdandrekorLogIndexcompatibility fields continue to refer to this receipt when the primary URL isstellaops://attestor/local-transparency. - Mirror receipt: an external Rekor-compatible receipt attached to one local receipt for one configured target. It is exposed as additive metadata and must not be stuffed into the local compatibility fields.
- Sync batch: a bounded connected-window run over selected local entries and targets.
- Schedule file: the sealed site’s signed request for a relay to mirror selected local entries. This uses the same air-gap operator pattern as vulnerability database refreshes.
- Import file: the connected relay’s signed return file containing external mirror receipts for a prior schedule file.
Mirror status is tracked per target. local_only, mirror_pending, mirror_failed, and mirrored are reporting states only; they do not alter the validity of the local receipt.
External Mirror Persistence
External mirror state is stored separately from the local transparency log:
attestor.external_transparency_targetsstores operator-approved mirror destinations, trust-root references, auth references, enabled state, and policy metadata.attestor.external_transparency_mirror_receiptsstores one receipt state per local UUID and target. It carries the local UUID/index/digest binding, external UUID/index/proof/checkpoint material, retry status, last error, and installation-certificate/regional-crypto profile evidence fields.attestor.transparency_exchange_batchesrecords connected sync runs and manual schedule/import-file audit state, including manifest digest, selected local index range, operator label, certificate/profile binding, signature digest, and import timestamp.
ITransparencyMirrorRepository owns this persistence boundary. It may read attestor.local_transparency_entries to enumerate pending local entries, but it must not mutate local receipt rows. A restored sealed deployment can therefore verify local receipts even when external mirror state is absent, failed, or waiting for a future import file.
IExternalTransparencyMirrorClient owns target submission and receipt validation. The Rekor-compatible adapter reconstructs the DSSE submission from the local entry descriptor, submits it to the configured target, and verifies the returned inclusion proof against the local bundle SHA-256 before producing a mirrored receipt record. Digest mismatches, missing proof/checkpoint material, authentication failures, disabled targets, and unavailable endpoints return mirror_failed retry metadata without attaching external UUID/proof fields.
Operator Control APIs
Operators manage external mirror targets through Attestor instead of editing PostgreSQL rows directly:
GET /api/v1/transparency/targets(attestor:read) returns tenant-scoped targets withunconfigured, enabled state, endpoint URL, trust-root reference,authRefConfigured, required crypto profile, operator label, and per-target counts formirrored,mirror_pending, andmirror_failedreceipts. It also reports last local index, last mirrored local index, last connected sync/import timestamps, and the last retry error.GET /api/v1/transparency/targets/{targetId}(attestor:read) returns the same shape for one target.POST /api/v1/transparency/targets(attestor:write) creates or updates an operator-approved target. The body requiresname,requiredCryptoProfileId, andoperatorLabel; acceptskind(rekor-compatible,rekor, orsigstore-rekor),endpointUrl,trustRootRef,authRef,enabled, and a JSON-objectmetadataJson; and stores only secret references, never raw credential material.POST /api/v1/transparency/targets/{targetId}:enableandPOST /api/v1/transparency/targets/{targetId}:disable(attestor:write) flip the target state while preserving endpoint, trust, secret-reference, and metadata fields.
requiredCryptoProfileId records the regional crypto expectation for schedules, imports, and connected-run reporting. The actual installation certificate and private-key operations still come from Authority/Platform trust state and the configured crypto provider; Attestor does not mint or store those keys.
Connected-Window Sync
Connected-window sync is for environments where operators can temporarily open a controlled egress path to an approved external transparency service.
Required controls:
- Sync is disabled by default and enabled only for named targets.
- Operators bound every run by target, local index/UUID selection, maximum entry count, maximum runtime, and dry-run/stop-on-error flags.
- The external target must be Rekor-compatible or implement an approved Stella mirror adapter. The default product configuration must not assume public Sigstore, GCP, or Tessera.
- External receipt validation binds the returned UUID/index/proof/checkpoint to the local bundle digest before Attestor stores a mirror receipt.
- Failed external sync leaves the local receipt untouched and creates retryable mirror status/error records.
Runtime contract:
- Manual trigger:
POST /api/v1/transparency/external-sync:runwithattestor.write. The body acceptstargetIds,targetNames,maxEntries,maxRuntimeSeconds,dryRun,stopOnFirstHardError, andoperatorLabel. Tenant selection comes from the authenticated Stella tenant context, not from the request body. - Runner:
ITransparencySyncRunnerscans enabledexternal_transparency_targets, asksITransparencyMirrorRepository.ListPendingLocalEntriesAsync(...)for local entries not alreadymirroredfor each target, submits throughIExternalTransparencyMirrorClient, and stores the returned receipt with idempotent upsert semantics. - Resume behavior: a second run skips local UUID/target pairs already stored as
mirrored; failed or retryable receipts remain eligible for later retry. - Audit: each target run records a
connected_syncrow inattestor.transparency_exchange_batcheswith the selected local index range, counts, operator label, deterministic metadata JSON, and manifest digest. - Hosted worker:
TransparencySyncWorkeris disabled unless bothattestor:transparency:externalSync:enabled=trueandattestor:transparency:externalSync:workerEnabled=true. The manual trigger works when the worker is disabled, as long as external sync itself is enabled. - Report readback:
GET /api/v1/transparency/external-sync/reportsandGET /api/v1/transparency/external-sync/reports/{batchId}expose durableconnected_syncbatch metadata for CLI/UI readback. Reports include target id, entry count, selected local index range, manifest digest, file name, operator label, status, installation certificate id/thumbprint, algorithm id, crypto profile id, compliance profile hash, signature digest, metadata JSON, creation/update time, and import time. Package bytes and credentials are not returned.
Compose sealed defaults:
ATTESTOR_ATTESTOR__TRANSPARENCY__EXTERNALSYNC__ENABLED: "${ATTESTOR_EXTERNAL_TRANSPARENCY_SYNC_ENABLED:-false}"
ATTESTOR_ATTESTOR__TRANSPARENCY__EXTERNALSYNC__WORKERENABLED: "${ATTESTOR_EXTERNAL_TRANSPARENCY_WORKER_ENABLED:-false}"
ATTESTOR_ATTESTOR__TRANSPARENCY__EXTERNALSYNC__TENANTID: "${ATTESTOR_EXTERNAL_TRANSPARENCY_TENANT_ID:-default}"
ATTESTOR_ATTESTOR__TRANSPARENCY__EXTERNALSYNC__DEFAULTMAXENTRIES: "${ATTESTOR_EXTERNAL_TRANSPARENCY_MAX_ENTRIES:-100}"
ATTESTOR_ATTESTOR__TRANSPARENCY__EXTERNALSYNC__MAXENTRIESHARDLIMIT: "${ATTESTOR_EXTERNAL_TRANSPARENCY_MAX_ENTRIES_HARD_LIMIT:-1000}"
ATTESTOR_ATTESTOR__TRANSPARENCY__EXTERNALSYNC__MAXRUNTIMESECONDS: "${ATTESTOR_EXTERNAL_TRANSPARENCY_MAX_RUNTIME_SECONDS:-300}"
ATTESTOR_ATTESTOR__TRANSPARENCY__EXTERNALSYNC__INTERVALSECONDS: "${ATTESTOR_EXTERNAL_TRANSPARENCY_INTERVAL_SECONDS:-3600}"
ATTESTOR_ATTESTOR__TRANSPARENCY__EXTERNALSYNC__STOPONFIRSTHARDERROR: "${ATTESTOR_EXTERNAL_TRANSPARENCY_STOP_ON_HARD_ERROR:-true}"
No compose default points at public Rekor, GCP, Tessera, or any internet service. Operators configure targets in Attestor persistence and may point them at a local Rekor-compatible relay, a regional transparency service, or another approved mirror adapter.
Manual Schedule/Import Exchange
Manual exchange is for sealed deployments that use removable media or a controlled transfer station instead of a live sync window. It must follow the same validate/import discipline used by vulnerability database air-gap refreshes:
- The sealed site creates a deterministic schedule file for selected local transparency entries.
- The schedule file is signed with the installation certificate identity preserved by Authority/Platform trust administration. The private key never appears in the file.
- The connected relay validates the schedule file, submits entries to the approved external target, and creates a deterministic import file.
- The sealed site validates the import file before applying it. Unknown local UUIDs, digest mismatches, tampered manifests, untrusted certificates, expired or revoked certificates, and regional-crypto profile mismatches fail closed.
Schedule and import files carry public certificate metadata only:
- installation certificate id;
- issuer id;
- certificate SHA-256 thumbprint;
- public chain or trust-reference id;
- key id;
- algorithm id;
- active crypto profile id and compliance-profile hash;
- validity and revocation metadata;
- signature bytes over the canonical manifest.
The signing algorithm must match the installation’s active regional crypto profile (world, fips, eidas, gost, sm, kcmvp, or a future approved profile). Attestor must resolve that binding through the Authority/Platform trust state and the crypto-provider registry; it must not mint its own exchange certificate or silently fall back to another algorithm.
Runtime contract:
ITransparencyExchangeFileServicecreates deterministic schedule packages, validates schedule packages at the relay, creates deterministic import packages, validates returned import packages, and applies mirror receipts only to matching local UUID/index/bundle-digest rows.ITransparencyMirrorRepository.ListLocalEntriesAsyncselects local entries by UUID list, local index range, timestamp range, and artifact kind for schedule creation and sealed-site import validation.IInstallationCertificateResolveris the Authority/Platform trust-state boundary for transparency exchange certificates. Attestor receives certificate identity metadata and validation results; it does not create independent exchange certificates.ITransparencyExchangeSigneris the regional crypto signing boundary for schedule and import manifests. Algorithm/profile mismatches fail closed.- Web APIs are
POST /api/v1/transparency/exchange/schedules,POST /api/v1/transparency/exchange/relay-imports,POST /api/v1/transparency/exchange/imports:validate, andPOST /api/v1/transparency/exchange/imports:apply. All requireattestor:writeand JSON request bodies. - Status APIs are
GET /api/v1/transparency/exchange/batchesandGET /api/v1/transparency/exchange/batches/{batchId}withattestor:read. They expose schedule, relay-import, sealed-import, and connected-sync batch metadata without returning package bytes.direction,targetId,manifestDigest,operatorLabel, andlimitquery parameters support CLI and UI filtering. - Default infrastructure registration is deliberately fail-closed:
UnsupportedInstallationCertificateResolverandUnsupportedTransparencyExchangeSignerreturninstallation_certificate_resolver_unavailableortransparency_exchange_signer_unavailableuntil the host composition provides the Authority/Platform-backed resolver and signer.
Verification and query APIs expose mirror state additively:
GET /api/v1/attestationsandGET /api/v1/attestations/{uuid}includelocalTransparencyReceiptfor the Stella local log receipt.- The same responses include
externalMirrorReceipts[]for zero or more connected-window or manual-import external mirror receipts. - The legacy
mirrorfield remains a compatibility field for pre-existing single-replica submissions. New external sync/import receipts are not folded intomirror. - Existing
rekorEntryId,rekorLogIndex,uuid, andindexcompatibility fields continue to identify the local primary receipt unless an older caller explicitly used a direct Rekor backend as the primary transparency target. External mirror identifiers are only inexternalMirrorReceipts[]. - Console copy and client behavior are defined in
docs/modules/attestor/transparency-ui-api-handoff.md.
Offline Inputs (Air-Gap / Sealed Mode)
Baseline directory layout is defined in docs/product/advisories/14-Dec-2025 - Offline and Air-Gap Technical Reference.md:
/evidence/
keys/
tlog-root/ # pinned transparency log public key(s)
tlog/
checkpoint.sig # signed tree head / checkpoint (note format)
rekor-tile-snapshot.json # optional full local tile snapshot for root consistency
rekor-sparse-proof.json # optional bounded sparse proof for large logs
entries/ # *.jsonl entry pack (leaves + proofs)
Rekor Receipt (rekor-receipt.json)
The offline kit (or any offline DSSE evidence pack) may include a Rekor receipt alongside a DSSE statement.
- Schema:
docs/modules/attestor/schemas/rekor-receipt.schema.json - Source:
docs/product/advisories/14-Dec-2025 - Rekor Integration Technical Reference.md(Section 13.1) anddocs/product/advisories/14-Dec-2025 - Offline and Air-Gap Technical Reference.md(Section 1.4)
Fields:
uuid: Rekor entry UUID.logIndex: Rekor log index (integer, >= 0).rootHash: expected Merkle tree root hash (lowercase hex, 32 bytes).hashes: Merkle inclusion path hashes (lowercase hex, 32 bytes each; ordered as provided by Rekor).checkpoint: either the signed checkpoint note text (UTF-8) or a relative path (e.g.,checkpoint.sig,tlog/checkpoint.sig) resolved relative to the receipt file.
Checkpoint (checkpoint.sig)
/evidence/tlog/checkpoint.sig is the pinned signed tree head used for offline verification.
Contract:
- Content is UTF-8 text using LF line endings.
- The checkpoint MUST parse to the checkpoint body shape used by
CheckpointSignatureVerifier(origin, tree size, base64 root hash, optional timestamp). - In offline verification, the checkpoint from receipts SHOULD match the pinned checkpoint (tree size + root hash).
Entry Pack (entries/*.jsonl)
/evidence/tlog/entries/*.jsonl is an optional-but-recommended offline mirror snapshot for bulk audit/replay.
Contract:
- Files are NDJSON (one JSON object per line).
- Each line uses the “Rekor Entry Structure” defined in
docs/product/advisories/14-Dec-2025 - Rekor Integration Technical Reference.md(Section 4). - Deterministic ordering:
- File names sort lexicographically (Ordinal).
- Within each file, lines sort by
rekor.logIndexascending.
Tile Snapshot (rekor-tile-snapshot.json)
Attestor Core can verify a strict local tile/root consistency snapshot when an offline kit includes full tile hash material.
- Schema:
docs/modules/attestor/schemas/rekor-tile-snapshot.schema.json - Verifier:
RekorTileRootConsistencyVerifier - Schema version:
stellaops.rekor.tile-snapshot.v1
Required fields:
origin: checkpoint origin line. It must exactly match the signed checkpoint origin.treeSize: checkpoint tree size. It must exactly match the signed checkpoint tree size.rootHash: lowercase hex SHA-256 root hash. It must match the signed checkpoint root.tileWidth: tile width, 1…256.levels: contiguous full levels from level0leaves to the single root level. Every level contains contiguous tile indexes, exact widths, and lowercase 32-byte hex hashes.
Verification rules:
- Level
0hashes are RFC 6962 leaf hashes (SHA256(0x00 || entryDigest)), not UUIDs, log indexes, or raw checkpoint text. - Each upper level hash is recomputed from the prior level with RFC 6962 interior hashing (
SHA256(0x01 || left || right)); odd nodes are promoted the same way as the existing inclusion verifier. - The derived root must equal both
rootHashand the signed checkpoint root. - The hash at the receipt
logIndexmust equalSHA256(0x00 || SHA256(dsseEnvelopeBytes))for Scanner signed-SBOM/offline-kit use. - The inclusion path derived from the local snapshot must byte-match the receipt
hashespath.
The contract is intentionally fail-closed. Missing snapshot material, unsupported schemaVersion, non-contiguous levels/tiles, malformed hashes, root mismatch, checkpoint mismatch, leaf mismatch, or receipt-path mismatch returns an invalid tile consistency result. A Rekor UUID, log index, signed-note-shaped checkpoint, or receipt inclusion path alone does not produce tile/root consistency success.
Sparse Tile Proof (rekor-sparse-proof.json)
Attestor Core can verify a bounded sparse proof when an offline kit covers a large Rekor tree and cannot ship every local tile hash.
- Schema:
docs/modules/attestor/schemas/rekor-sparse-proof.schema.json - Verifier:
RekorSparseTileProofVerifier - Schema version:
stellaops.rekor.sparse-tile-proof.v1
Required fields:
origin: checkpoint origin line. It must exactly match the signed checkpoint origin.treeSize: checkpoint tree size. It must exactly match the signed checkpoint tree size.rootHash: lowercase hex SHA-256 root hash. It must match the signed checkpoint root.logIndex: receipt log index for the verified entry.leafHash: RFC 6962 leaf hash for the verified payload digest, encoded as lowercase 32-byte hex.proofNodes: ordered sparse audit-path nodes from the receipt leaf to the root. Each node haslevel,index, and lowercase 32-byte hexhash.
Verification rules:
- The verifier first verifies
rekor-receipt.jsonwith the local Rekor public key and signed checkpoint. Sparse material is never accepted as a substitute for checkpoint-bound inclusion. - The sparse proof
origin,treeSize,rootHash, andlogIndexmust match the verified checkpoint and receipt. leafHashmust equalSHA256(0x00 || SHA256(dsseEnvelopeBytes))for Scanner signed-SBOM/offline-kit use, or the equivalent Attestor payload digest leaf for other callers.proofNodesmust contain exactly the expected RFC 6962 audit-path coordinates forlogIndexandtreeSize, in leaf-to-root order. Missing, extra, duplicate-by-position, or reordered nodes fail closed.- Every sparse proof node hash must byte-match the corresponding receipt
hashesentry. - Recomputing the RFC 6962 root from
leafHashplusproofNodesmust equal both the sparserootHashand the signed checkpoint root.
The contract is intentionally bounded and fail-closed. It proves one receipt path against a signed checkpoint using locally supplied nodes; it does not claim that a complete tile mirror is present. Metadata-only sparse material, UUID/log-index-only material, checkpoint text without proof nodes, malformed hashes, coordinate mismatches, root mismatch, leaf mismatch, or receipt/proof divergence returns an invalid sparse proof result.
Offline Verification Rules (High Level)
- Load the pinned Rekor log public key from
/evidence/keys/tlog-root/(rotation is handled by shipping a new key file alongside the updated checkpoint snapshot). - Verify the checkpoint signature (when configured) and extract tree size + root hash.
- For each
rekor-receipt.json, verify:- inclusion proof path resolves to
rootHashfor the given leaf hash, - receipt checkpoint root matches the pinned checkpoint root (same tree head).
- inclusion proof path resolves to
- Optionally, validate that each receipt’s UUID/digest appears in the entry pack and that the recomputed Merkle root matches the pinned checkpoint.
- When
rekor-tile-snapshot.jsonis present and the caller requires tile/root consistency, validate the full local tile snapshot withRekorTileRootConsistencyVerifier. Do not downgrade missing or malformed tile material into success; report tile consistency as unavailable/invalid while preserving the existing signed-checkpoint inclusion result. - When
rekor-sparse-proof.jsonis present for a large tree, validate the bounded sparse proof withRekorSparseTileProofVerifier. Do not treat sparse metadata as proof unless the local nodes match the receipt path and signed checkpoint.
Configured Local Bundle Verification (2026-04-29)
Attestor Core exposes RekorLocalTransparencyBundleVerifier for services and offline tooling that need one configured local/offline proof-material path instead of separate receipt, checkpoint, key, tile, and sparse-proof arguments.
Input contract:
BundleRootDirectoryis required and must be a local directory.- Optional explicit paths (
ReceiptPath,CheckpointPath,RekorPublicKeyPath,TileSnapshotPath,SparseProofPath) must resolve underBundleRootDirectory; URI inputs and path escapes fail closed. PayloadDigestmust be the 32-byte SHA-256 digest used to form the Rekor RFC 6962 leaf hash.RequireTileConsistency=truerequires localrekor-tile-snapshot.json.RequireSparseConsistency=truerequires localrekor-sparse-proof.json.
Default local resolution order:
- Receipt:
rekor-receipt.json,tlog/rekor-receipt.json,evidence/tlog/rekor-receipt.json,transparency/rekor-receipt.json,evidence/transparency/rekor-receipt.json. - Checkpoint:
checkpoint.sig,tlog/checkpoint.sig,evidence/tlog/checkpoint.sig,transparency/checkpoint.sig,evidence/transparency/checkpoint.sig. - Rekor public key: exactly one local key file (
*.pem,*.pub, or*.der) underkeys/tlog-root/,evidence/keys/tlog-root/, ortlog-root/; multiple matches are ambiguous and fail closed unlessRekorPublicKeyPathis explicit. - Full tile snapshot:
rekor-tile-snapshot.json,tlog/rekor-tile-snapshot.json,evidence/tlog/rekor-tile-snapshot.json,transparency/rekor-tile-snapshot.json,evidence/transparency/rekor-tile-snapshot.json. - Sparse proof:
rekor-sparse-proof.json,tlog/rekor-sparse-proof.json,evidence/tlog/rekor-sparse-proof.json,transparency/rekor-sparse-proof.json,evidence/transparency/rekor-sparse-proof.json.
Verification behavior:
- The verifier always binds the receipt to the pinned local
checkpoint.sigbefore inclusion verification. An inline checkpoint insiderekor-receipt.jsonis diagnostic input only when a pinned checkpoint file is configured or discovered. - Signed-checkpoint inclusion is verified first through
RekorOfflineReceiptVerifier. - Local full tile snapshots are verified through
RekorTileRootConsistencyVerifierwhen present or required. - Local sparse proofs are verified through
RekorSparseTileProofVerifierwhen present or required. - The result includes resolved material paths plus per-stage diagnostics (
key,checkpoint,receipt,tile_snapshot,sparse_proof) so operators can see exactly which local file failed.
The verifier remains local/offline only. It does not fetch live Rekor checkpoints, tiles, entries, keys, or issuer metadata.
Fixture Contract (2026-04-28)
Positive offline transparency fixtures must contain all of the following material:
- payload or entry digest bytes used to compute the RFC 6962 leaf hash;
rekor-receipt.jsonwithlogIndex,rootHash, ordered pathhashes, and a checkpoint reference or inline checkpoint;- signed checkpoint note whose tree size and root hash match the receipt proof;
- local transparency-log public key that verifies the checkpoint signature.
Fixtures that only contain a Rekor UUID, log index, certificate text, JWS header, Fulcio issuer string, or unsigned checkpoint are negative/unavailable fixtures. They may be used to test diagnostics, but they must not produce Verified, valid, or equivalent transparency success.
Tile/root consistency positive fixtures must additionally contain rekor-tile-snapshot.json with complete level 0..root hash material. Fixtures without this file may still verify signed checkpoint inclusion, but they must not claim tile consistency.
Sparse proof positive fixtures must contain rekor-sparse-proof.json with the payload leaf hash and ordered proof nodes for the receipt path. Sparse fixtures without proofNodes, with only UUID/log index/checkpoint metadata, or with nodes that do not match the receipt hashes are negative/unavailable fixtures.
Scanner Consumer Contract (2026-04-28)
Scanner consumes Attestor Core’s offline Rekor receipt verifier through a narrow local adapter for signed SBOM archives and offline-kit imports. The adapter normalizes archive/snapshot material into the Attestor receipt contract and verifies:
SHA256(dsseEnvelopeBytes)is the payload digest used for the Rekor leaf;- the receipt includes
logIndex,rootHash, ordered Merkle pathhashes, and either inline checkpoint text or a checkpoint reference resolved from the local snapshot; - the signed checkpoint verifies against a local Rekor public key from the archive or snapshot;
- the recomputed RFC 6962 root equals both the receipt root and checkpoint root.
Scanner does not use online Rekor for this path and does not treat UUIDs, log indexes, JWS headers, unsigned checkpoints, or Fulcio issuer strings as proof. The local bundle must include the Rekor public key, signed checkpoint, inclusion proof, and DSSE envelope bytes being verified.
Local JWS/Fulcio Verification Contract (2026-04-28)
VexLens can now verify the narrow offline JWS slice used by signed VEX inputs when all local proof material is present:
- compact JWS with a protected header containing
alg,kid, and anx5ccertificate chain; - a supported JWS algorithm (
ES256orRS256); - a leaf certificate whose public key verifies the JWS signing input;
- a Fulcio leaf certificate that is not a CA certificate and carries
digitalSignaturekey usage; - a certificate chain that terminates at a locally configured Fulcio root certificate loaded from
VexLens:Trust:SignatureTrustRootPathsor request-levelTrustRootPaths; - a leaf certificate Fulcio OIDC issuer extension (
1.3.6.1.4.1.57264.1.1) accepted by any request-level trusted issuer policy; - a verification time supplied by the request when deterministic replay needs to pin certificate validity.
The verifier remains fail-closed for missing local roots, missing x5c, malformed certificate material, unsupported critical JWS headers, unsupported algorithms, missing/untrusted Fulcio issuer extensions, CA/non-signing leaf certificates, tampered signatures, and revocation checks that would require online lookup. JWS kid, issuer strings, Fulcio OIDC extension text, and certificate presence are diagnostic metadata only until signature verification, local chain validation, leaf-certificate checks, and issuer-policy checks succeed.
Local JWKS/kid JWS Verification Contract (2026-04-28)
VexLens can also verify compact JWS inputs without x5c when the offline kit provides local JWKS material through VexLens:Trust:SignatureTrustRootPaths or request-level TrustRootPaths.
Required local proof material:
- compact JWS with a protected header containing a supported
alg(ES256orRS256) and non-emptykid; - a local JWKS file or offline bundle directory containing a matching
kid; - for
ES256, a JWK withkty=EC,crv=P-256, and publicx/ycoordinates; - for
RS256, a JWK withkty=RSAand publicn/evalues; - the resolved key fingerprint in the request’s trusted key allowlist when such a policy is configured;
- a signature over the compact JWS signing input that verifies with the selected JWKS public key.
The verifier remains fail-closed for missing kid, absent local JWKS material, unknown kid, unsupported or incompatible JWK key material, alg mismatches between the protected header and selected key, key fingerprints outside the configured trusted set, unsupported critical JWS headers, unsupported algorithms, and tampered signatures. A kid, JWKS file, or algorithm name alone is not proof; success requires local key resolution plus cryptographic signature verification.
Local Detached JWS Payload Binding Contract (2026-04-28)
VexLens supports the compact detached JWS shape used by offline signed VEX inputs when the caller supplies both pieces explicitly:
SignatureVerificationRequest.Contentcontains the signed payload bytes.SignatureVerificationRequest.DetachedSignaturecontains the compact JWS signature. For a detached compact JWS, the middle payload part is normally empty (header..signature).- The verifier reconstructs the JWS signing input as
base64url(protectedHeader) + "." + base64url(Content)before applying the existing local Fulciox5cor local JWKS/kid verification rules. - If
DetachedSignaturecarries a non-empty compact payload part, it must exactly matchbase64url(Content); otherwise verification fails closed withERR_JWS_DETACHED_002.
Rules:
- A detached-shaped compact JWS (
header..signature) passed asContentwithoutDetachedSignaturefails closed withERR_JWS_DETACHED_001. - Detached verification with empty payload bytes fails closed with
ERR_JWS_DETACHED_001. - Altering
Contentchanges the reconstructed signing input and must make cryptographic signature verification fail. - Fulcio local roots, JWKS/kid lookup, trusted issuer/key policies, and local revocation-bundle checks still gate success after payload binding.
- JWS with
b64=falseremains unsupported because the verifier rejects unsupported critical protected headers; offline signed VEX callers must use the default base64url-encoded JWS payload contract.
Local JWS Revocation Bundle Contract (2026-04-28)
When a VexLens caller sets SignatureVerificationOptions.CheckRevocation=true, compact JWS verification now requires a local revocation bundle in the configured trust-root paths. The verifier searches only local files named revocations.json, revocation-bundle.json, or *.revocations.json; it does not fetch OCSP, CRL, Fulcio, Rekor, or issuer metadata over the network.
Bundle schema:
{
"schemaVersion": "stellaops.vexlens.revocation.v1",
"generatedAt": "2026-04-28T00:00:00Z",
"revokedCertificates": [
{
"certificateSha256": "<sha256 of DER certificate bytes>",
"certificateThumbprintSha1": "<optional compatibility thumbprint>",
"issuer": "<optional issuer DN>",
"serialNumber": "<optional serial>",
"revokedAt": "2026-04-28T00:00:00Z",
"reason": "keyCompromise"
}
],
"revokedKeys": [
{
"keySha256": "<sha256 of SubjectPublicKeyInfo>",
"reason": "keyRetired"
}
]
}
Rules:
- Missing local revocation material fails closed with
ERR_JWS_REVOCATION_001. - Malformed or unsupported revocation material fails closed with
ERR_JWS_REVOCATION_002. - A verified Fulcio
x5cJWS fails withRevokedCertificatewhen the leaf certificate matches a revoked certificate entry. - A verified local JWKS/kid JWS fails with
RevokedCertificatewhen the selected public-key fingerprint matches a revoked key entry. - An empty revocation bundle is allowed as a local “no known revocations in this snapshot” statement, but it gates only an already cryptographically verified JWS path. The bundle itself is not proof of issuer trust.
Scanner Signed-SBOM Revocation Bundle Contract (2026-04-28)
Scanner signed-SBOM archives reuse the same local revocation bundle schema for Fulcio leaf certificate revocation checks. Callers that request revocation checking must supply the bundle locally with the signed-SBOM material; Scanner does not fetch OCSP, CRL, Fulcio, Rekor, or issuer metadata.
Rules:
- Revocation checking runs only after the SBOM DSSE payload/signature verifies and the signing leaf chains to a configured local Fulcio root.
- Missing bundle material fails closed.
- Malformed JSON, unsupported
schemaVersion, or invalid revoked-certificate entries fail closed. - The verified Fulcio leaf is rejected when it matches
certificateSha256,certificateThumbprintSha1, orissuerplusserialNumber. - Optional
revokedAtentries are active for proofs signed at or afterrevokedAt. If deterministic signing timestamp material is absent, a matchingrevokedAtentry is treated as active. - Empty bundles are allowed only as local “no known revocations in this snapshot” statements for an already verified DSSE/Fulcio path.
Scanner signed-SBOM archives now validate local Fulcio chains before packaging keyless material, can enforce local revocation bundles when requested, enforce strict local full-snapshot Rekor tile/root consistency when CheckRekorTileConsistency=true or when rekor-tile-snapshot.json material is supplied, and enforce bounded sparse proof consistency when CheckRekorSparseConsistency=true or when rekor-sparse-proof.json material is supplied. Scanner producer handoff treats includeRekorProof=false as a request to omit proof files from the emitted archive only; any supplied Rekor/tile/sparse material or consistency flag still forces local verification before storage. The cross-module fixture in src/VexLens/__Tests/StellaOps.VexLens.Tests/Verification/CrossModuleTransparencyFixtureTests.cs combines Scanner-shaped DSSE/Fulcio/Rekor material with VexLens compact JWS/JWKS/revocation material and verifies the two proof shapes are not accepted interchangeably. Still unsupported in these slices: online Fulcio discovery, online Rekor tile fetching/consistency proofs, and persisted arbitrary tile-source lookup.
