Skip to content
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

Add support for certificate chain to verify certificate #1659

Merged
merged 3 commits into from
Mar 25, 2022

Conversation

haydentherapper
Copy link
Contributor

@haydentherapper haydentherapper commented Mar 25, 2022

This adds a flag to provide a chain of CA certificates to verify a
certificate provided by flag. Callers should include a chain from the
parent of the certificate to the root.

While it'd be ideal to force the root to be specified out of band, by
TUF, that code is currently intertwined with expectations around Fulcio
and Rekor usage.

Signed-off-by: Hayden Blauzvern hblauzvern@google.com

Summary

Ticket Link

Ref #1554

Release Note

Added certificate chain flag for verifying a certificate provided by flag

@codecov-commenter
Copy link

codecov-commenter commented Mar 25, 2022

Codecov Report

Merging #1659 (7950fa2) into main (7402eb4) will increase coverage by 0.54%.
The diff coverage is 16.85%.

@@            Coverage Diff             @@
##             main    #1659      +/-   ##
==========================================
+ Coverage   28.18%   28.73%   +0.54%     
==========================================
  Files         139      139              
  Lines        7997     8214     +217     
==========================================
+ Hits         2254     2360     +106     
- Misses       5495     5602     +107     
- Partials      248      252       +4     
Impacted Files Coverage Δ
cmd/cosign/cli/dockerfile.go 0.00% <0.00%> (ø)
cmd/cosign/cli/manifest.go 0.00% <0.00%> (ø)
cmd/cosign/cli/options/certificate.go 0.00% <0.00%> (ø)
cmd/cosign/cli/verify.go 0.00% <0.00%> (ø)
cmd/cosign/cli/verify/verify.go 0.00% <0.00%> (ø)
cmd/cosign/cli/verify/verify_attestation.go 0.00% <0.00%> (ø)
cmd/cosign/cli/verify/verify_blob.go 11.34% <0.00%> (-0.64%) ⬇️
pkg/cosign/verify.go 18.42% <100.00%> (+2.10%) ⬆️
pkg/cosign/kubernetes/webhook/validator.go 80.49% <0.00%> (-1.22%) ⬇️
pkg/cosign/common.go 0.00% <0.00%> (ø)
... and 7 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7402eb4...7950fa2. Read the comment docs.

This adds a flag to provide a chain of CA certificates to verify a
certificate provided by flag. Callers should include a chain from the
parent of the certificate to the root.

While it'd be ideal to force the root to be specified out of band, by
TUF, that code is currently intertwined with expectations around Fulcio
and Rekor usage.

Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>
Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>
This also checks if the certificate matches a subject provided via flag.

Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>
@dlorenc dlorenc merged commit 87a85e6 into sigstore:main Mar 25, 2022
@github-actions github-actions bot added this to the v1.7.0 milestone Mar 25, 2022
@bburky
Copy link
Contributor

bburky commented Mar 29, 2022

I'm putting my verification notes and comments here, let me know if you'd rather all the comments in one place.

Is the following expected to work? Sign with a full chain, and verify with only the root? I was unable to get this to work. I verified the chain using openssl verify -CAfile root.pem -untrusted intermediate.pem cert.pem.

./cosign sign  "localhost:5000/$image"  --key "pkcs11:$key" --cert-chain full-chain.pem
# The following returns `error during command execution: x509: certificate signed by unknown authority`
./cosign verify  "localhost:5000/$image"  --cert cert.pem --cert-chain root.pem

Some follow up operations could make sense to add longer term:

# Don't pin the specific cert, just check that it was signed by the specified CA
$ cosign verify "$image" --cert-chain chain.pem
# Check the Email SAN of the leaf certificate:
$ cosign verify "$image" --cert-chain chain.pem  --cert-email user@example.com

# The only current operation possible with --cert-chain requires --cert too:
$ cosign verify "$image" --cert-chain chain.pem --cert cert.pem

# Additionally, the current error message here is misleading, `--cert` is also accepted here:
$ cosign verify "$image"
Error: exactly one of: key reference (--key), or hardware token (--sk) must be provided
main.go:46: error during command execution: exactly one of: key reference (--key), or hardware token (--sk) must be provided

@bburky
Copy link
Contributor

bburky commented Mar 29, 2022

I'm actually not sure if --cert-chain makes sense as an argument for cosign verify. Would a --roots flag make more sense actually? The verifier user wants to ask "is this signature made by a root I trust?" and should not need to provide the specific intermediates (unless the signature is missing a chain annotation).

A user may want to provide a root bundle, not a specific chain for verification. This isn't possible with a --cert-chain flag. Please see my comment on the above Kyverno issue too, it's along the same lines.

@haydentherapper
Copy link
Contributor Author

Is the following expected to work? Sign with a full chain, and verify with only the root? I was unable to get this to work. I verified the chain using openssl verify -CAfile root.pem -untrusted intermediate.pem cert.pem.

No, it would not work without the intermediate. The verification library needs the intermediate CA in order to build a chain from leaf to root. For OpenSSL, -untrusted is the same as the Intermediates certificate pool in Golang. If you were to drop -untrusted, verification should fail.

Don't pin the specific cert, just check that it was signed by the specified CA
$ cosign verify "$image" --cert-chain chain.pem

See the last part of this comment.

Check the Email SAN of the leaf certificate:
$ cosign verify "$image" --cert-chain chain.pem --cert-email user@example.com

This actually should work! It would require the --cert flag currently though.

cosign verify --cert cert.txt --cert-chain .sigstore/root/targets/fulcio_v1.crt.pem --cert-email "<my-email>" --cert-oidc-issuer "<oidc-issuer>" us-west1-docker.pkg.dev/project/repo/image:tag

# Additionally, the current error message here is misleading, --cert is also accepted here:

Good find, will update this!

Would a --roots flag make more sense actually?

This gets back to an initial remark I made about not supporting roots specified from the command line. I agree that it'd be reasonable to support a root bundle (and a bundle of intermediates for path finding too). I'd prefer to encourage users to use TUF for this however. This provides an out-of-band mechanism for forming the trust bundle, and that trust bundle can be verified by the TUF framework (Users can provide their own TUF metadata via cosign initialize). An alternative is creating a verification policy, something like what Cosigned is working on.

My concern with providing a certificate chain without pinning the certificate means a client could be coerced into using a chain that issued a certificate from an untrusted identity. The same issue arises with a trust bundle. By pinning the certificate and/or the identity of the certificate, this risk is reduced (the assumption being it should be easier to confirm a trusted identity rather than a trusted chain).

@bburky
Copy link
Contributor

bburky commented Mar 30, 2022

Ok thanks, it sounds like validation is working as intended then. This does support verifying "is this image signed by this specific cert with this specific full chain".

I look forward to seeing how other tooling can take advantage of these signatures and provide flexible verification policy.

mlieberman85 pushed a commit to mlieberman85/cosign that referenced this pull request May 6, 2022
* Add support for certificate chain to verify certificate

This adds a flag to provide a chain of CA certificates to verify a
certificate provided by flag. Callers should include a chain from the
parent of the certificate to the root.

While it'd be ideal to force the root to be specified out of band, by
TUF, that code is currently intertwined with expectations around Fulcio
and Rekor usage.

Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>

* Fix test

Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>

* Use function to validate certificate chain

This also checks if the certificate matches a subject provided via flag.

Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants