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 intermediate CA certificate pool for Fulcio #1749

Merged
merged 1 commit into from
Apr 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/cosign/cli/fulcio/fulcio.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ func GetRoots() *x509.CertPool {
return fulcioroots.Get()
}

func GetIntermediates() *x509.CertPool {
return fulcioroots.GetIntermediates()
}

func NewClient(fulcioURL string) (api.Client, error) {
fulcioServer, err := url.Parse(fulcioURL)
if err != nil {
Expand Down
62 changes: 48 additions & 14 deletions cmd/cosign/cli/fulcio/fulcioroots/fulcioroots.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,21 @@
package fulcioroots

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

"github.com/pkg/errors"
"github.com/sigstore/cosign/pkg/cosign/tuf"
"github.com/sigstore/sigstore/pkg/cryptoutils"
)

var (
rootsOnce sync.Once
roots *x509.CertPool
rootsOnce sync.Once
roots *x509.CertPool
intermediates *x509.CertPool
)

// This is the root in the fulcio project.
Expand All @@ -43,45 +46,76 @@ const (
func Get() *x509.CertPool {
rootsOnce.Do(func() {
var err error
roots, err = initRoots()
roots, intermediates, err = initRoots()
if err != nil {
panic(err)
}
})
return roots
}

func initRoots() (*x509.CertPool, error) {
cp := x509.NewCertPool()
func GetIntermediates() *x509.CertPool {
rootsOnce.Do(func() {
var err error
roots, intermediates, err = initRoots()
if err != nil {
panic(err)
}
})
return intermediates
}

func initRoots() (*x509.CertPool, *x509.CertPool, error) {
rootPool := x509.NewCertPool()
intermediatePool := x509.NewCertPool()

rootEnv := os.Getenv(altRoot)
if rootEnv != "" {
raw, err := os.ReadFile(rootEnv)
if err != nil {
return nil, errors.Wrap(err, "error reading root PEM file")
return nil, nil, errors.Wrap(err, "error reading root PEM file")
}
certs, err := cryptoutils.UnmarshalCertificatesFromPEM(raw)
if err != nil {
return nil, nil, errors.Wrap(err, "error unmarshalling certificates")
}
if !cp.AppendCertsFromPEM(raw) {
return nil, errors.New("error creating root cert pool")
for _, cert := range certs {
// root certificates are self-signed
if bytes.Equal(cert.RawSubject, cert.RawIssuer) {
rootPool.AddCert(cert)
} else {
intermediatePool.AddCert(cert)
}
}
} else {
tufClient, err := tuf.NewFromEnv(context.Background())
if err != nil {
return nil, errors.Wrap(err, "initializing tuf")
return nil, nil, errors.Wrap(err, "initializing tuf")
}
defer tufClient.Close()
// Retrieve from the embedded or cached TUF root. If expired, a network
// call is made to update the root.
targets, err := tufClient.GetTargetsByMeta(tuf.Fulcio, []string{fulcioTargetStr, fulcioV1TargetStr})
if err != nil {
return nil, errors.New("error getting targets")
return nil, nil, errors.New("error getting targets")
}
if len(targets) == 0 {
return nil, errors.New("none of the Fulcio roots have been found")
return nil, nil, errors.New("none of the Fulcio roots have been found")
}
for _, t := range targets {
if !cp.AppendCertsFromPEM(t.Target) {
return nil, errors.New("error creating root cert pool")
certs, err := cryptoutils.UnmarshalCertificatesFromPEM(t.Target)
if err != nil {
return nil, nil, errors.Wrap(err, "error unmarshalling certificates")
}
for _, cert := range certs {
// root certificates are self-signed
if bytes.Equal(cert.RawSubject, cert.RawIssuer) {
rootPool.AddCert(cert)
} else {
intermediatePool.AddCert(cert)
}
}
}
}
return cp, nil
return rootPool, intermediatePool, nil
}
24 changes: 18 additions & 6 deletions cmd/cosign/cli/fulcio/fulcioroots/fulcioroots_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,35 @@ import (
)

func TestGetFulcioRoots(t *testing.T) {
rootCert, _, _ := test.GenerateRootCa()
pemCert, _ := cryptoutils.MarshalCertificateToPEM(rootCert)
rootCert, rootPriv, _ := test.GenerateRootCa()
rootPemCert, _ := cryptoutils.MarshalCertificateToPEM(rootCert)
subCert, _, _ := test.GenerateSubordinateCa(rootCert, rootPriv)
subPemCert, _ := cryptoutils.MarshalCertificateToPEM(subCert)

var chain []byte
chain = append(chain, subPemCert...)
chain = append(chain, rootPemCert...)

tmpCertFile, err := os.CreateTemp(t.TempDir(), "cosign_fulcio_root_*.cert")
if err != nil {
t.Fatalf("failed to create temp cert file: %v", err)
}
defer tmpCertFile.Close()
if _, err := tmpCertFile.Write(pemCert); err != nil {
if _, err := tmpCertFile.Write(chain); err != nil {
t.Fatalf("failed to write cert file: %v", err)
}
os.Setenv("SIGSTORE_ROOT_FILE", tmpCertFile.Name())
defer os.Unsetenv("SIGSTORE_ROOT_FILE")

certPool := Get()
rootCertPool := Get()
// ignore deprecation error because certificates do not contain from SystemCertPool
if len(rootCertPool.Subjects()) != 1 { // nolint:staticcheck
t.Errorf("expected 1 root certificate, got 0")
}

subCertPool := GetIntermediates()
// ignore deprecation error because certificates do not contain from SystemCertPool
if len(certPool.Subjects()) == 0 { // nolint:staticcheck
t.Errorf("expected 1 or more certificates, got 0")
if len(subCertPool.Subjects()) != 1 { // nolint:staticcheck
t.Errorf("expected 1 intermediate certificate, got 0")
}
}
7 changes: 4 additions & 3 deletions cmd/cosign/cli/verify/verify_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,10 @@ func verifySigByUUID(ctx context.Context, ko sign.KeyOpts, rClient *client.Rekor
}

co := &cosign.CheckOpts{
RootCerts: fulcio.GetRoots(),
CertEmail: certEmail,
CertOidcIssuer: certOidcIssuer,
RootCerts: fulcio.GetRoots(),
IntermediateCerts: fulcio.GetIntermediates(),
CertEmail: certEmail,
CertOidcIssuer: certOidcIssuer,
}
cert := certs[0]
verifier, err := cosign.ValidateAndUnpackCert(cert, co)
Expand Down