rekor icon indicating copy to clipboard operation
rekor copied to clipboard

Better docs on how to verify signedEntryTimestamp

Open ernoc opened this issue 1 year ago • 10 comments

In order to verify signedEntryTimestamp, one needs to follow instructions that I could only find here in this yaml.

That's also the only specification I could find as to what's included in the signature (although I could be mistaken of course).

However, that's not easily discoverable in the docs, in particular, it doesn't show up on swagger docs.

Would be nice if these spec and instructions easily searchable in docs:

  • In swagger generated doc
  • Ideally, also somewhere like https://docs.sigstore.dev/verifying/verify/

ernoc avatar Jan 09 '24 17:01 ernoc

@tiziano88

ernoc avatar Jan 09 '24 17:01 ernoc

@ernoc there's also info here:

  • https://docs.sigstore.dev/verifying/timestamps/

ianhundere avatar Jan 09 '24 19:01 ianhundere

One question that comes to mind from reading the comments at https://github.com/sigstore/rekor/blob/4fcdcaa58fd5263560a82978d781eb64f5c5f93c/openapi.yaml#L433-L476 is Step 1 says "Remove the Verification object from the JSON Document".

The JSON document could be referring to:

  1. The entire JSON document, like the result of a curl as explained in https://docs.sigstore.dev/logging/verify-release/ , e.g.:
{
  "b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33": {
    "attestation": {},
    "body": "...",
    "integratedTime": 1627461494,
    "logID": "...",
    "logIndex": 25579,
    "verification": {...}
  }
}
  1. Just the LogEntry structure, e.g.:
{
  "attestation": {},
  "body": "...",
  "integratedTime": 1627461494,
  "logID": "...",
  "logIndex": 25579,
  "verification": {...}
}

I'm assuming the second is the right one?

ernoc avatar Jan 11 '24 12:01 ernoc

I have this same problem. I'm currently trying to manually do this by following the logic in cosign and/or in rekor.

I got a dump of the canonicalized entry from rekor and it looks like

{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoicmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJiNmQ2Y2E0MTAxOTNiYTQ0MDJiYjkwZjExYjgyM2UzNWM4NTc0MTQzMjhkN2M3YWM3YTgzMzQwZGMxYTZjODUyIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6IkxTMHRMUzFDUlVkSlRpQlRVMGdnVTBsSFRrRlVWVkpGTFMwdExTMEtWVEZPU1ZVd2JFaEJRVUZCUVZGQlFVRkVUVUZCUVVGTVl6Tk9iMHhYVm10TmFsVXhUVlJyUVVGQlFXZE5kREo2U0M5cUwwNUxaRUpxU2tSRVR6aG5id3AyTUVscVptNVFURkZITlhJeEsySXlNMGcwYm5vMlFVRkJRVUZGV20xc2MxcFJRVUZCUVVGQlFVRkJSMk15YUdoT1ZFVjVRVUZCUVZWM1FVRkJRWFI2Q21NeVozUmFWMUY1VGxSVmVFOVJRVUZCUlVGRlEzUk9ZamRWWmtSS1ZHaHNTblJZTVZSYVZrazJjWHBGU201Q1NUQTJTVFpWWTJsR1VVUjFNM3AyWjNVS1FXMTVLMFZzU1hKYVNXWlRTa3RTZG1KdU9HeFJOVGx2ZUhsdmVUUm5UVWxRSzFnemFHSnJSZ290TFMwdExVVk9SQ0JUVTBnZ1UwbEhUa0ZVVlZKRkxTMHRMUzBLIiwiZm9ybWF0Ijoic3NoIiwicHVibGljS2V5Ijp7ImNvbnRlbnQiOiJjM05vTFdWa01qVTFNVGtnUVVGQlFVTXpUbnBoUXpGc1drUkpNVTVVUlRWQlFVRkJTVVJNWkhONEx6UXZlbE51VVZsNVVYZDZka2xMVERsRFNUTTFlbmt3UW5WaE9XWnRPWFI0SzBvNEsyY0sifX19fQ==","integratedTime":1708462670,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d","logIndex":72768902}

