Skip to content

Commit

Permalink
Add the ability to supply multiple verification material
Browse files Browse the repository at this point in the history
Also add ability to specify validity start time for keys

Signed-off-by: Zach Steindler <[email protected]>
  • Loading branch information
steiza committed Oct 8, 2024
1 parent cab9148 commit f705836
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 83 deletions.
46 changes: 19 additions & 27 deletions cmd/cosign/cli/options/trustedroot.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,51 +20,43 @@ import (
)

type TrustedRootCreateOptions struct {
CAIntermediates string
CARoots string
CertChain string
CtfeKeyPath string
RekorKeyPath string
CertChain []string
CtfeKeyPath []string
CtfeStartTime []string
Out string
TSACertChainPath string
RekorKeyPath []string
RekorStartTime []string
TSACertChainPath []string
}

var _ Interface = (*TrustedRootCreateOptions)(nil)

func (o *TrustedRootCreateOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(&o.CAIntermediates, "ca-intermediates", "",
"path to a file of intermediate CA certificates in PEM format which will be needed "+
"when building the certificate chains for the signing certificate. "+
"The flag is optional and must be used together with --ca-roots, conflicts with "+
"--certificate-chain.")
_ = cmd.Flags().SetAnnotation("ca-intermediates", cobra.BashCompFilenameExt, []string{"cert"})

cmd.Flags().StringVar(&o.CARoots, "ca-roots", "",
"path to a bundle file of CA certificates in PEM format which will be needed "+
"when building the certificate chains for the signing certificate. Conflicts with --certificate-chain.")
_ = cmd.Flags().SetAnnotation("ca-roots", cobra.BashCompFilenameExt, []string{"cert"})

cmd.Flags().StringVar(&o.CertChain, "certificate-chain", "",
cmd.Flags().StringArrayVar(&o.CertChain, "certificate-chain", nil,
"path to a list of CA certificates in PEM format which will be needed "+
"when building the certificate chain for the signing certificate. "+
"Must start with the parent intermediate CA certificate of the "+
"signing certificate and end with the root certificate. Conflicts with --ca-roots and --ca-intermediates.")
_ = cmd.Flags().SetAnnotation("certificate-chain", cobra.BashCompFilenameExt, []string{"cert"})

cmd.MarkFlagsMutuallyExclusive("ca-roots", "certificate-chain")
cmd.MarkFlagsMutuallyExclusive("ca-intermediates", "certificate-chain")

cmd.Flags().StringVar(&o.CtfeKeyPath, "ctfe-key", "",
cmd.Flags().StringArrayVar(&o.CtfeKeyPath, "ctfe-key", nil,
"path to a PEM-encoded public key used by certificate authority for "+
"certificate transparency log.")

cmd.Flags().StringVar(&o.RekorKeyPath, "rekor-key", "",
cmd.Flags().StringArrayVar(&o.CtfeStartTime, "ctfe-start-time", nil,
"RFC 3339 string describing validity start time for key use by "+
"certificate transparency log.")

cmd.Flags().StringVar(&o.Out, "out", "", "path to output trusted root")

cmd.Flags().StringArrayVar(&o.RekorKeyPath, "rekor-key", nil,
"path to a PEM-encoded public key used by transparency log like Rekor.")

cmd.Flags().StringVar(&o.Out, "out", "",
"path to output trusted root")
cmd.Flags().StringArrayVar(&o.RekorStartTime, "rekor-start-time", nil,
"RFC 3339 string describing validity start time for key use by "+
"transparency log like Rekor.")

cmd.Flags().StringVar(&o.TSACertChainPath, "timestamp-certificate-chain", "",
cmd.Flags().StringArrayVar(&o.TSACertChainPath, "timestamp-certificate-chain", nil,
"path to PEM-encoded certificate chain file for the RFC3161 timestamp authority. Must contain the root CA certificate. "+
"Optionally may contain intermediate CA certificates")
}
4 changes: 2 additions & 2 deletions cmd/cosign/cli/trustedroot.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ func trustedRootCreate() *cobra.Command {
Long: "Create a Sigstore protobuf trusted root by supplying verification material",
RunE: func(cmd *cobra.Command, _ []string) error {
trCreateCmd := &trustedroot.CreateCmd{
CAIntermediates: o.CAIntermediates,
CARoots: o.CARoots,
CertChain: o.CertChain,
CtfeKeyPath: o.CtfeKeyPath,
CtfeStartTime: o.CtfeStartTime,
Out: o.Out,
RekorKeyPath: o.RekorKeyPath,
RekorStartTime: o.RekorStartTime,
TSACertChainPath: o.TSACertChainPath,
}

Expand Down
83 changes: 39 additions & 44 deletions cmd/cosign/cli/trustedroot/trustedroot.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"encoding/pem"
"fmt"
"os"
"time"

"github.com/sigstore/sigstore-go/pkg/root"
"github.com/sigstore/sigstore/pkg/cryptoutils"
Expand All @@ -31,13 +32,13 @@ import (
)

type CreateCmd struct {
CAIntermediates string
CARoots string
CertChain string
CtfeKeyPath string
CertChain []string
CtfeKeyPath []string
CtfeStartTime []string
Out string
RekorKeyPath string
TSACertChainPath string
RekorKeyPath []string
RekorStartTime []string
TSACertChainPath []string
}

func (c *CreateCmd) Exec(_ context.Context) error {
Expand All @@ -46,71 +47,64 @@ func (c *CreateCmd) Exec(_ context.Context) error {
var timestampAuthorities []root.CertificateAuthority
rekorTransparencyLogs := make(map[string]*root.TransparencyLog)

if c.CertChain != "" {
fulcioAuthority, err := parsePEMFile(c.CertChain)
for i := 0; i < len(c.CertChain); i++ {
fulcioAuthority, err := parsePEMFile(c.CertChain[i])
if err != nil {
return err
}
fulcioCertAuthorities = append(fulcioCertAuthorities, *fulcioAuthority)
} else if c.CARoots != "" {
roots, err := parseCerts(c.CARoots)
}

for i := 0; i < len(c.CtfeKeyPath); i++ {
ctLogPubKey, id, idBytes, err := getPubKey(c.CtfeKeyPath[i])
if err != nil {
return err
}

var intermediates []*x509.Certificate
if c.CAIntermediates != "" {
intermediates, err = parseCerts(c.CAIntermediates)
startTime := time.Unix(0, 0)

if i < len(c.CtfeStartTime) {
startTime, err = time.Parse(time.RFC3339, c.CtfeStartTime[i])
if err != nil {
return err
}
}

// Here we're trying to "flatten" the x509.CertPool cosign was using
// into a trusted root with a clear mapping between roots and
// intermediates. Make a guess that if there are intermediates, there
// is one per root.

for i, rootCert := range roots {
var fulcioAuthority root.CertificateAuthority
fulcioAuthority.Root = rootCert
if i < len(intermediates) {
fulcioAuthority.Intermediates = []*x509.Certificate{intermediates[i]}
}
fulcioCertAuthorities = append(fulcioCertAuthorities, fulcioAuthority)
ctLogs[id] = &root.TransparencyLog{
HashFunc: crypto.SHA256,
ID: idBytes,
ValidityPeriodStart: startTime,
PublicKey: *ctLogPubKey,
SignatureHashFunc: crypto.SHA256,
}
}

if c.CtfeKeyPath != "" {
ctLogPubKey, id, idBytes, err := getPubKey(c.CtfeKeyPath)
for i := 0; i < len(c.RekorKeyPath); i++ {
tlogPubKey, id, idBytes, err := getPubKey(c.RekorKeyPath[i])
if err != nil {
return err
}

ctLogs[id] = &root.TransparencyLog{
HashFunc: crypto.SHA256,
ID: idBytes,
PublicKey: *ctLogPubKey,
SignatureHashFunc: crypto.SHA256,
}
}
startTime := time.Unix(0, 0)

if c.RekorKeyPath != "" {
tlogPubKey, id, idBytes, err := getPubKey(c.RekorKeyPath)
if err != nil {
return err
if i < len(c.RekorStartTime) {
startTime, err = time.Parse(time.RFC3339, c.RekorStartTime[i])
if err != nil {
return err
}
}

rekorTransparencyLogs[id] = &root.TransparencyLog{
HashFunc: crypto.SHA256,
ID: idBytes,
PublicKey: *tlogPubKey,
SignatureHashFunc: crypto.SHA256,
HashFunc: crypto.SHA256,
ID: idBytes,
ValidityPeriodStart: startTime,
PublicKey: *tlogPubKey,
SignatureHashFunc: crypto.SHA256,
}
}

if c.TSACertChainPath != "" {
timestampAuthority, err := parsePEMFile(c.TSACertChainPath)
for i := 0; i < len(c.TSACertChainPath); i++ {
timestampAuthority, err := parsePEMFile(c.TSACertChainPath[i])
if err != nil {
return err
}
Expand Down Expand Up @@ -152,6 +146,7 @@ func parsePEMFile(path string) (*root.CertificateAuthority, error) {

var ca root.CertificateAuthority
ca.Root = certs[len(certs)-1]
ca.ValidityPeriodStart = certs[len(certs)-1].NotBefore
if len(certs) > 1 {
ca.Intermediates = certs[:len(certs)-1]
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/cosign/cli/trustedroot/trustedroot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ func TestCreateCmd(t *testing.T) {
outPath := filepath.Join(td, "trustedroot.json")

trustedrootCreate := CreateCmd{
CertChain: fulcioChainPath,
CertChain: []string{fulcioChainPath},
Out: outPath,
TSACertChainPath: tsaChainPath,
TSACertChainPath: []string{tsaChainPath},
}

err := trustedrootCreate.Exec(ctx)
Expand Down
16 changes: 8 additions & 8 deletions doc/cosign_trusted-root_create.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f705836

Please sign in to comment.