test bundles: DSSE-with-hashedrekord on Rekor v2#371
Conversation
|
Might be worth splitting into v1 and v2 changes. At least we can get the v2 changes in? |
|
I'll test the v2 changes against the sigstore-java impl for now though. |
|
I thought in the sigstore-go meeting we had discussed doing this only for Rekor v2? +1 to splitting these. I don't think we should pursue this change in Rekor v1 if it's a breaking change to verification. We will have to test this and conformance is the easiest way to do so. But I assume it will be a breaking change because clients won't know to construct the PAE as the artifact, either when comparing it to the hash digest in the canonicalized body or if the client reconstructed the leaf hash themselves. I want to avoid having a divergent signing path with a flag to control how signing is done for v1, that's just more technical debt we have to keep track of. |
|
the v2 tests are working as expected in sigstore-java (on my branch). I think we need to get this into sigstore-python first maybe? (or xfail on the self test... we've done this before as long as there was confirmation that they work)? @jku |
|
also cosign-nightly is gonna be mad if it can't handle these new tests. |
|
otherwise lgtm |
|
Can we create a PR to xfail these tests with Cosign before this lands? |
|
I have a PR for sigstore-python here: sigstore/sigstore-python#1776 |
|
I'll have a look at sigstore-python today but I have not problem with xfails being added for the selftest client (as long as someone has tested the cases with another compliant client). |
|
I can make a release of the current state of conformance if that makes it easier for clients. We can make another one when this merges |
* verify, rekor: encode DSSE as hashedrekord for Rekor v2 Implements rekor-v2-spec §6.1.4: DSSE envelope entries are submitted and verified as hashedrekord/0.0.2 with digest = Hash(PAE(payloadType, payload)) and signature.content = envelope.signatures[0].sig. This is vibecoded — a maintainer should take a closer look at correctness, especially the hash-algorithm dispatch in _hash_for_key_details and the entry-body reconstruction in _validate_hashedrekord_v002_dsse_entry_body. Passes the draft conformance tests in sigstore/sigstore-conformance#371. Related spec change: sigstore/architecture-docs#63 Signed-off-by: Cody Soyland <cody.soyland@chainguard.dev> * verify: fix lint (import order, format, quoted annotation) Signed-off-by: Cody Soyland <cody.soyland@chainguard.dev> * Add Envelope.pae() helper Replace cross-module `_pae` imports in the Rekor v2 producer and DSSE hashedrekord verifier with a public `Envelope.pae()` method. Addresses review feedback on #1776: drops the cross-module use of a private symbol and lets the hashedrekord-for-DSSE docstring read as `Hash(envelope.pae())`. No behavior change. Signed-off-by: Cody Soyland <cody.soyland@chainguard.dev> * Drop dsse/0.0.2 verifier path; replace staging test fixture Rekor v2 will not support the dsse entry type — DSSE envelopes are encoded as hashedrekord/0.0.2 (rekor-v2-spec §6.1.4). Remove the now-orphaned dsse/0.0.2 dispatch branch and `_validate_dsse_v002_entry_body` function. The dsse/0.0.1 path stays for Rekor v1 legacy bundles. Replaces `test/assets/a.dsse.staging-rekor-v2.txt.sigstore.json` with the `rekor2-dsse-happy-path` fixture from the sigstore-conformance `dsse-hashedrekord-test-bundles` branch, so the staging DSSE verification test now exercises hashedrekord/0.0.2 end-to-end. Addresses review feedback on #1776. Signed-off-by: Cody Soyland <cody.soyland@chainguard.dev> * key_details: centralize algorithm registry; use for DSSE prehash Replace the inline hash-for-key-details mappings in verifier.py and the hardcoded SHA-256 in client_v2.py with a single algorithm registry table in key_details.py, matching the spec at architecture-docs/algorithm-registry.md. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Cody Soyland <cody.soyland@chainguard.dev> * key_details: fix HashAlgorithm for pure Ed25519 HASH_ALGORITHM_UNSPECIFIED doesn't exist in sigstore_models; use None instead, since _get_prehash already rejects algorithms with no prehash. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Cody Soyland <cody.soyland@chainguard.dev> * key_details: narrow None check so mypy sees non-None hash_algorithm Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Cody Soyland <cody.soyland@chainguard.dev> * conformance: bump sigstore-conformance to v0.0.28 Signed-off-by: Cody Soyland <cody.soyland@chainguard.dev> --------- Signed-off-by: Cody Soyland <cody.soyland@chainguard.dev> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d-DSSE bundles The four rekor2-dsse-* fixtures were re-signed against staging Sigstore so their tlog entries use kind=hashedrekord/0.0.2 with Hash(PAE(payloadType, payload)) as the recorded digest, instead of the previous dsse/0.0.2 entries that committed to the whole envelope. This matches the encoding described in the architecture-docs PR sigstore/architecture-docs#63 and exercised by the corresponding sigstore-go signing/verification changes. Adds four new dsse-with-hashedrekord-* fixtures covering the same matrix on Rekor v1 (kind=hashedrekord/0.0.1, signed against production Sigstore Public Good with sigstore-go's experimental hashedrekord-over-DSSE flag enabled), replacing the two pre-existing dsse-with-hashedrekord/ and dsse-with-hashedrekord_fail/ dirs. The four scenarios per family are: *-happy-path : valid bundle, must verify *-mismatch-sig_fail : same cert, same PAE, but envelope.sig != tlog.sig (a second valid signature of the same PAE was swapped in) *-mismatch-envelope_fail : same cert, envelope swapped for one covering a different payload so Hash(PAE(envelope)) != tlog.digest *-invalid-sig_fail : envelope.sig was made by an unrelated key and does not verify under the bundle's certificate All bundles use the sigstore-conformance/extremely-dangerous-public-oidc-beacon workflow identity (the suite's default in test/client.py). The rekor v2 bundles ship a custom trusted_root.json (the staging trust root); the rekor v1 bundles use the default production trust root. Signed-off-by: Cody Soyland <cody.soyland@chainguard.dev>
The architecture-docs spec change scopes the dsse-hashedrekord proposal to Rekor v2 only and drops the Rekor v1 bridge feature paragraph. These fixtures covered the v1 bridge encoding (kind=hashedrekord/0.0.1 whose data.hash = SHA256(PAE(payloadType, payload))) and no longer correspond to a supported wire format. The rekor2-dsse-* fixtures (v2 path) remain. Signed-off-by: Cody Soyland <cody.soyland@chainguard.dev>
9badc81 to
a486574
Compare
|
we can upgrade the selftest client even without a sigstore-python releases: (I see we've forgotten to update version in there the last time something like this happened, oops) |
Signed-off-by: Cody Soyland <cody.soyland@chainguard.dev> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Cody Soyland <cody.soyland@chainguard.dev>
|
Is this ready to go? I think we could merge this so clients could easily test against main branch -- we could still hold off releasing new conformance until the main clients have their implementations ready. |
Yeah, it should be good to go now. I just ran it against my local branch of sigstore-go again and it passes. |
jku
left a comment
There was a problem hiding this comment.
lgtm, thanks for all your work on this
Summary
Regenerates the four
rekor2-dsse-*fixtures so the suite has end-to-end test coverage for the DSSE-with-hashedrekord client behaviour described in sigstore/architecture-docs#63.For DSSE envelopes the tlog entry is now a
hashedrekordwhosedatadigest isHash(PAE(payloadType, payload))— the same bytes the DSSE signature covers — rather than adsse/intotoentry over the whole envelope. The architecture-docs spec change scopes this proposal to Rekor v2 only, so these bundles are signed against staging Sigstore (staging Fulcio + staging Rekor v2) and their tlog entries arekind=hashedrekord/0.0.2, replacing the priordsse/0.0.2entries. Each dir still ships its stagingtrusted_root.json; once production has a Rekor v2 instance the custom trust root can be removed.The four scenarios:
rekor2-dsse-happy-pathrekor2-dsse-mismatch-sig_failenvelope.sig != tlog.sig(a second valid signature of the same PAE was swapped in) — exercises §4.4.1 #2 (signature-equality)rekor2-dsse-mismatch-envelope_failHash(PAE(envelope)) != tlog.digest— exercises §4.4.1 #1 (digest-equality)rekor2-dsse-invalid-sig_failenvelope.sigwas made by an unrelated key and does not verify under the bundle's certificateIn every
_faildir the RFC3161 TSA timestamp'smessageImprintis over the swapped-in envelope signature (not the original tlog signature), so the timestamp check passes and the bundle fails only for the labelled reason.All bundles use the
sigstore-conformance/extremely-dangerous-public-oidc-beaconworkflow identity (the suite's default intest/client.py), so no per-diridentity/issueroverrides are needed.Related: sigstore/architecture-docs#63