Skip to content

Commit 00b4edb

Browse files
committed
Upgrade to TUF v2 client
Swap the use of the go-tuf v0.7.0 client from sigstore/sigstore to the v2.0.0 client from sigstore/sigstore-go. Sigstore-go provides a way to check for a trusted root and automatically use it if available, but can also fetch individual targets as needed if the provided TUF mirror does not supply a trusted_root.json. This change is intended to be backwards compatible and transparent. TODO: - e2e tests - deprecate `cosign initialize` Signed-off-by: Colleen Murphy <[email protected]>
1 parent 182f64b commit 00b4edb

20 files changed

+432
-213
lines changed

.github/workflows/kind-verify-attestation.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,26 +106,41 @@ jobs:
106106
REPOSITORY=${PWD}/repository
107107
./cosign initialize --root ${ROOT} --mirror file://${REPOSITORY}
108108
109+
- name: Set up root.json
110+
run: |
111+
[ -f $(pwd)/repository/1.root.json ] && cp $(pwd)/repository/1.root.json root.json
112+
[ -f root.json ] || ( echo "Failed to set up trust root ; exit 1 )
113+
109114
- name: Sign demoimage with cosign
110115
run: |
116+
TUF_MIRROR=$(kubectl -n tuf-system get ksvc tuf -ojsonpath='{.status.url}')
117+
TUF_ROOT_JSON=root.json
111118
./cosign sign --rekor-url ${{ env.REKOR_URL }} --fulcio-url ${{ env.FULCIO_URL }} --yes --allow-insecure-registry ${{ env.demoimage }} --identity-token ${{ env.OIDC_TOKEN }}
112119
113120
- name: Create attestation for it
114121
run: |
115122
echo -n 'foobar e2e test' > ./predicate-file
123+
TUF_MIRROR=$(kubectl -n tuf-system get ksvc tuf -ojsonpath='{.status.url}')
124+
TUF_ROOT_JSON=root.json
116125
./cosign attest --predicate ./predicate-file --fulcio-url ${{ env.FULCIO_URL }} --rekor-url ${{ env.REKOR_URL }} --allow-insecure-registry --yes ${{ env.demoimage }} --identity-token ${{ env.OIDC_TOKEN }}
117126
118127
- name: Sign a blob
119128
run: |
129+
TUF_MIRROR=$(kubectl -n tuf-system get ksvc tuf -ojsonpath='{.status.url}')
130+
TUF_ROOT_JSON=root.json
120131
./cosign sign-blob README.md --fulcio-url ${{ env.FULCIO_URL }} --rekor-url ${{ env.REKOR_URL }} --output-certificate cert.pem --output-signature sig --yes --identity-token ${{ env.OIDC_TOKEN }}
121132
122133
- name: Verify with cosign
123134
run: |
135+
TUF_MIRROR=$(kubectl -n tuf-system get ksvc tuf -ojsonpath='{.status.url}')
136+
TUF_ROOT_JSON=root.json
124137
./cosign verify --rekor-url ${{ env.REKOR_URL }} --allow-insecure-registry ${{ env.demoimage }} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local"
125138
126139
- name: Verify custom attestation with cosign, works
127140
run: |
128141
echo '::group:: test custom verify-attestation success'
142+
TUF_MIRROR=$(kubectl -n tuf-system get ksvc tuf -ojsonpath='{.status.url}')
143+
TUF_ROOT_JSON=root.json
129144
if ! ./cosign verify-attestation --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" --policy ./test/testdata/policies/cue-works.cue --rekor-url ${{ env.REKOR_URL }} --allow-insecure-registry ${{ env.demoimage }} ; then
130145
echo Failed to verify attestation with a valid policy
131146
exit 1
@@ -137,6 +152,8 @@ jobs:
137152
- name: Verify custom attestation with cosign, fails
138153
run: |
139154
echo '::group:: test custom verify-attestation success'
155+
TUF_MIRROR=$(kubectl -n tuf-system get ksvc tuf -ojsonpath='{.status.url}')
156+
TUF_ROOT_JSON=root.json
140157
if ./cosign verify-attestation --policy ./test/testdata/policies/cue-fails.cue --rekor-url ${{ env.REKOR_URL }} --allow-insecure-registry ${{ env.demoimage }} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" ; then
141158
echo custom verify-attestation succeeded with cue policy that should not work
142159
exit 1
@@ -147,6 +164,8 @@ jobs:
147164
148165
- name: Verify a blob
149166
run: |
167+
TUF_MIRROR=$(kubectl -n tuf-system get ksvc tuf -ojsonpath='{.status.url}')
168+
TUF_ROOT_JSON=root.json
150169
./cosign verify-blob README.md --rekor-url ${{ env.REKOR_URL }} --certificate ./cert.pem --signature sig --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local"
151170
152171
- name: Collect diagnostics
@@ -155,11 +174,15 @@ jobs:
155174

156175
- name: Create vuln attestation for it
157176
run: |
177+
TUF_MIRROR=$(kubectl -n tuf-system get ksvc tuf -ojsonpath='{.status.url}')
178+
TUF_ROOT_JSON=root.json
158179
./cosign attest --predicate ./test/testdata/attestations/vuln-predicate.json --type vuln --fulcio-url ${{ env.FULCIO_URL }} --rekor-url ${{ env.REKOR_URL }} --allow-insecure-registry --yes ${{ env.demoimage }} --identity-token ${{ env.OIDC_TOKEN }}
159180
160181
- name: Verify vuln attestation with cosign, works
161182
run: |
162183
echo '::group:: test vuln verify-attestation success'
184+
TUF_MIRROR=$(kubectl -n tuf-system get ksvc tuf -ojsonpath='{.status.url}')
185+
TUF_ROOT_JSON=root.json
163186
if ! ./cosign verify-attestation --type vuln --policy ./test/testdata/policies/cue-vuln-works.cue --rekor-url ${{ env.REKOR_URL }} --allow-insecure-registry ${{ env.demoimage }} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" ; then
164187
echo Failed to verify attestation with a valid policy
165188
exit 1
@@ -171,6 +194,8 @@ jobs:
171194
- name: Verify vuln attestation with cosign, fails
172195
run: |
173196
echo '::group:: test vuln verify-attestation success'
197+
TUF_MIRROR=$(kubectl -n tuf-system get ksvc tuf -ojsonpath='{.status.url}')
198+
TUF_ROOT_JSON=root.json
174199
if ./cosign verify-attestation --type vuln --policy ./test/testdata/policies/cue-vuln-fails.cue --rekor-url ${{ env.REKOR_URL }} --allow-insecure-registry ${{ env.demoimage }} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" ; then
175200
echo verify-attestation succeeded with cue policy that should not work
176201
exit 1

cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func NewSigner(ctx context.Context, ko options.KeyOpts, signer signature.SignerV
3333
}
3434

3535
// Grab the PublicKeys for the CTFE, either from tuf or env.
36-
pubKeys, err := cosign.GetCTLogPubs(ctx)
36+
pubKeys, err := cosign.GetCTLogPubs()
3737
if err != nil {
3838
return nil, fmt.Errorf("getting CTFE public keys: %w", err)
3939
}

cmd/cosign/cli/sign/sign.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ func signerFromKeyRef(ctx context.Context, certPath, certChainPath, keyRef strin
505505
return nil, err
506506
}
507507
if contains {
508-
pubKeys, err := cosign.GetCTLogPubs(ctx)
508+
pubKeys, err := cosign.GetCTLogPubs()
509509
if err != nil {
510510
return nil, fmt.Errorf("getting CTLog public keys: %w", err)
511511
}

cmd/cosign/cli/verify/verify.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,11 @@ type VerifyCommand struct {
8484
ExperimentalOCI11 bool
8585
}
8686

87-
func (c *VerifyCommand) loadTSACertificates(ctx context.Context) (*cosign.TSACertificates, error) {
87+
func (c *VerifyCommand) loadTSACertificates() (*cosign.TSACertificates, error) {
8888
if c.TSACertChainPath == "" && !c.UseSignedTimestamps {
8989
return nil, fmt.Errorf("TSA certificate chain path not provided and use-signed-timestamps not set")
9090
}
91-
tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath, cosign.GetTufTargets)
91+
tsaCertificates, err := cosign.GetTSACerts(c.TSACertChainPath)
9292
if err != nil {
9393
return nil, fmt.Errorf("unable to load TSA certificates: %w", err)
9494
}
@@ -150,7 +150,7 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
150150
}
151151

152152
if c.TSACertChainPath != "" || c.UseSignedTimestamps {
153-
tsaCertificates, err := c.loadTSACertificates(ctx)
153+
tsaCertificates, err := c.loadTSACertificates()
154154
if err != nil {
155155
return fmt.Errorf("unable to load TSA certificates: %w", err)
156156
}
@@ -169,7 +169,7 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
169169
}
170170
// This performs an online fetch of the Rekor public keys, but this is needed
171171
// for verifying tlog entries (both online and offline).
172-
co.RekorPubKeys, err = cosign.GetRekorPubs(ctx)
172+
co.RekorPubKeys, err = cosign.GetRekorPubs()
173173
if err != nil {
174174
return fmt.Errorf("getting Rekor public keys: %w", err)
175175
}
@@ -185,7 +185,7 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
185185

186186
// Ignore Signed Certificate Timestamp if the flag is set or a key is provided
187187
if shouldVerifySCT(c.IgnoreSCT, c.KeyRef, c.Sk) {
188-
co.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx)
188+
co.CTLogPubKeys, err = cosign.GetCTLogPubs()
189189
if err != nil {
190190
return fmt.Errorf("getting ctlog public keys: %w", err)
191191
}

cmd/cosign/cli/verify/verify_attestation.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,11 @@ type VerifyAttestationCommand struct {
7272
UseSignedTimestamps bool
7373
}
7474

75-
func (c *VerifyAttestationCommand) loadTSACertificates(ctx context.Context) (*cosign.TSACertificates, error) {
75+
func (c *VerifyAttestationCommand) loadTSACertificates() (*cosign.TSACertificates, error) {
7676
if c.TSACertChainPath == "" && !c.UseSignedTimestamps {
7777
return nil, fmt.Errorf("TSA certificate chain path not provided and use-signed-timestamps not set")
7878
}
79-
tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath, cosign.GetTufTargets)
79+
tsaCertificates, err := cosign.GetTSACerts(c.TSACertChainPath)
8080
if err != nil {
8181
return nil, fmt.Errorf("unable to load TSA certificates: %w", err)
8282
}
@@ -125,14 +125,14 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e
125125
}
126126
// Ignore Signed Certificate Timestamp if the flag is set or a key is provided
127127
if shouldVerifySCT(c.IgnoreSCT, c.KeyRef, c.Sk) {
128-
co.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx)
128+
co.CTLogPubKeys, err = cosign.GetCTLogPubs()
129129
if err != nil {
130130
return fmt.Errorf("getting ctlog public keys: %w", err)
131131
}
132132
}
133133

134134
if c.TSACertChainPath != "" || c.UseSignedTimestamps {
135-
tsaCertificates, err := c.loadTSACertificates(ctx)
135+
tsaCertificates, err := c.loadTSACertificates()
136136
if err != nil {
137137
return fmt.Errorf("unable to load TSA certificates: %w", err)
138138
}
@@ -151,7 +151,7 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e
151151
}
152152
// This performs an online fetch of the Rekor public keys, but this is needed
153153
// for verifying tlog entries (both online and offline).
154-
co.RekorPubKeys, err = cosign.GetRekorPubs(ctx)
154+
co.RekorPubKeys, err = cosign.GetRekorPubs()
155155
if err != nil {
156156
return fmt.Errorf("getting Rekor public keys: %w", err)
157157
}

cmd/cosign/cli/verify/verify_blob.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ type VerifyBlobCmd struct {
6969
IgnoreTlog bool
7070
}
7171

72-
func (c *VerifyBlobCmd) loadTSACertificates(ctx context.Context) (*cosign.TSACertificates, error) {
72+
func (c *VerifyBlobCmd) loadTSACertificates() (*cosign.TSACertificates, error) {
7373
if c.TSACertChainPath == "" && !c.UseSignedTimestamps {
7474
return nil, fmt.Errorf("either TSA certificate chain path must be provided or use-signed-timestamps must be set")
7575
}
76-
tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath, cosign.GetTufTargets)
76+
tsaCertificates, err := cosign.GetTSACerts(c.TSACertChainPath)
7777
if err != nil {
7878
return nil, fmt.Errorf("unable to load TSA certificates: %w", err)
7979
}
@@ -142,7 +142,7 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error {
142142
return fmt.Errorf("either TSA certificate chain path must be provided or use-signed-timestamps must be set when using RFC3161 timestamp path")
143143
}
144144
if c.TSACertChainPath != "" || c.UseSignedTimestamps {
145-
tsaCertificates, err := c.loadTSACertificates(ctx)
145+
tsaCertificates, err := c.loadTSACertificates()
146146
if err != nil {
147147
return err
148148
}
@@ -161,7 +161,7 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error {
161161
}
162162
// This performs an online fetch of the Rekor public keys, but this is needed
163163
// for verifying tlog entries (both online and offline).
164-
co.RekorPubKeys, err = cosign.GetRekorPubs(ctx)
164+
co.RekorPubKeys, err = cosign.GetRekorPubs()
165165
if err != nil {
166166
return fmt.Errorf("getting Rekor public keys: %w", err)
167167
}
@@ -294,7 +294,7 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error {
294294

295295
// Ignore Signed Certificate Timestamp if the flag is set or a key is provided
296296
if shouldVerifySCT(c.IgnoreSCT, c.KeyRef, c.Sk) {
297-
co.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx)
297+
co.CTLogPubKeys, err = cosign.GetCTLogPubs()
298298
if err != nil {
299299
return fmt.Errorf("getting ctlog public keys: %w", err)
300300
}

cmd/cosign/cli/verify/verify_blob_attestation.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st
160160
}
161161

162162
if c.TSACertChainPath != "" || c.UseSignedTimestamps {
163-
tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath, cosign.GetTufTargets)
163+
tsaCertificates, err := cosign.GetTSACerts(c.TSACertChainPath)
164164
if err != nil {
165165
return fmt.Errorf("unable to load or get TSA certificates: %w", err)
166166
}
@@ -179,7 +179,7 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st
179179
}
180180
// This performs an online fetch of the Rekor public keys, but this is needed
181181
// for verifying tlog entries (both online and offline).
182-
co.RekorPubKeys, err = cosign.GetRekorPubs(ctx)
182+
co.RekorPubKeys, err = cosign.GetRekorPubs()
183183
if err != nil {
184184
return fmt.Errorf("getting Rekor public keys: %w", err)
185185
}
@@ -192,7 +192,7 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st
192192

193193
// Ignore Signed Certificate Timestamp if the flag is set or a key is provided
194194
if shouldVerifySCT(c.IgnoreSCT, c.KeyRef, c.Sk) {
195-
co.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx)
195+
co.CTLogPubKeys, err = cosign.GetCTLogPubs()
196196
if err != nil {
197197
return fmt.Errorf("getting ctlog public keys: %w", err)
198198
}

internal/pkg/cosign/fulcio/fulcioroots/fulcioroots.go

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,10 @@
1616
package fulcioroots
1717

1818
import (
19-
"bytes"
2019
"crypto/x509"
21-
"fmt"
22-
"os"
2320
"sync"
2421

25-
"github.com/sigstore/cosign/v2/pkg/cosign/env"
26-
"github.com/sigstore/sigstore/pkg/cryptoutils"
27-
"github.com/sigstore/sigstore/pkg/fulcioroots"
22+
"github.com/sigstore/cosign/v2/pkg/cosign"
2823
)
2924

3025
var (
@@ -64,41 +59,5 @@ func ReInit() error {
6459
}
6560

6661
func initRoots() (*x509.CertPool, *x509.CertPool, error) {
67-
rootPool := x509.NewCertPool()
68-
// intermediatePool should be nil if no intermediates are found
69-
var intermediatePool *x509.CertPool
70-
71-
rootEnv := env.Getenv(env.VariableSigstoreRootFile)
72-
if rootEnv != "" {
73-
raw, err := os.ReadFile(rootEnv)
74-
if err != nil {
75-
return nil, nil, fmt.Errorf("error reading root PEM file: %w", err)
76-
}
77-
certs, err := cryptoutils.UnmarshalCertificatesFromPEM(raw)
78-
if err != nil {
79-
return nil, nil, fmt.Errorf("error unmarshalling certificates: %w", err)
80-
}
81-
for _, cert := range certs {
82-
// root certificates are self-signed
83-
if bytes.Equal(cert.RawSubject, cert.RawIssuer) {
84-
rootPool.AddCert(cert)
85-
} else {
86-
if intermediatePool == nil {
87-
intermediatePool = x509.NewCertPool()
88-
}
89-
intermediatePool.AddCert(cert)
90-
}
91-
}
92-
} else {
93-
var err error
94-
rootPool, err = fulcioroots.Get()
95-
if err != nil {
96-
return nil, nil, err
97-
}
98-
intermediatePool, err = fulcioroots.GetIntermediates()
99-
if err != nil {
100-
return nil, nil, err
101-
}
102-
}
103-
return rootPool, intermediatePool, nil
62+
return cosign.GetFulcioCerts()
10463
}

pkg/cosign/ctlog.go

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,11 @@
1515
package cosign
1616

1717
import (
18-
"context"
1918
"errors"
2019
"fmt"
21-
"os"
2220

2321
"github.com/sigstore/cosign/v2/pkg/cosign/env"
24-
"github.com/sigstore/sigstore/pkg/tuf"
22+
"github.com/sigstore/sigstore-go/pkg/root"
2523
)
2624

2725
// This is the CT log public key target name
@@ -32,37 +30,36 @@ var ctPublicKeyStr = `ctfe.pub`
3230
// By default the public keys comes from TUF, but you can override this for test
3331
// purposes by using an env variable `SIGSTORE_CT_LOG_PUBLIC_KEY_FILE`. If using
3432
// an alternate, the file can be PEM, or DER format.
35-
func GetCTLogPubs(ctx context.Context) (*TrustedTransparencyLogPubKeys, error) {
33+
func GetCTLogPubs() (*TrustedTransparencyLogPubKeys, error) {
3634
publicKeys := NewTrustedTransparencyLogPubKeys()
3735
altCTLogPub := env.Getenv(env.VariableSigstoreCTLogPublicKeyFile)
3836

3937
if altCTLogPub != "" {
40-
raw, err := os.ReadFile(altCTLogPub)
41-
if err != nil {
42-
return nil, fmt.Errorf("error reading alternate CTLog public key file: %w", err)
43-
}
44-
if err := publicKeys.AddTransparencyLogPubKey(raw, tuf.Active); err != nil {
45-
return nil, fmt.Errorf("AddCTLogPubKey: %w", err)
46-
}
47-
} else {
48-
tufClient, err := tuf.NewFromEnv(ctx)
49-
if err != nil {
50-
return nil, err
51-
}
52-
targets, err := tufClient.GetTargetsByMeta(tuf.CTFE, []string{ctPublicKeyStr})
53-
if err != nil {
54-
return nil, err
55-
}
56-
for _, t := range targets {
57-
if err := publicKeys.AddTransparencyLogPubKey(t.Target, t.Status); err != nil {
58-
return nil, fmt.Errorf("AddCTLogPubKey: %w", err)
59-
}
38+
return addKeyFromFile(&publicKeys, altCTLogPub, "CT log public key")
39+
}
40+
41+
opts, err := setTUFOpts()
42+
if err != nil {
43+
return nil, err
44+
}
45+
46+
// Try getting keys from trusted_root.json
47+
trustedRoot, _ := root.NewLiveTrustedRoot(opts)
48+
if trustedRoot == nil {
49+
// The TUF repository didn't have a trusted_root.json, try getting the individual target
50+
return addKeyFromTUF(&publicKeys, opts, ctPublicKeyStr, "CT log public key")
51+
}
52+
53+
ctlogs := trustedRoot.CTLogs()
54+
for _, ct := range ctlogs {
55+
validity := checkValidityPeriod(ct.ValidityPeriodStart, ct.ValidityPeriodEnd)
56+
if err := publicKeys.AddTransparencyLogPubKey(ct.PublicKey, validity); err != nil {
57+
return nil, fmt.Errorf("error adding CT log public key: %w", err)
6058
}
6159
}
6260

6361
if len(publicKeys.Keys) == 0 {
6462
return nil, errors.New("none of the CTLog public keys have been found")
6563
}
66-
6764
return &publicKeys, nil
6865
}

0 commit comments

Comments
 (0)