Skip to content

security: add Ed25519 public-only permit verification without HMAC downgrade - #72

Merged
Shards-inc merged 14 commits into
mainfrom
security/ed25519-public-only-permit-verifier-20261102
Nov 2, 2026
Merged

Shards-inc merged 14 commits into
mainfrom
security/ed25519-public-only-permit-verifier-20261102

Conversation

@Shards-inc

Copy link
Copy Markdown
Member

P0 hardening for #68: public-only Ed25519 permit verification

Adds a versioned Ed25519 (v2) permit format while preserving exact v1 HS256 canonical bytes, permit IDs and existing API behaviour. A trusted separate issuer module signs v2 permits; the kernel holds only pinned Ed25519 public verification keys and cannot re-enable shared-secret verification within that instance.

Changes

  • v2 permit canonical payload adds version, algorithm and audience, covered by an Ed25519 signature and protocol-specific domain separator.
  • PublicVerificationKey pins key ID → issuer, target kernel audience and raw public key; explicit revoked state.
  • BaseKernel.set_public_verifiers(...) selects public-only mode, clears HMAC capability and enforces algorithm non-downgrade. Existing HMAC mode denies v2 permits.
  • PermitBuilder.build_unsigned_v2 makes a signed-input template; shards_kernel.issuer.sign_v2_permit uses a reviewed maintained crypto library.
  • HTTP/MCP wire preserves v1 shape and carries v2 fields explicitly.
  • Adversarial tests cover spoofed issuer, wrong audience, tampering, forged signature, HMAC downgrade, wrong public key, revoke, expiration, not-before and nonce replay.
  • CI installs optional crypto extra on every supported Python; runtime base remains dependency-free. Security operator guidance documents incomplete pieces.

Release gates

  • 4-version Python matrix, coverage, wheel and demo jobs green.
  • CodeQL, Codacy, CodeFactor and secret scanning green.
  • Check no signing-capable private or HMAC secret inside public-only kernel.
  • No changes to legacy v1 canonical signatures/IDs.

Explicitly NOT solved

Operator service deployment and approval, per-agent transport identity, durable/distributed nonce usage, signed policy/config, persistent revocation distribution, recovery and cross-process real gateway test. Do not close #68 or claim production readiness.

Related programme #63; future operator setup #69.

@codacy-production

codacy-production Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 74 complexity · 2 duplication

Metric Results
Complexity 74
Duplication 2

View in Codacy

AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@Shards-inc
Shards-inc marked this pull request as ready for review November 2, 2026 00:41
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T00:42:28.423849Z d86592a Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@Shards-inc
Shards-inc merged commit 1ce4a79 into main Nov 2, 2026
22 checks passed

@codacy-production codacy-production Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

✅ No blocking issues noticed

No blocking security or logic findings were identified. The required v2 verification, rejection, revocation, replay, validity, wire-format, and key-rotation scenarios are represented as tests.

A legacy compatibility regression test for exact v1 canonical bytes, signatures, permit IDs, and API behavior is still missing. The release-gate claims and the public-only keyring invariant also lack clear evidence or explicit coverage in this diff.

Test suggestions

  • Successful v2 Ed25519 verification and execution with only a public key configured in the kernel
  • Replay of an otherwise valid permit is rejected
  • Issuer mismatch, audience mismatch, permit tampering, invalid signature, and wrong public key are rejected
  • Revoked and unknown public keys are rejected
  • Public-only mode rejects legacy HMAC permits and prevents HMAC key configuration
  • Expiration and not-before validity checks reject permits
  • Wire round-trip preserves v2 fields and rejects missing v2 metadata
  • Issuer helper refuses wrong permit versions, pre-signed permits, invalid permit IDs, and non-Ed25519 keys
  • Legacy v1 canonical bytes, signatures, permit IDs, and API behavior remain unchanged
  • Key rotation/replacement behavior is tested without weakening public-only mode
Prompt proposal for missing tests
Consider implementing these tests if applicable:
1. Legacy v1 canonical bytes, signatures, permit IDs, and API behavior remain unchanged
Low confidence findings
  • Clarify and test the public-only keyring invariant, including behavior when a verifier already has HMAC material configured.
  • The release-gate claims should be backed by visible CI jobs or documented as externally enforced; this diff only makes the cryptography dependency available.

TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback

Comment thread shards_kernel/permits.py
Comment on lines +831 to +844
unsigned = PermitToken(
permit_id="",
issuer=self._issuer,
subject=self._subject,
jurisdiction=self._jurisdiction,
action=self._action,
params=self._params,
constraints=self._constraints,
max_executions=self._max_executions,
valid_from_ms=self._valid_from_ms,
valid_until_ms=self._valid_until_ms,
evidence_hash=self._evidence_hash,
proposal_hash=self._proposal_hash,
nonce=self._nonce or generate_nonce(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM RISK

Suggestion: Consider centralizing the shared PermitToken field construction in a private helper, leaving only algorithm-specific behavior in each builder. This would reduce the risk that v1 and v2 receive inconsistent defaults or validation as fields change.

See Clone in Codacy

TIP React 👍 if this review is right, or reply with what's wrong and how it could be better to help improve the reviewer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

P0: Separate permit issuance and verification with asymmetric signatures and key rotation

1 participant