Skip to content

Org membership: no member-cert expiry + no key rotation; write_trust not atomic #246

@laulpogan

Description

@laulpogan

Grouped lower-urgency findings from the v0.15 identity-layer audit (org/SSO + trust persistence). Filed together; split if picked up separately.

1. Member certs never expire (audit F-5) — MED/HIGH

identity.rs::sign_did_cert produces a raw Ed25519 sig over the DID with no not_after; org_membership.rs::evaluate_card_membership has no time check. A revoked operator's member_cert verifies forever offline. RFC-001 open question O6 ("version-based expiry, decide v0.14-beta") was never resolved in the implementation.
Fix: add not_after to the signed cert payload + enforce in evaluate_card_membership. Breaking cert-format change.

2. No org key rotation / revocation path (audit F-6) — HIGH (escalated by #1)

No wire org rotate-key. RFC-001 T19 designed the bridging-signature rotation but it's unimplemented. Combined with #1: a leaked org key signs forged member_certs for arbitrary op_dids that verify forever.
Fix: implement T19 rotation; #1's expiry is the prerequisite that makes revocation meaningful.

3. SSO verification pipeline is absent (audit F-1..F-4, F-9) — informational until SSO ships

sso_provider.rs is claim-normalization only — no JWKS fetch, no iss byte-equal (Keycloak uses iss.contains("/realms/")), no exp/aud/nonce/receiver_did checks. So SSO→ORG_VERIFIED isn't reachable yet; these matter when the §B pipeline is wired. Generic adapter also accepts http:// issuers.
Fix: implement the amendment-sso §B verification stack before exposing the SSO channel; reject non-HTTPS sso_iss.

4. write_trust is neither atomic nor flocked (audit H-3) — MED

config.rs::write_trust does a raw fs::write while the sibling write_relay_state uses flock + tmp+rename. Concurrent daemon-pull + foreground wire accept can lose a pin or half-write trust.json.
Fix: copy the write_relay_state flock + tmp+rename pattern to write_trust (+ trust.lock).

5. Group introduce_pin doesn't verify member key ↔ DID (audit M-4) — MED

cli/group.rs::introduce_pin trusts roster-supplied key/did without checking sha256(key)[..4] == the DID's 8-hex suffix; dedups by key_id string only. A signed-but-malicious roster could pin a mismatched key.
Fix: verify did_commits_to_key (now available from #244) in introduce_pin; dedup by (key_id, key_bytes).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions