Skip to content

Commit

Permalink
Upgrade to TUF v2 client
Browse files Browse the repository at this point in the history
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 <colleenmurphy@google.com>
  • Loading branch information
cmurphy committed Aug 20, 2024
1 parent 182f64b commit 7bb6343
Show file tree
Hide file tree
Showing 15 changed files with 380 additions and 182 deletions.
2 changes: 1 addition & 1 deletion cmd/cosign/cli/verify/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (c *VerifyCommand) loadTSACertificates(ctx context.Context) (*cosign.TSACer
if c.TSACertChainPath == "" && !c.UseSignedTimestamps {
return nil, fmt.Errorf("TSA certificate chain path not provided and use-signed-timestamps not set")
}
tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath, cosign.GetTufTargets)
tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath)
if err != nil {
return nil, fmt.Errorf("unable to load TSA certificates: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/cosign/cli/verify/verify_attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (c *VerifyAttestationCommand) loadTSACertificates(ctx context.Context) (*co
if c.TSACertChainPath == "" && !c.UseSignedTimestamps {
return nil, fmt.Errorf("TSA certificate chain path not provided and use-signed-timestamps not set")
}
tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath, cosign.GetTufTargets)
tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath)
if err != nil {
return nil, fmt.Errorf("unable to load TSA certificates: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/cosign/cli/verify/verify_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (c *VerifyBlobCmd) loadTSACertificates(ctx context.Context) (*cosign.TSACer
if c.TSACertChainPath == "" && !c.UseSignedTimestamps {
return nil, fmt.Errorf("either TSA certificate chain path must be provided or use-signed-timestamps must be set")
}
tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath, cosign.GetTufTargets)
tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath)
if err != nil {
return nil, fmt.Errorf("unable to load TSA certificates: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/cosign/cli/verify/verify_blob_attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st
}

if c.TSACertChainPath != "" || c.UseSignedTimestamps {
tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath, cosign.GetTufTargets)
tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath)
if err != nil {
return fmt.Errorf("unable to load or get TSA certificates: %w", err)
}
Expand Down
45 changes: 2 additions & 43 deletions internal/pkg/cosign/fulcio/fulcioroots/fulcioroots.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,10 @@
package fulcioroots

import (
"bytes"
"crypto/x509"
"fmt"
"os"
"sync"

"github.com/sigstore/cosign/v2/pkg/cosign/env"
"github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/sigstore/sigstore/pkg/fulcioroots"
"github.com/sigstore/cosign/v2/pkg/cosign"
)

