{"id":50495347,"url":"https://github.com/johnforfar/xnode-tpm-verify","last_synced_at":"2026-06-02T06:30:29.258Z","repository":{"id":355979692,"uuid":"1230499066","full_name":"johnforfar/xnode-tpm-verify","owner":"johnforfar","description":"TPM2 remote-attestation verifier service. Companion to johnforfar/xnode-tpm-attest. Deploys as an xnode-app.","archived":false,"fork":false,"pushed_at":"2026-05-06T05:05:53.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-06T06:20:55.135Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johnforfar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-06T03:53:26.000Z","updated_at":"2026-05-06T05:05:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/johnforfar/xnode-tpm-verify","commit_stats":null,"previous_names":["johnforfar/xnode-tpm-verify"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/johnforfar/xnode-tpm-verify","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnforfar%2Fxnode-tpm-verify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnforfar%2Fxnode-tpm-verify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnforfar%2Fxnode-tpm-verify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnforfar%2Fxnode-tpm-verify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johnforfar","download_url":"https://codeload.github.com/johnforfar/xnode-tpm-verify/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnforfar%2Fxnode-tpm-verify/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33810341,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-02T02:00:07.132Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-02T06:30:28.642Z","updated_at":"2026-06-02T06:30:29.248Z","avatar_url":"https://github.com/johnforfar.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# xnode-tpm-verify\n\nA minimal TPM 2.0 attestation **verifier** service. Companion to\n[`xnode-tpm-attest`](https://github.com/johnforfar/xnode-tpm-attest)\n(the prover side).\n\nThis is the service a node sends its quote bundles to. It validates the\nattestation key's signature on the quote, compares live PCR values\nagainst operator-pinned expected values, returns a verdict, and issues\nshort-lived signed receipts.\n\n## Status — v0.2 (Phase 2 shipped)\n\nNow in production-ready state for non-confidential workloads:\n\n- ✅ Server-side AK signature verification (RSASSA-PKCS1v1.5-SHA256 via openssl)\n- ✅ Bearer-token auth on operator endpoints (env: `OPERATOR_TOKEN`)\n- ✅ `/heartbeat` for continuous attestation (lighter than full `/verify-quote`)\n- ✅ `/badge/\u003capp\u003e` returning HTML or SVG for embedding in any frontend\n- ✅ Node enrollment ledger captures `(ak_fingerprint, ak_pub_pem, apps_attested)`\n- ✅ Receipts include `ak_signature_verified: true` + `ak_fpr` for chain-of-custody\n\nPhase 2.5 deferred (documented in caller's engineering handoff):\n- EIP-712 wallet auth (replaces bearer; clean integration via xnode-auth)\n- TPM-sealed credentials (`tpm2_makecredential` server-side)\n- ed25519 receipt signing (third-party verifiable, replaces HMAC)\n- Full Intel On-Die CA chain validation (intermediate not publicly downloadable)\n\n## Endpoints\n\n| Method | Path | Caller | Auth | Purpose |\n|---|---|---|---|---|\n| GET | `/` | anyone | — | health + summary stats |\n| GET | `/api` | anyone | — | machine-readable endpoint index |\n| POST | `/register-app` | operator | `Bearer $OPERATOR_TOKEN` | pin golden values for an app version |\n| GET | `/golden/\u003capp\u003e` | anyone | — | read pinned values |\n| GET | `/badge/\u003capp\u003e[.svg]` | anyone | — | HTML or SVG status badge for embedding |\n| POST | `/verify-quote` | node (prover) | AK signature on quote | submit quote, get verdict + attestation receipt |\n| POST | `/heartbeat` | node (prover) | AK signature on quote | continuous attestation (lighter, shorter TTL) |\n| POST | `/task-result` | node (prover) | links to prior receipt_id | submit task output, get task-completion receipt |\n| GET | `/receipt/\u003cid\u003e` | anyone | — | read a previously-issued receipt |\n\n## Deploying\n\nAs an xnode-app via `om`:\n\n```sh\nom app deploy --flake github:johnforfar/xnode-tpm-verify xnode-tpm-verify --wait true\nom app expose xnode-tpm-verify --port 8080 --domain attest.\u003cyour-xnode-domain\u003e\n```\n\nSet the operator token (optional but recommended in production) via a\nsecrets file the systemd unit auto-loads:\n\n```sh\necho 'OPERATOR_TOKEN=...random_64_hex...' \\\n  \u003e /run/secrets/xnode-tpm-verify.env\n```\n\nAfter that, anyone can query `https://attest.\u003cyour-xnode-domain\u003e/`.\n\n## Demo flow (verified end-to-end)\n\n```\n1. operator: POST /register-app    pin app + closure hash\n2. prover:   GET  /golden/\u003capp\u003e    fetch what verifier expects\n3. prover:   tpm2 pcrextend 16:sha256=\u003cbinary_hash\u003e\n             tpm2 pcrextend 16:sha256=\u003cmodel_hash\u003e\n4. prover:   tpm2 quote             with verifier-supplied nonce\n5. prover:   POST /verify-quote     with quote + AK pubkey + live PCRs\n6. verifier: parse, openssl-verify AK sig, compare PCRs\n             → attestation receipt\n7. prover:   run real task (Qwen3 inference, image gen, etc.)\n8. prover:   POST /task-result      input + output hashes + prior receipt\n9. verifier: validate prior is fresh + attested\n             → task-completion receipt linking input → output → attestation\n```\n\n## Embedding the badge in your app frontend\n\nThree patterns — all load from the verifier directly so the source\ncan't lie about its own attestation status:\n\n```html\n\u003c!-- iframe (simplest) --\u003e\n\u003ciframe src=\"https://attest.\u003cyour-xnode-domain\u003e/badge/\u003capp\u003e\"\n        width=\"100%\" height=\"60\" frameborder=\"0\"\u003e\u003c/iframe\u003e\n\n\u003c!-- inline SVG with click-through to the receipt --\u003e\n\u003ca href=\"https://attest.\u003cyour-xnode-domain\u003e/receipt/\u003clatest-id\u003e\"\u003e\n  \u003cimg src=\"https://attest.\u003cyour-xnode-domain\u003e/badge/\u003capp\u003e.svg\"\u003e\n\u003c/a\u003e\n\n\u003c!-- JS polling for live updates --\u003e\n\u003cdiv id=\"attest-status\"\u003e…\u003c/div\u003e\n\u003cscript\u003e\n  async function refresh() {\n    const r = await fetch('https://attest.\u003cyour-xnode-domain\u003e/badge/\u003capp\u003e');\n    document.getElementById('attest-status').innerHTML = await r.text();\n  }\n  refresh(); setInterval(refresh, 60_000);\n\u003c/script\u003e\n```\n\n## Storage layout\n\n```\n$STATE_DIR/\n├── apps.json           registered apps + golden values\n├── nodes.json          enrolled node ledger (ak_fingerprint → metadata)\n├── attestations.jsonl  audit log of all submitted quotes\n├── receipts.jsonl      audit log of all issued receipts\n└── verifier.secret     HMAC key (auto-generated, mode 0600)\n```\n\nState is JSON-file backed for simplicity; production rollout would swap\nin SQLite or PostgreSQL with the same schema.\n\n## Engineering handoff\n\nFor full architecture, threat model, integration recipes, and Phase 3\nroadmap, see the consuming project's engineering doc (private\ndocumentation; pointer available on request).\n\n## License\n\nMIT.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnforfar%2Fxnode-tpm-verify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohnforfar%2Fxnode-tpm-verify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnforfar%2Fxnode-tpm-verify/lists"}