-
Notifications
You must be signed in to change notification settings - Fork 566
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix verifying when a certificate is provided #2633
Conversation
Keys were preferred over certificates. This caused an issue, because in the CLI functions that call verify, if you pass a certificate to verify with, we extract the public key from it and set that to co.SigVerifier while also setting sig.Cert. Checking if a certificate was provided first should mitigate this. Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>
Looking into unit test failures now |
The failure is when you provide both a key (which you want to verify with) and a bundle with a certificate. I think the fix is just to make this an error when taking in input. We don't allow you to specify more than one of (cert, security key, public key), so we shouldn't allow you to specify a bundle with a verifier (pub key or cert) if you also specified the verifier. (Note we would still allow a bundle + verifier if the bundle only contains the Rekor entry) (also note that we should still error if the rekor entry contains the wrong verifier, which I will make sure there’s a test for that case) Will follow up on Tuesday. |
// We have a public key. | ||
if co.SigVerifier != nil { | ||
switch { | ||
// certificate provided from the OCI image, or via flag (--certificate or --bundle) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% sure I understand the logic here, but I'm worried that this bit might have a subtle verification bug. Let me know if this makes sense:
If the user has specified --certificate
at the command line my understanding is that it get parsed and its public key is used in initialize co.SigVerifier
. This function appears to then return a certificate PEM if found on the OCI signature (which may be different than --certificate
😬 ). The function calling this one
Lines 1078 to 1081 in 29360f6
if !bytes.Equal(pemFirst.Bytes, pemSecond.Bytes) { | |
return fmt.Errorf("comparing public key PEMs, expected %s, got %s", | |
pemBytes, decodeSecond) | |
} |
My worry here is that the certificate compared to the rekor bundle might not be the one the user actually specified at the command line, unless that bit of logic is lurking in a different place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we have this issue now also, although it doesn’t surface any error. If you provide a certificate that certified the same public key as a certificate on the OCI imagine, but the rest of the cert differs, we wouldn’t notice.
Note this isn’t an issue for verify-blob since we construct a static OCI struct from input. For verify on OCI, theres no way to pass the certificate passed in from input
Sigh…maybe we could add a check that a provided cert matches what’s on the image annotations? Or disallow providing a certificate when the image annotations contain a certificate already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sigh…maybe we could add a check that a provided cert matches what’s on the image annotations? Or disallow providing a certificate when the image annotations contain a certificate already?
+1, see my comment below. I think --certificate
is a little misleading here. The --certificate
flag for OCI image never "makes" it into the pkg verification code (just the pub key does). In the CLI layer there's some verification of it, but once we get into pkg/verify
, we rely on sig.Cert()
.
Oof my brain I was confused why we hadn't caught this for https://github.com/sigstore/cosign/blob/main/cmd/cosign/cli/verify/verify_blob.go#L193-L197 Contrast this to verify: https://github.com/sigstore/cosign/blob/main/cmd/cosign/cli/verify/verify.go#L214-L243 This means that the certificate is used when comparing to the Rekor entry, because Not sure if this was intentional or accidental. I think it wasn't intentional because if a bundle is provided with a certificate in the bundle, we do set the verifier: https://github.com/sigstore/cosign/blob/main/cmd/cosign/cli/verify/verify_blob.go#L220 I think we should pick one place to set the verifier. Either require a verifier always provided (and figure out how to pass a certificate value into Lines 638 to 670 in 29360f6
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Yes this should have been the correct behavior -- chose cert, or choose public key PEM for the verifier.
One comment -- I think @nsmith5 identified the problem about the comparison in pkg/cosign/verify.go
linked in the comment. The more weird problem is in my comment, but --certificate
is never actually used besides public key extraction and verification BEFORE hitting the pkg. I think we either want to set the sig.Cert()
with this / override it, or disallow this flag when a sig.Cert()
is already specified on the OCI layer. Flag confusion..
// We have a public key. | ||
if co.SigVerifier != nil { | ||
switch { | ||
// certificate provided from the OCI image, or via flag (--certificate or --bundle) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this comment accurate / misleading? If it's OCI it will always take it in from the OCI image, NOT from the --certificate
flag. I think @nsmith5 issue shows a "Red herring" like you mentioned. I think the issue should have happened if the --certificate
was specified or not since it's comparing sig.Cert()
form the OCI annotation. The OCI verify CLI never sets that. So maybe
// certificate provided from the OCI image, or, in the case of a blob, via flag (--certificate or --bundle)
// We have a public key. | ||
if co.SigVerifier != nil { | ||
switch { | ||
// certificate provided from the OCI image, or via flag (--certificate or --bundle) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sigh…maybe we could add a check that a provided cert matches what’s on the image annotations? Or disallow providing a certificate when the image annotations contain a certificate already?
+1, see my comment below. I think --certificate
is a little misleading here. The --certificate
flag for OCI image never "makes" it into the pkg verification code (just the pub key does). In the CLI layer there's some verification of it, but once we get into pkg/verify
, we rely on sig.Cert()
.
After trying a few different approaches, the cleanest is to override sig.Cert() (if not set). We don't have any issues in verify-blob because we are setting sig.Cert() based on |
OK, so after repeatedly typing lines and deleting them, here's what I think I'll do:
|
Yup, this sounds like the right approach to me! |
This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 10 days. |
This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 10 days. |
This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 10 days. |
This PR was closed because it has been stalled for 10 days with no activity. |
Keys were preferred over certificates. This caused an issue, because in the CLI functions that call verify, if you pass a certificate to verify with, we extract the public key from it and set that to co.SigVerifier while also setting sig.Cert. Checking if a certificate was provided first should mitigate this.
Fixes: #2632
Signed-off-by: Hayden Blauzvern hblauzvern@google.com
Summary
Release Note
Documentation