Skip to content

Commit

Permalink
Add intermediate CA certificate pool for Fulcio
Browse files Browse the repository at this point in the history
This separates roots and intermediates from the TUF targets. This will
be used to configure the default intermediate certificates when none are
found. In particular, this will be used by verify-blob when fetching an
entry from Rekor.

An intermediate CA certificate will be added to the v3 TUF root.

Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>
  • Loading branch information
haydentherapper committed Apr 13, 2022
1 parent cf03ef2 commit b263a60
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 20 deletions.
62 changes: 48 additions & 14 deletions cmd/cosign/cli/fulcio/fulcioroots/fulcioroots.go
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
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")
}
}

0 comments on commit b263a60

Please sign in to comment.