Skip to content

Follow-ups from #779: seal after bundle verification, owner-auth wording, config-digest changelog #782

Open

Description

@imran-siddique

Three follow-ups from the review of #779 at dd07fac. None blocks the merge; each is small.

  1. Seal after the policy bundle verifies. On the first start the key is sealed (startup.py:542) before the bundle is checked (:693). If that bundle fails, the start aborts but leaves the store sealed to the bad digest, so the next good start refuses with SEALED_KEY_DIGEST_MISMATCH until someone runs rotate.
  2. Say plainly what protects the sealed key. Sealing works only with an empty TPM owner password, so any process that can open the TPM device and read sealed_key_dir can unseal. The security model doc and the seal.py docstring should say that.
  3. Correct the CHANGELOG line: the config digest changes for every deployment on upgrade, not only with sink_policy.

Optional: TPM-free unit tests for the reseal hash check and the post-rotation gate check.

Activity

  1. dinakarjs commented on Oct 21, 2026

    @dinakarjs
    Contributor

    @rajnisht7 @Yatsuiii A bounded adoption candidate for the three requested items is ready at dinakarjs#3, commit b42dd44, based exactly on #779's dd07fac. I am preserving Rajnish's assignment and the parent author's branch.

    It defers provisioning/unseal until the existing policy verification succeeds, clarifies the empty-owner-password plus TPM-device/store access boundary, and corrects the configuration-digest changelog for default sink_policy deployments. Four new tests exercise the real policy loader with synthetic TPM seams; all four fail behaviorally against original startup.py and pass with the fix.

    Linux/Python 3.11.17: final full unit suite 2521 passed, 8 skipped; focused startup/sealing/policy selection 157 passed, 1 skipped; Ruff, mypy (77 source files), Bandit and whitespace checks pass. All five published modified blobs match local files. The draft records the earlier native-library interruption and inherited-proxy setup failures; final full run isolates proxy environment variables without committed dependency changes.

    Please adopt or review this single-commit correction on the selected branch. No swtpm/hardware run or independently observed recovery is claimed. Measurement and store locking remain earlier than verification; this is not an atomic measurement/loaded-policy snapshot fix. Optional reseal/rotation test additions remain separate. The issue stays open for owner adoption, final-head review and the required independent maintainer approvals. Prepared with Codex.

  2. dinakarjs commented on Oct 21, 2026

    @dinakarjs
    Contributor

    The optional TPM-free lifecycle controls are now a separate adoption companion: dinakarjs#5, head 2a4b490, stacked on the existing fix b42dd44.

    Six cases invoke real reseal/rotation orchestration: accepted versus changed policy bytes, and absent/unwritten/written/foreign gate profiles. They observe mocked TPM calls and actual store-file contents. Three isolated mutations catch omitted verified-hash comparison, omitted gate-profile validation, and omitted sentinel writes (1/1/2 failures respectively); source restored exactly.

    Final fresh Linux/Python 3.11.17 installed-checkout run: 2,585 passed, 8 skipped across unit/conformance; Ruff, mypy, Bandit, dependency consistency and whitespace pass. Published test bytes verified. Setup corrections and exact evidence limits are recorded in the draft.

    No swtpm, host TPM, hardware gate state or recovery run is claimed. This preserves the current owner/author and leaves adoption, final-head CI and required independent approvals open. Prepared with Codex.

  3. dinakarjs commented on Nov 8, 2026

    @dinakarjs
    Contributor

    @rajnisht7 @Yatsuiii Closure recheck on 8 November: both owner-adoption companions remain open and unchanged: dinakarjs#3 at b42dd44 and dinakarjs#5 at 2a4b490. Please disposition adoption into the existing owner-led work, or name the remaining correction. These are prepared contributions with the pinned software validation recorded in each description; no new full rerun, upstream acceptance, TPM execution or recovery guarantee is claimed by this recheck. The signing-key lifecycle/security and independent-review requirements remain. I have not opened a competing upstream implementation. Prepared with OpenAI Codex.

  4. Yatsuiii commented on Nov 8, 2026

    @Yatsuiii
    Contributor

    Thanks for keeping this moving. #779 is merged now, so these would need a new upstream PR rather than an adoption into it.

    I ran b42dd44 on swtpm 0.10.2, one process per start. On main, a first start with an invalid manifest leaves a sealed key, and the next start after the fix is refused with SEALED_KEY_DIGEST_MISMATCH. cmcp key reseal recovers it with the same key, so no rotate is needed, but the refusal is still wrong for a start that never ran. With b42dd44 the failed start leaves no sealed key and the next start provisions normally.

    The same refusal still happens through checks that run after the new seal point, because those settings are part of the measured config. With b42dd44 applied, a first start that fails with KILL_SWITCH_REQUIRES_IDENTITY or AUDIT_STORE_UNAVAILABLE still leaves a sealed key, and the next start after the config fix is refused the same way. Nothing after that point uses the private key, and moving _finish_sealed_start to just before run_startup returns fixed all three cases on swtpm. A start that fails only at the port bind still provisions, since the CLI binds after run_startup returns.

    Two swtpm tests that CI runs need new expected codes with either version: test_an_unmeasurable_gateway_gets_no_key now gets CONFIG_ERROR, and test_a_tpm_that_has_gone_away_is_reported_not_raised gets the attestation report's IO failure. Both still refuse to start.

    The six tests in dinakarjs#5 pass on main, with b42dd44, and with the seal at the end of startup, so they cover the existing reseal and rotation paths rather than this change.

    @rajnisht7 it's assigned to you, so it's your call how to land it.

  5. dinakarjs commented on Nov 8, 2026

    @dinakarjs
    Contributor

    The revised upstream PR is #840 at 0beb5a3, now ready for independent review. It moves provisioning/unseal after all run_startup validation, including kill-switch identity, audit store and session store; carries the owner-auth/config-digest wording; and adds paired late-refusal/corrected-start tests plus four swtpm recovery cases. Historical policy-only dinakarjs#3 is closed as superseded; #5 remains a separate lifecycle-test companion.

    All six Linux/Windows Python 3.11/3.12/3.13 CI test jobs and governance passed: https://github.com/agentrust-io/cmcp/actions/runs/42487782062. Each Linux job reports 2,778 passed, 29 skipped and three subtests; the logs explicitly show all four new swtpm recovery cases and both changed diagnostic expectations passing. Documentation, CodeQL, confinement-reference, Docker and bounded ClusterFuzzLite checks also passed. Eight new software controls fail behaviorally with original startup.py. Published remote tree matches the validated local tree.

    @rajnisht7 retains the landing decision; @Yatsuiii's reproduction is credited. Formal reviewer assignment returned 403, so this handoff does not claim a successful assignment. Independent maintainer approvals remain. No host-TPM or production recovery claim; port-bind failures remain outside run_startup, and reseal rather than necessarily rotate can recover an existing bad-digest store. Prepared with OpenAI Codex.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions