Skip to content

Commit

Permalink
Localize flags to each subcommand (#274)
Browse files Browse the repository at this point in the history
This makes it more clear which flag is for which subcommand.

Signed-off-by: Nathan Smith <nathan@nfsmith.ca>
  • Loading branch information
nsmith5 authored Dec 12, 2021
1 parent e270bd4 commit 6ff4fbf
Show file tree
Hide file tree
Showing 4 changed files with 249 additions and 236 deletions.
218 changes: 114 additions & 104 deletions cmd/app/createca.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,126 +40,136 @@ const (
LABEL = "PKCS11CA"
)

// createcaCmd represents the createca command
var createcaCmd = &cobra.Command{
Use: "createca",
Short: "Create a root CA in a pkcs11 device",
Long: `Create an x509 root CA within a pkcs11 device using values
func newCreateCACmd() *cobra.Command {
cmd := &cobra.Command{
Use: "createca",
Short: "Create a root CA in a pkcs11 device",
Long: `Create an x509 root CA within a pkcs11 device using values
such as organization, country etc. This can then be used as the root
certificate authority for an instance of sigstore fulcio`,
Run: func(cmd *cobra.Command, args []string) {
log.Logger.Info("binding to PKCS11 HSM")
p11Ctx, err := crypto11.ConfigureFromFile(viper.GetString("pkcs11-config-path"))
if err != nil {
log.Logger.Fatal(err)
}
defer p11Ctx.Close()
Run: runCreateCACmd,
}

rootID := []byte(viper.GetString("hsm-caroot-id"))
cmd.Flags().String("org", "Fulcio Root CA", "Organization name for root CA")
cmd.Flags().String("country", "", "Country name for root CA")
cmd.Flags().String("province", "", "Province name for root CA")
cmd.Flags().String("locality", "", "Locality name for root CA")
cmd.Flags().String("street-address", "", "Street address for root CA")
cmd.Flags().String("postal-code", "", "Postal code for root CA")
cmd.Flags().String("out", "", "output root CA to file")
cmd.Flags().String("hsm", "softhsm", "The HSM provider to use. Valid values: softhsm (default), aws")
cmd.Flags().String("pkcs11-config-path", "config/crypto11.conf", "path to fulcio pkcs11 config file")
cmd.Flags().String("hsm-caroot-id", "", "HSM ID for Root CA")

err := cmd.MarkFlagRequired("hsm-caroot-id")
if err != nil {
log.Logger.Fatal(`Failed to mark flag as required`)
}

// Check if CA already exists (or a cert within the provided ID)
findCA, err := p11Ctx.FindCertificate(rootID, nil, nil)
if err != nil {
log.Logger.Fatal(err)
}
if findCA != nil {
log.Logger.Fatal("certificate already exists with this ID")
}
return cmd
}

// Find the existing Key Pair
// TODO: We could make the TAG customizable
log.Logger.Info("finding slot for private key: ", LABEL)
privKey, err := p11Ctx.FindKeyPair(nil, []byte(LABEL))
if err != nil {
log.Logger.Fatal(err)
}
func runCreateCACmd(cmd *cobra.Command, args []string) {
if err := viper.BindPFlags(cmd.Flags()); err != nil {
log.Logger.Fatal(err)
}

pubKey := privKey.Public()
log.Logger.Info("binding to PKCS11 HSM")
p11Ctx, err := crypto11.ConfigureFromFile(viper.GetString("pkcs11-config-path"))
if err != nil {
log.Logger.Fatal(err)
}
defer p11Ctx.Close()

// TODO: We could make it so this could be passed in by the user
serialNumber, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64))
if err != nil {
log.Logger.Fatal(err)
}
rootCA := &x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{viper.GetString("org")},
Country: []string{viper.GetString("country")},
Province: []string{viper.GetString("province")},
Locality: []string{viper.GetString("locality")},
StreetAddress: []string{viper.GetString("street-address")},
PostalCode: []string{viper.GetString("postal-code")},
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
IsCA: true,
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
BasicConstraintsValid: true, MaxPathLen: 1,
}
rootID := []byte(viper.GetString("hsm-caroot-id"))

caBytes, err := x509.CreateCertificate(rand.Reader, rootCA, rootCA, pubKey, privKey)
if err != nil {
log.Logger.Fatal(err)
}
// Check if CA already exists (or a cert within the provided ID)
findCA, err := p11Ctx.FindCertificate(rootID, nil, nil)
if err != nil {
log.Logger.Fatal(err)
}
if findCA != nil {
log.Logger.Fatal("certificate already exists with this ID")
}

pemBytes := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: caBytes,
})
// Find the existing Key Pair
// TODO: We could make the TAG customizable
log.Logger.Info("finding slot for private key: ", LABEL)
privKey, err := p11Ctx.FindKeyPair(nil, []byte(LABEL))
if err != nil {
log.Logger.Fatal(err)
}

log.Logger.Info("Root CA:")
fmt.Println(string(pemBytes))
pubKey := privKey.Public()

certParse, err := x509.ParseCertificate(caBytes)
if err != nil {
// TODO: We could make it so this could be passed in by the user
serialNumber, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64))
if err != nil {
log.Logger.Fatal(err)
}
rootCA := &x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{viper.GetString("org")},
Country: []string{viper.GetString("country")},
Province: []string{viper.GetString("province")},
Locality: []string{viper.GetString("locality")},
StreetAddress: []string{viper.GetString("street-address")},
PostalCode: []string{viper.GetString("postal-code")},
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
IsCA: true,
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
BasicConstraintsValid: true, MaxPathLen: 1,
}

caBytes, err := x509.CreateCertificate(rand.Reader, rootCA, rootCA, pubKey, privKey)
if err != nil {
log.Logger.Fatal(err)
}

pemBytes := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: caBytes,
})

log.Logger.Info("Root CA:")
fmt.Println(string(pemBytes))

certParse, err := x509.ParseCertificate(caBytes)
if err != nil {
log.Logger.Fatal(err)
}

// Import the root CA into the HSM
// TODO: We could make the TAG customizable
if viper.GetString("hsm") == "aws" {
log.Logger.Info("Running in AWS mode; skipping root CA storage in HSM")
if !viper.IsSet("out") {
log.Logger.Warn("WARNING: --out is not set. Root CA will not be saved.")
}
} else {
if err = p11Ctx.ImportCertificateWithLabel(rootID, []byte(LABEL), certParse); err != nil {
log.Logger.Fatal(err)
}
log.Logger.Info("root CA created with PKCS11 ID: ", viper.GetString("hsm-caroot-id"))
}

// Import the root CA into the HSM
// TODO: We could make the TAG customizable
if viper.GetString("hsm") == "aws" {
log.Logger.Info("Running in AWS mode; skipping root CA storage in HSM")
if !viper.IsSet("out") {
log.Logger.Warn("WARNING: --out is not set. Root CA will not be saved.")
}
} else {
if err = p11Ctx.ImportCertificateWithLabel(rootID, []byte(LABEL), certParse); err != nil {
log.Logger.Fatal(err)
}
log.Logger.Info("root CA created with PKCS11 ID: ", viper.GetString("hsm-caroot-id"))
// Save out the file in pem format for easy import to CTL chain
if viper.IsSet("out") {
certOut, err := os.Create(filepath.Clean(viper.GetString("out")))
if err != nil {
log.Logger.Fatal(err)
}

// Save out the file in pem format for easy import to CTL chain
if viper.IsSet("out") {
certOut, err := os.Create(filepath.Clean(viper.GetString("out")))
if err != nil {
log.Logger.Fatal(err)
}
if err := pem.Encode(certOut, &pem.Block{ //nolint
Type: "CERTIFICATE",
Bytes: caBytes},
); err != nil {
certOut.Close()
log.Logger.Fatal(err)
}
if err := pem.Encode(certOut, &pem.Block{ //nolint
Type: "CERTIFICATE",
Bytes: caBytes},
); err != nil {
certOut.Close()
log.Logger.Info("root CA saved to file: ", viper.GetString("out"))
log.Logger.Fatal(err)
}
},
}

func init() {
rootCmd.AddCommand(createcaCmd)
createcaCmd.PersistentFlags().String("org", "Fulcio Root CA", "Organization name for root CA")
createcaCmd.PersistentFlags().String("country", "", "Country name for root CA")
createcaCmd.PersistentFlags().String("province", "", "Province name for root CA")
createcaCmd.PersistentFlags().String("locality", "", "Locality name for root CA")
createcaCmd.PersistentFlags().String("street-address", "", "Street address for root CA")
createcaCmd.PersistentFlags().String("postal-code", "", "Postal code for root CA")
createcaCmd.PersistentFlags().String("out", "", "output root CA to file")
createcaCmd.PersistentFlags().String("hsm", "softhsm", "The HSM provider to use. Valid values: softhsm (default), aws")
if err := viper.BindPFlags(createcaCmd.PersistentFlags()); err != nil {
log.Logger.Fatal(err)
certOut.Close()
log.Logger.Info("root CA saved to file: ", viper.GetString("out"))
}
}
23 changes: 3 additions & 20 deletions cmd/app/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,10 @@ import (
"os"

"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/sigstore/fulcio/pkg/log"
)

var (
logType string
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "fulcio",
Expand All @@ -46,19 +41,7 @@ func Execute(ctx context.Context) {
}

func init() {
rootCmd.PersistentFlags().StringVar(&logType, "log_type", "dev", "logger type to use (dev/prod)")
rootCmd.PersistentFlags().String("ca", "", "googleca | pkcs11ca | ephemeralca (for testing)")
rootCmd.PersistentFlags().String("aws-hsm-root-ca-path", "", "Path to root CA on disk (only used with AWS HSM)")
rootCmd.PersistentFlags().String("gcp_private_ca_parent", "", "private ca parent: /projects/<project>/locations/<location>/<name> (only used with --ca googleca)")
rootCmd.PersistentFlags().String("gcp_private_ca_version", "v1", "private ca version: [v1|v1beta1] (only used with --ca googleca)")
rootCmd.PersistentFlags().String("hsm-caroot-id", "", "HSM ID for Root CA (only used with --ca pkcs11ca)")
rootCmd.PersistentFlags().String("ct-log-url", "http://localhost:6962/test", "host and path (with log prefix at the end) to the ct log")
rootCmd.PersistentFlags().String("config-path", "/etc/fulcio-config/config.json", "path to fulcio config json")
rootCmd.PersistentFlags().String("pkcs11-config-path", "config/crypto11.conf", "path to fulcio pkcs11 config file")
rootCmd.PersistentFlags().String("host", "0.0.0.0", "The host on which to serve requests")
rootCmd.PersistentFlags().String("port", "8080", "The port on which to serve requests")

if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil {
log.Logger.Fatal(err)
}
rootCmd.AddCommand(newCreateCACmd())
rootCmd.AddCommand(newServeCmd())
rootCmd.AddCommand(newVersionCmd())
}
Loading

0 comments on commit 6ff4fbf

Please sign in to comment.