Skip to content

Commit b3a0606

Browse files
committed
policy.json BYOPKI signature verification API
Signed-off-by: Qi Wang <qiwan@redhat.com>
1 parent 9e1153a commit b3a0606

14 files changed

+919
-7
lines changed

docs/containers-policy.json.5.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,14 +329,22 @@ This requirement requires an image to be signed using a sigstore signature with
329329
"oidcIssuer": "https://expected.OIDC.issuer/",
330330
"subjectEmail", "expected-signing-user@example.com",
331331
},
332+
"pki": {
333+
"caRootsPath": "/path/to/local/CARoots/file",
334+
"caRootsData": "base64-encoded-CARoots-data",
335+
"caIntermediatesPath": "/path/to/local/CAIntermediates/file",
336+
"caIntermediatesData": "base64-encoded-CAIntermediates-data",
337+
"subjectHostname": "expected-signing-hostname.example.com",
338+
"subjectEmail": "expected-signing-user@example.com"
339+
},
332340
"rekorPublicKeyPath": "/path/to/local/public/key/file",
333341
"rekorPublicKeyPaths": ["/path/to/local/public/key/one","/path/to/local/public/key/two"],
334342
"rekorPublicKeyData": "base64-encoded-public-key-data",
335343
"rekorPublicKeyDatas": ["base64-encoded-public-key-one-data","base64-encoded-public-key-two-data"],
336344
"signedIdentity": identity_requirement
337345
}
338346
```
339-
Exactly one of `keyPath`, `keyPaths`, `keyData`, `keyDatas` and `fulcio` must be present.
347+
Exactly one of `keyPath`, `keyPaths`, `keyData`, `keyDatas`, `fulcio` and `pki` must be present.
340348

341349
If `keyPath` or `keyData` is present, it contains a sigstore public key.
342350
Only signatures made by this key are accepted.
@@ -350,6 +358,11 @@ Both `oidcIssuer` and `subjectEmail` are mandatory,
350358
exactly specifying the expected identity provider,
351359
and the identity of the user obtaining the Fulcio certificate.
352360

361+
If `pki` is present, the signature must be based on a non-Fulcio X.509 certificate.
362+
One of `caRootsPath` and `caRootsData` must be specified, containing the public key of the CA.
363+
Only one of `caIntermediatesPath` and `caIntermediatesData` can be present, containing the public key of the intermediate CA.
364+
One of `subjectEmail` and `subjectHostname` must be specified, exactly specifying the expected identity provider, and the identity of the user obtaining the certificate.
365+
353366
At most one of `rekorPublicKeyPath`, `rekorPublicKeyPaths`, `rekorPublicKeyData` and `rekorPublicKeyDatas` can be present;
354367
it is mandatory if `fulcio` is specified.
355368
If a Rekor public key is specified,
@@ -407,6 +420,19 @@ selectively allow individual transports and scopes as desired.
407420
"rekorPublicKeyPath": "/path/to/rekor.pub",
408421
}
409422
],
423+
/* A Sigstore-signed repository using a certificate generated by the Bring Your Own Public Key Infrastructure (BYOPKI).*/
424+
"hostname:5000/myns/sigstore-signed-byopki": [
425+
{
426+
"type": "sigstoreSigned",
427+
"pki": {
428+
"caRootsPath": "/path/to/pki_roots_crt.pem",
429+
"caIntermediatesPath": "/path/to/pki_intermediates_crt.pem",
430+
"oidcIssuer": "https://github.com/login/oauth",
431+
"subjectHostname": "test-user.example.com"
432+
"subjectEmail": "test-user@example.com"
433+
}
434+
}
435+
],
410436
/* A sigstore-signed repository, accepts signatures by /usr/bin/cosign */
411437
"hostname:5000/myns/sigstore-signed-allows-malicious-tag-substitution": [
412438
{
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:84e2abbb0b1347753fa15b585fb2181509ee296e29eed9f4bd3fd7778d027a98","size":348},"layers":[],"annotations":{"org.opencontainers.image.base.digest":"","org.opencontainers.image.base.name":""}}
7.41 KB
Binary file not shown.

signature/fixtures/pki-cert

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
-----BEGIN CERTIFICATE-----
2+
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
34+
-----END CERTIFICATE-----

signature/fixtures/pki-chain

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
-----BEGIN CERTIFICATE-----
2+
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
33+
a+uS+G24eP8F/EA=
34+
-----END CERTIFICATE-----
35+
-----BEGIN CERTIFICATE-----
36+
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
67+
-----END CERTIFICATE-----
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
-----BEGIN CERTIFICATE-----
2+
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
33+
a+uS+G24eP8F/EA=
34+
-----END CERTIFICATE-----
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
-----BEGIN CERTIFICATE-----
2+
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
33+
-----END CERTIFICATE-----

signature/pki_cert.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package signature
2+
3+
import (
4+
"crypto"
5+
"crypto/x509"
6+
"errors"
7+
"fmt"
8+
"slices"
9+
10+
"github.com/containers/image/v5/signature/internal"
11+
"github.com/sigstore/sigstore/pkg/cryptoutils"
12+
)
13+
14+
type pkiTrustRoot struct {
15+
caRootsCertificates *x509.CertPool
16+
caIntermediateCertificates []byte
17+
subjectEmail string
18+
subjectHostname string
19+
}
20+
21+
func (p *pkiTrustRoot) validate() error {
22+
if p.subjectEmail == "" && p.subjectHostname == "" {
23+
return errors.New("Internal inconsistency: PKI use set up without subject email or subject hostname")
24+
}
25+
return nil
26+
}
27+
28+
func verifyPKI(pkiTrustRoot *pkiTrustRoot, untrustedCertificateBytes []byte, untrustedIntermediateChainBytes []byte) (crypto.PublicKey, error) {
29+
30+
untrustedLeafCerts, err := cryptoutils.UnmarshalCertificatesFromPEM(untrustedCertificateBytes)
31+
if err != nil {
32+
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("parsing leaf certificate: %v", err))
33+
}
34+
switch len(untrustedLeafCerts) {
35+
case 0:
36+
return nil, internal.NewInvalidSignatureError("no certificate found in signature certificate data")
37+
case 1:
38+
break // OK
39+
default:
40+
return nil, internal.NewInvalidSignatureError("unexpected multiple certificates present in signature certificate data")
41+
}
42+
untrustedCertificate := untrustedLeafCerts[0]
43+
44+
if pkiTrustRoot.subjectEmail != "" {
45+
if !slices.Contains(untrustedCertificate.EmailAddresses, pkiTrustRoot.subjectEmail) {
46+
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("Required email %q not found (got %q)",
47+
pkiTrustRoot.subjectEmail,
48+
untrustedCertificate.EmailAddresses))
49+
}
50+
}
51+
52+
if pkiTrustRoot.subjectHostname != "" {
53+
if err = untrustedCertificate.VerifyHostname(pkiTrustRoot.subjectHostname); err != nil {
54+
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("Unexpected subject hostname: %v", err))
55+
}
56+
}
57+
58+
untrustedIntermediatePool := x509.NewCertPool()
59+
if len(untrustedIntermediateChainBytes) > 0 {
60+
untrustedIntermediateChain, err := cryptoutils.UnmarshalCertificatesFromPEM(untrustedIntermediateChainBytes)
61+
if err != nil {
62+
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("loading certificate chain: %v", err))
63+
}
64+
if len(untrustedIntermediateChain) > 1 {
65+
for _, untrustedIntermediateCert := range untrustedIntermediateChain {
66+
if isIntermediateCA(untrustedIntermediateCert) {
67+
untrustedIntermediatePool.AddCert(untrustedIntermediateCert)
68+
}
69+
}
70+
}
71+
}
72+
73+
if len(pkiTrustRoot.caIntermediateCertificates) > 0 {
74+
trustedIntermediates, err := cryptoutils.UnmarshalCertificatesFromPEM(pkiTrustRoot.caIntermediateCertificates)
75+
if err != nil {
76+
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("loading trusted intermediate certificates: %v", err))
77+
}
78+
for _, trustedIntermediateCert := range trustedIntermediates {
79+
untrustedIntermediatePool.AddCert(trustedIntermediateCert)
80+
}
81+
}
82+
83+
if _, err := untrustedCertificate.Verify(x509.VerifyOptions{
84+
Intermediates: untrustedIntermediatePool,
85+
Roots: pkiTrustRoot.caRootsCertificates,
86+
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning},
87+
}); err != nil {
88+
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("veryfing leaf certificate failed: %v", err))
89+
}
90+
91+
return untrustedCertificate.PublicKey, nil
92+
}
93+
94+
// isIntermediateCA checks if the certificate is an intermediate CA
95+
func isIntermediateCA(cert *x509.Certificate) bool {
96+
// The certificate is an intermediate CA if:
97+
// 1. It is a CA (cert.IsCA is true).
98+
// 2. It is not self-signed (Issuer != Subject).
99+
return cert.IsCA && cert.Issuer.String() != cert.Subject.String()
100+
}

0 commit comments

Comments
 (0)