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

policy.json BYOPKI signature verification API #2579

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

QiWang19
Copy link
Collaborator

@QiWang19 QiWang19 commented Sep 20, 2024

@QiWang19 QiWang19 changed the title policy.json BYOPKI signature verification API WIP: policy.json BYOPKI signature verification API Sep 20, 2024
@QiWang19
Copy link
Collaborator Author

Hi @mtrmac , I’ve created this draft PR for the policy.json API change, could you take a look and provide your initial thoughts on the structure of the API update?
I just want to make sure I’m on the right path before proceeding further. My plan is to merge both the API and code support in a single PR. What do you think?

Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks good overall.

Earlier discussion openshift/enhancements#1658 .

Doing both the API and implementation in one PR works for me, having the API available but broken is not really helping anything.

signature/policy_types.go Show resolved Hide resolved
signature/policy_types.go Outdated Show resolved Hide resolved
signature/policy_types.go Outdated Show resolved Hide resolved
@QiWang19 QiWang19 force-pushed the byo-pki-verify branch 2 times, most recently from b3a0606 to f8585cd Compare October 2, 2024 23:08
@QiWang19 QiWang19 changed the title WIP: policy.json BYOPKI signature verification API policy.json BYOPKI signature verification API Oct 3, 2024
@QiWang19 QiWang19 marked this pull request as ready for review October 3, 2024 02:12
@QiWang19
Copy link
Collaborator Author

QiWang19 commented Oct 3, 2024

@mtrmac Could you please take a look? It's ready for review. I am unsure about how I’m handling the intermediate certificates.

Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few-minute first pass — this looks very good. I didn’t read this carefully, and I skipped the tests completely, for now.

Combining the policy-provided and signature-provided intermediate certificates makes sense to me, but I’ll at least check what Cosign does.

signature/pki_cert.go Outdated Show resolved Hide resolved
}

// isIntermediateCA checks if the certificate is an intermediate CA
func isIntermediateCA(cert *x509.Certificate) bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s not immediately clear to me that this is necessary, I’d expect the crypto/x509 code to validate the intermediates are usable. Is there a specific reason to filter them this way? If so, it would be nice to document that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this because I’m not sure if multiple root certificates will be included in the untrustedIntermediateChainBytes from dev.sigstore.cosign/chain. So, I’ve been filtering out intermediates from the data. Do you think this is necessary?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the principle of the thing, and reading crypto/x509.Certificate.buildChains, an intermediate entry is only trusted if it is signed by some other CA. So including any extra certificates should not hurt — after all, an attacker can include arbitrary intermediate certificates in the signature.

(Also — probably not for sigstore, but in general — there are transition scenarios, where a new CA might get its to-be-root certificate signed by some other CA; this to-be-root certificate can then be accepted as an intermediate. That’s a valid situation (again, in general, probably not now for sigstore, and not for the BYOPKI users).

The certificate/issuer link is nowadays primarily happening via SubjectKeyId/AuthorityKeyId fields, so it seems to me it is possible to for an intermediate to have cert.Issuer == cert.Subject.)

signature/policy_eval_sigstore.go Outdated Show resolved Hide resolved
signature/policy_eval_sigstore.go Outdated Show resolved Hide resolved
@mtrmac
Copy link
Collaborator

mtrmac commented Oct 3, 2024

Cc: @Honny1 as well — c/image/signature is a somewhat separate part of the codebase, and as security-critical with a lot of paranoia. Worth understanding the structure and idioms.

@QiWang19
Copy link
Collaborator Author

QiWang19 commented Oct 9, 2024

@mtrmac Do you think the PKI code needs a file like fulcio_cert_stub.go and should include build tags? I'm not fully clear on the purpose of this compile configuration.

@mtrmac
Copy link
Collaborator

mtrmac commented Oct 9, 2024

The signature/*_stub.go files were added in #2180 , to avoid dependencies on sigstore Go modules not packaged (at the time??) in Debian.

Here, the only similar dependency seems to be github.com/sigstore/sigstore/pkg/cryptoutils, which is also required by no-stubbed policy_eval_sigstore.go; so this shouldn’t need a stub.

@QiWang19
Copy link
Collaborator Author

Combining the policy-provided and signature-provided intermediate certificates makes sense to me, but I’ll at least check what Cosign does.

I checked some cosign code, maybe I got lost in the code path, I did see it process the signature-provided intermediate certificates 🤔

@QiWang19
Copy link
Collaborator Author

@mtrmac could you review?

signature/policy_eval_sigstore.go Outdated Show resolved Hide resolved

untrustedIntermediatePool := x509.NewCertPool()
if pkiTrustRoot.caIntermediatesCertificates != nil {
untrustedIntermediatePool = pkiTrustRoot.caIntermediatesCertificates
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICS this … (A)

}
if len(untrustedIntermediateChain) > 1 {
for _, untrustedIntermediateCert := range untrustedIntermediateChain {
untrustedIntermediatePool.AddCert(untrustedIntermediateCert)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(A) … and this, together, means, that pkiTrustRoot.caIntermediatesCertificates will grow over time as validations happen.

Right now that doesn’t really matter, but see the pending // FIXME: move this to per-context initialization — the idea is that “the trust root” is computed once and ~immutable, maintained over the lifetime of a PolicyContext for possibly many signature validations.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also added the same comment before these lines of code.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s not just the comment, it’s that the “trust root” is supposed to represent a trust root, and now it accumulates unrelated untrusted data. That’s confusing and it shouldn’t be happening.

(I didn’t check whether it is possible to easily clone a certificate pool. If it weren’t possible, I’d prefer going back to the situation where the trust root contained unparsed file contents to the current state.)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a clone function https://pkg.go.dev/crypto/x509#CertPool.Clone
I updated to clone the trusted certs pool to a new pool and append untrusted certs to it. Could you take a look?

Copy link
Member

@saschagrunert saschagrunert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just two nits, otherwise LGTM

docs/containers-policy.json.5.md Outdated Show resolved Hide resolved
docs/containers-policy.json.5.md Outdated Show resolved Hide resolved
Signed-off-by: Qi Wang <qiwan@redhat.com>
@saschagrunert
Copy link
Member

@containers/image-maintainers can we get this merged?

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.

3 participants