var (
Expand Down Expand Up @@ -64,41 +59,5 @@ func ReInit() error {
}

func initRoots() (*x509.CertPool, *x509.CertPool, error) {
rootPool := x509.NewCertPool()
// intermediatePool should be nil if no intermediates are found
var intermediatePool *x509.CertPool

rootEnv := env.Getenv(env.VariableSigstoreRootFile)
if rootEnv != "" {
raw, err := os.ReadFile(rootEnv)
if err != nil {
return nil, nil, fmt.Errorf("error reading root PEM file: %w", err)
}
certs, err := cryptoutils.UnmarshalCertificatesFromPEM(raw)
if err != nil {
return nil, nil, fmt.Errorf("error unmarshalling certificates: %w", err)
}
for _, cert := range certs {
// root certificates are self-signed
if bytes.Equal(cert.RawSubject, cert.RawIssuer) {
rootPool.AddCert(cert)
} else {
if intermediatePool == nil {
intermediatePool = x509.NewCertPool()
}
intermediatePool.AddCert(cert)
}
}
} else {
var err error
rootPool, err = fulcioroots.Get()
if err != nil {
return nil, nil, err
}
intermediatePool, err = fulcioroots.GetIntermediates()
if err != nil {
return nil, nil, err
}
}
return rootPool, intermediatePool, nil
return cosign.GetFulcioCerts()
}
44 changes: 21 additions & 23 deletions pkg/cosign/ctlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ import (
"context"
"errors"
"fmt"
"os"

"github.com/sigstore/cosign/v2/pkg/cosign/env"
"github.com/sigstore/sigstore/pkg/tuf"
"github.com/sigstore/sigstore-go/pkg/root"
)

// This is the CT log public key target name
Expand All @@ -37,32 +36,31 @@ func GetCTLogPubs(ctx context.Context) (*TrustedTransparencyLogPubKeys, error) {
altCTLogPub := env.Getenv(env.VariableSigstoreCTLogPublicKeyFile)

if altCTLogPub != "" {
raw, err := os.ReadFile(altCTLogPub)
if err != nil {
return nil, fmt.Errorf("error reading alternate CTLog public key file: %w", err)
}
if err := publicKeys.AddTransparencyLogPubKey(raw, tuf.Active); err != nil {
return nil, fmt.Errorf("AddCTLogPubKey: %w", err)
}
} else {
tufClient, err := tuf.NewFromEnv(ctx)
if err != nil {
return nil, err
}
targets, err := tufClient.GetTargetsByMeta(tuf.CTFE, []string{ctPublicKeyStr})
if err != nil {
return nil, err
}
for _, t := range targets {
if err := publicKeys.AddTransparencyLogPubKey(t.Target, t.Status); err != nil {
return nil, fmt.Errorf("AddCTLogPubKey: %w", err)
}
return addKeyFromFile(&publicKeys, altCTLogPub, "CT log public key")
}

opts, err := setTUFOpts()
if err != nil {
return nil, err
}

// Try getting keys from trusted_root.json
trustedRoot, _ := root.NewLiveTrustedRoot(opts)
if trustedRoot == nil {
// The TUF repository didn't have a trusted_root.json, try getting the individual target
return addKeyFromTUF(&publicKeys, opts, ctPublicKeyStr, "CT log public key")
}

ctlogs := trustedRoot.CTLogs()
for _, ct := range ctlogs {
validity := checkValidityPeriod(ct.ValidityPeriodStart, ct.ValidityPeriodEnd)
if err := publicKeys.AddTransparencyLogPubKey(ct.PublicKey, validity); err != nil {
return nil, fmt.Errorf("error adding CT log public key: %w", err)
}
}

if len(publicKeys.Keys) == 0 {
return nil, errors.New("none of the CTLog public keys have been found")
}

return &publicKeys, nil
}
138 changes: 138 additions & 0 deletions pkg/cosign/fulcio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright 2024 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cosign

import (
"bytes"
"crypto/x509"
"fmt"
"os"

"github.com/sigstore/cosign/v2/pkg/cosign/env"
"github.com/sigstore/sigstore-go/pkg/root"
"github.com/sigstore/sigstore-go/pkg/tuf"
"github.com/sigstore/sigstore/pkg/cryptoutils"
)

const (
// This is the root in the fulcio project.
fulcioTargetStr = `fulcio.crt.pem`
// This is the v1 migrated root.
fulcioV1TargetStr = `fulcio_v1.crt.pem`
// This is the untrusted v1 intermediate CA certificate, used or chain building.
fulcioV1IntermediateTargetStr = `fulcio_intermediate_v1.crt.pem`
)

func GetFulcioCerts() (*x509.CertPool, *x509.CertPool, error) {
rootEnv := env.Getenv(env.VariableSigstoreRootFile)

if rootEnv != "" {
return getFulcioCertsFromFile(rootEnv)
}

opts, err := setTUFOpts()
if err != nil {
return nil, nil, err
}

trustedRoot, _ := root.NewLiveTrustedRoot(opts)
if trustedRoot == nil {
return getFulcioCertsFromTUF(opts)
}
cas := trustedRoot.FulcioCertificateAuthorities()
if len(cas) < 1 {
return nil, nil, fmt.Errorf("could not find fulcio certificate authorities")
}
rootPool := x509.NewCertPool()
var intermediatePool *x509.CertPool
for _, ca := range cas {
rootPool.AddCert(ca.Root)
for _, i := range ca.Intermediates {
if intermediatePool == nil {
intermediatePool = x509.NewCertPool()
}
intermediatePool.AddCert(i)
}
}
return rootPool, intermediatePool, nil
}

func getFulcioCertsFromFile(path string) (*x509.CertPool, *x509.CertPool, error) {
rootPool := x509.NewCertPool()
// intermediatePool should be nil if no intermediates are found
var intermediatePool *x509.CertPool
raw, err := os.ReadFile(path)
if err != nil {
return nil, nil, fmt.Errorf("error reading root PEM file: %w", err)
}
certs, err := cryptoutils.UnmarshalCertificatesFromPEM(raw)
if err != nil {
return nil, nil, fmt.Errorf("error unmarshalling certificates: %w", err)
}
for _, cert := range certs {
// root certificates are self-signed
if bytes.Equal(cert.RawSubject, cert.RawIssuer) {
rootPool.AddCert(cert)
} else {
if intermediatePool == nil {
intermediatePool = x509.NewCertPool()
}
intermediatePool.AddCert(cert)
}
}
return rootPool, intermediatePool, nil
}

func getFulcioCertsFromTUF(opts *tuf.Options) (*x509.CertPool, *x509.CertPool, error) {
tufClient, err := tuf.New(opts)
if err != nil {
return nil, nil, fmt.Errorf("error creating TUF client: %w", err)
}
rootPool := x509.NewCertPool()
fulcioCertBytes, _ := tufClient.GetTarget(fulcioTargetStr)
fulcioV1CertBytes, _ := tufClient.GetTarget(fulcioV1TargetStr)
if len(fulcioCertBytes) > 0 {
fulcioCert, err := cryptoutils.UnmarshalCertificatesFromPEM(fulcioCertBytes)
if err != nil {
return nil, nil, fmt.Errorf("error unmarshalling fulcio cert: %w", err)
}
for _, c := range fulcioCert {
rootPool.AddCert(c)
}
}
if len(fulcioV1CertBytes) > 0 {
fulcioV1Cert, err := cryptoutils.UnmarshalCertificatesFromPEM(fulcioV1CertBytes)
if err != nil {
return nil, nil, fmt.Errorf("error unmarshalling fulcio v1 cert: %w", err)
}
for _, c := range fulcioV1Cert {
rootPool.AddCert(c)
}
}

var intermediatePool *x509.CertPool
fulcioIntermediateBytes, _ := tufClient.GetTarget(fulcioV1IntermediateTargetStr)
if len(fulcioIntermediateBytes) == 0 {
fulcioIntermediate, err := cryptoutils.UnmarshalCertificatesFromPEM(fulcioIntermediateBytes)
if err != nil {
return nil, nil, fmt.Errorf("error unmarshalling fulcio intermediate cert: %w", err)
}
intermediatePool = x509.NewCertPool()
for _, c := range fulcioIntermediate {
intermediatePool.AddCert(c)
}
}
return rootPool, intermediatePool, nil
}
Loading

0 comments on commit 7bb6343

Please sign in to comment.