Repository navigation
sign,trust-record-verify: reject private JWK members in thumbprint and key import (#567) - #574
Conversation
…d key import Reject RFC 7517, RFC 7518, and RFC 8037 private or symmetric JWK members (d, p, q, dp, dq, qi, oth, k) in sign.jwk_thumbprint, sign._pubkey_from_jwk, trust-record-verify jwkThumbprint, and trust-record-verify importEd25519, naming only the offending member keys without echoing secret values. Closes agentrust-io#567 Signed-off-by: Raghuvar Durga <177662415+drk-ram@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
dinakarjs
left a comment
There was a problem hiding this comment.
Independent review at 48510f0. Both Python public-key primitives reject the complete eight-member private/symmetric set before constructing the thumbprint/key. The TypeScript thumbprint and Ed25519-import paths use the same member set and preserve role-specific error codes; errors name members, not secret values. Public extensions remain allowed.
Linux/Python 3.12.14 with this head's hash-locked dev/conformance dependencies: 628 selected signing, provenance, cnf, bridge, revocation and public-error tests pass. npm ci from the committed lock and npm test: 119 pass. An independent 80-case sweep covers null/empty/list/object/sentinel values for all eight members through both Python primitives, with a passing public-extension twin and no sentinel in errors. Returned technical CI succeeds; Dependabot is skipped. DCO present. Nonblocking formatting nit: units.test.mjs has a new blank line at EOF (git diff --check); no source correction retained. This is bounded public-key-input validation review, not a broader security certification. Reviewed with OpenAI Codex assistance.
imran-siddique
left a comment
There was a problem hiding this comment.
Thanks @drk-ram, and @dinakarjs for running both suites. With #541 this closes both sides: records and schemas refuse private members, and so do the thumbprint and key-import helpers in Python and TypeScript. Non-blocking: sign.py now has its own copy of the private-member set; a follow-up could have provenance and models import it from one place.
What this changes
Contributor: Raghuvar Durga (@drk-ram)
Closes #567
While
schema/trace-claim.jsonandmodels.pyalready reject private JWK parameters onrecord["cnf"]["jwk"](per GHSA-vc4p-h84j-7qxj), the JWK thumbprint and public-key reconstruction primitives in both the Python SDK (src/agentrust_trace/sign.py) and the TypeScript SDK (trust-record-verify/src/jwk.ts,trust-record-verify/src/crypto.ts) previously inspected only public parameters (kty,crv,x,y,e,n) and silently ignored private or symmetric JWK members (d,p,q,dp,dq,qi,oth,k).This change updates:
sign.jwk_thumbprintandsign._pubkey_from_jwk(src/agentrust_trace/sign.py) to reject any JWK containing RFC 7517 / RFC 7518 / RFC 8037 private or symmetric key members (d,p,q,dp,dq,qi,oth,k) withValueError, naming only the offending member keys in sorted order and never echoing the secret material.jwkThumbprint(trust-record-verify/src/jwk.ts) andimportEd25519(trust-record-verify/src/crypto.ts) to reject any JWK carrying private key members withjwk_invalidand the role'smalformedcode (trusted_key_malformed,cnf_key_malformed, orinvalid_argument), respectively, without echoing secret values.trust-record-verify/differential/oracle.py(KEY_MESSAGES) to classify"JWK contains private key material"asmalformedso differential verification remains aligned across Python and TypeScript.Independent review noted that error messages rejecting private JWKs must never include
jwk[m]secret values and thatrevocation.check_bundlereachesjwk_thumbprintvia_trusted_bundle_key->_key_identifiersbefore_pubkey_from_jwk, so bothjwk_thumbprintand_pubkey_from_jwkare tested directly and throughverify_record,check_bundle,verify_bridge, andverify_successor_artifactwith a sentinel secret assertion.Type of change
Spec section
Reference SDKs (
src/agentrust_trace/sign.py,trust-record-verify/src/jwk.ts,trust-record-verify/src/crypto.ts) implementingspec/trace-v0.2.mdsection 3.2.2 and section 3.2.3 JWK handling.Tests for a fix
python tools/review_bar.py --base origin/main --head HEADreports 49 tests failing on behaviour againstorigin/main(e1560f3) and passing onHEAD:tests/test_sign_jwk_private_boundary.py::test_jwk_thumbprint_rejects_private_key_material_without_echoing_secret[d..k](8 cases)tests/test_sign_jwk_private_boundary.py::test_pubkey_from_jwk_rejects_private_key_material_without_echoing_secret[d..k](8 cases)tests/test_sign_jwk_private_boundary.py::test_verify_record_rejects_trusted_jwk_carrying_private_material[d..k](8 cases)tests/test_sign_jwk_private_boundary.py::test_check_bundle_rejects_trusted_bundle_key_carrying_private_material[d..k](8 cases)tests/test_sign_jwk_private_boundary.py::test_verify_bridge_rejects_trusted_authorizer_jwk_carrying_private_material[d..k](8 cases)tests/test_sign_jwk_private_boundary.py::test_verify_successor_artifact_rejects_trusted_observer_jwk_carrying_private_material[d..k](8 cases)tests/test_sign_jwk_private_boundary.py::test_multiple_private_jwk_members_are_listed_in_sorted_order(1 case)trust-record-verify/tests/units.test.mjs:jwkThumbprint and verifyRecord refuse private JWK members without echoing secret valuesValidation commands executed:
pytest tests/test_sign_jwk_private_boundary.py tests/test_sign.py tests/test_cnf_jwk_carries_key_material.py tests/test_provenance_cnf_boundary.py tests/test_intent_bridge.py tests/test_revocation_bundle.py tests/test_public_functions_raise_what_they_document.py-> passed (628 passed)npm --prefix trust-record-verify run build && npm --prefix trust-record-verify test-> passed (119 passed)trust-record-verifydifferential suite (generate_cases.py,oracle.py,run.mjs,compare.py --expect-external 12) -> passed (1644 cases, 1643 identical, 1 known divergence, 0 unexpected)python tools/review_bar.py --base origin/main --head HEAD-> passed (49 fail on behaviour on base, 0 fail on missing name)python tools/check_dashes.py-> passedruff check src/agentrust_trace/sign.py trust-record-verify/differential/oracle.py tests/test_sign_jwk_private_boundary.py-> passedmypy --strict src/agentrust_trace/sign.py tests/test_sign_jwk_private_boundary.py-> passedChecklist
git commit -s)CHANGELOG.mdupdated (for any normative change)<!-- CHANGED: #NNN: description -->in spec text