So far though I can't quite get it to work

$ openssl dgst -sha256 -verify ~/.sigstore/root/targets/rekor.pub -signature tle_set_decoded tle_canon_entry 
Verification failure

I've also tried with a sha256sum of the tle_canon_entry.

lkatalin avatar Feb 20 '24 22:02 lkatalin

See https://github.com/sigstore/cosign/blob/main/pkg/cosign/verify.go#L1311-L1329 - We marshal the body, integrated time, log ID and log index, and then use a json canonicalization library before verifying it. That last step might be what's missing?

haydentherapper avatar Feb 20 '24 22:02 haydentherapper

This works, but it was pretty involved:

$ TLE=$(rekor-cli get --uuid $ARTIFACT_UUID --format tle); \
> JSON=$(rekor-cli get --uuid $ARTIFACT_UUID --format json); \
> echo -n $TLE | jq .inclusionPromise.signedEntryTimestamp | tr -d "'\"" | base64 -d > set_decoded; \
> echo -n {\"body\":$(echo $TLE | jq .canonicalizedBody)\,\"integratedTime\":$(echo $TLE | jq .integratedTime | tr -d "'\"")\,\"logID\":$(echo $JSON | jq .LogID)\,\"logIndex\":$(echo $TLE | jq .logIndex | tr -d "'\"")} > rekor-bundle-70959618; \
> openssl dgst -sha256 -verify ~/.sigstore/root/targets/rekor.pub -signature set_decoded rekor-bundle-70959618
Verified OK

I know the new Sigstore protobuf bundle will include some of this info; but is it correct that for now there is no simpler way to get the entire Rekor bundle other than parsing and stitching together fields from the rekor-cli get output? If so, I will open an issue and take a look at getting it to emit this in a simpler way. One problem is that while the --format tle flag outputs most of the info needed for the SET verification, the logID displayed there is different from what is displayed with the --format json flag (which is what is needed for the Rekor bundle / SET verification). So you end up having to call the rekor-cli with both format flags to get all the output you need to create the Rekor bundle correctly.

--format tle output:

...
"logId": {
    "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="
  },

--format json output:

...
"LogID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"

lkatalin avatar Feb 22 '24 19:02 lkatalin

A feature to output the canonicalized bundle seems reasonable.

haydentherapper avatar Feb 28 '24 07:02 haydentherapper

The documentation referenced above does not accurately describe how the verification is actually performed. The actual implementation in rekor does not canonicalize the JSON, but just deserialize the base64 body and verifies the output.

Moreover, the verification procedure above fails with some rekor entries, as it seems that old rekor entries (e.g., index 25579) have not been canonicalized properly. We noticed this issue in a sigstore-rs PR.

Is that a correct assessment? Should the documentation and/or verification procedure be updated?

gaetanww avatar Mar 18 '24 17:03 gaetanww

The actual implementation in rekor does not canonicalize the JSON, but just deserialize the base64 body and verifies the output

The SET verification (not inclusionProof verification) is doing canonicalization here. This is evident in the manual testing I did recently, where the payload for the SET always has the fields in alphabetical order: body, integratedTime, logID, logIndex.

The documentation should definitely be updated - I plan to work on that after adding the canonicalized Rekor bundle to rekor-cli output (draft PR here and I'm planning to make a Rekor PR based on the protobuf).

I'm not sure about the verification failure for older entries, maybe someone else knows about this.

lkatalin avatar Mar 19 '24 16:03 lkatalin

Left a comment on the issue on protobuf-specs.

I'm not sure about the verification failure. That could be due to a change in requirements for the type? Early on there were a few changes that should have warranted a new type that we didn't do. We can relax those constraints if need be.

haydentherapper avatar Mar 19 '24 21:03 haydentherapper