diff --git a/simple-ca.sh b/simple-ca.sh index d7b449b..fdd63e3 100755 --- a/simple-ca.sh +++ b/simple-ca.sh @@ -43,6 +43,7 @@ function make_ca() { # CA defaults to the main CA if not specified, but can be overridden with --issuing-ca local CA_FILE_PREFIX="ca" local AIA_BASE_URL="" + local CA_DIR="" while [[ $# -gt 0 ]]; do case "$1" in @@ -74,16 +75,23 @@ function make_ca() { AIA_BASE_URL="$2" shift 2 ;; + --ca-dir) + if [[ -z "$2" ]]; then + echo "ERROR: Missing value for --ca-dir." >&2 + return 1 + fi + CA_DIR="$2" + shift 2 + ;; *) break ;; esac done - # Use the provided directory argument - local CA_DIR="$1" - local CA_NAME="$2" - shift 2 + local CA_NAME="$1" + shift 1 + CA_DIR="${CA_DIR:-${SIMPLE_CA_DIR:-$(pwd)}}" if [[ -z "$CA_DIR" || ! -d "$CA_DIR" ]]; then echo "ERROR: Certificate directory $CA_DIR does not exist." @@ -231,7 +239,7 @@ function make_cert() { local CERT_SUBJECT_NAME="$2" shift 2 - CA_DIR="${CA_DIR:-$CERT_DIR}" + CA_DIR="${CA_DIR:-${SIMPLE_CA_DIR:-$(pwd)}}" local AIA_BASE_URL_FILE="$CA_DIR/aia_base_url.txt" local AIA_URL="" @@ -371,6 +379,7 @@ function make_pfx() { esac done + CA_DIR="${CA_DIR:-${SIMPLE_CA_DIR:-$(pwd)}}" local ROOT_CA_CERT="ca_cert.pem" local ROOT_CA_KEY="ca_key.pem" local CA_CERT="${CA_FILE_PREFIX:-ca}_cert.pem" diff --git a/src/simple-ca/main.go b/src/simple-ca/main.go index 3dd4798..f15784a 100644 --- a/src/simple-ca/main.go +++ b/src/simple-ca/main.go @@ -30,6 +30,8 @@ import ( "encoding/pem" "errors" "fmt" + + "github.com/spf13/cobra" "math/big" "net" "os" @@ -38,7 +40,6 @@ import ( "strings" "time" - "github.com/spf13/cobra" "software.sslmate.com/src/go-pkcs12" ) @@ -278,9 +279,6 @@ func makeCert(certDir, subjectName string, sans []string, caDir, issuingCA strin if prefix == "" { prefix = "ca" } - if caDir == "" { - caDir = certDir - } if certDir == "" || !dirExists(certDir) { return fmt.Errorf("certificate directory %s does not exist", certDir) } @@ -461,6 +459,17 @@ func makePFX(certPath, caDir, issuingCA, password string) error { return nil } +func resolveCADir(flagVal string) string { + if flagVal != "" { + return flagVal + } + if env := os.Getenv("SIMPLE_CA_DIR"); env != "" { + return env + } + cwd, _ := os.Getwd() + return cwd +} + func newRootCmd() *cobra.Command { root := &cobra.Command{ Use: "simple-ca", @@ -477,36 +486,40 @@ func newMakeCACmd() *cobra.Command { days int issuingCA string aiaBaseURL string + caDir string ) cmd := &cobra.Command{ - Use: "make-ca CA_DIR CA_NAME", + Use: "make-ca CA_NAME", Short: "Create a root or issuing CA.", - Args: cobra.ExactArgs(2), + Args: cobra.ExactArgs(1), RunE: func(_ *cobra.Command, args []string) error { - return makeCA(args[0], args[1], days, issuingCA, aiaBaseURL) + return makeCA(resolveCADir(caDir), args[0], days, issuingCA, aiaBaseURL) }, } cmd.Flags().IntVar(&days, "days", 3650, "validity period in days") cmd.Flags().StringVar(&issuingCA, "issuing-ca", "", "issuing CA file prefix (creates an issuing CA signed by the root)") cmd.Flags().StringVar(&aiaBaseURL, "aia-base-url", "", "base URL for the AIA caIssuers extension") + cmd.Flags().StringVar(&caDir, "ca-dir", "", "directory for CA files") return cmd } func newMakeCertCmd() *cobra.Command { var ( + certDir string caDir string issuingCA string days int ) cmd := &cobra.Command{ - Use: "make-cert CERT_DIR SUBJECT [SAN...]", + Use: "make-cert SUBJECT [SAN...]", Short: "Create a server/client certificate signed by the CA.", - Args: cobra.MinimumNArgs(2), + Args: cobra.MinimumNArgs(1), RunE: func(_ *cobra.Command, args []string) error { - return makeCert(args[0], args[1], args[2:], caDir, issuingCA, days) + return makeCert(certDir, args[0], args[1:], resolveCADir(caDir), issuingCA, days) }, } - cmd.Flags().StringVar(&caDir, "ca-dir", "", "CA directory (defaults to CERT_DIR)") + cmd.Flags().StringVar(&certDir, "cert-dir", "", "directory to store the certificate files") + cmd.Flags().StringVar(&caDir, "ca-dir", "", "CA directory") cmd.Flags().StringVar(&issuingCA, "issuing-ca", "", "issuing CA file prefix") cmd.Flags().IntVar(&days, "days", 365, "validity period in days") return cmd @@ -516,23 +529,19 @@ func newMakePFXCmd() *cobra.Command { var ( caDir string issuingCA string - certPath string password string ) cmd := &cobra.Command{ - Use: "make-pfx --ca-dir DIR --path CERT_PATH [flags]", + Use: "make-pfx CERT_PATH", Short: "Create a PKCS#12 (PFX) bundle for a leaf certificate.", - Args: cobra.NoArgs, - RunE: func(_ *cobra.Command, _ []string) error { - return makePFX(certPath, caDir, issuingCA, password) + Args: cobra.ExactArgs(1), + RunE: func(_ *cobra.Command, args []string) error { + return makePFX(args[0], resolveCADir(caDir), issuingCA, password) }, } cmd.Flags().StringVar(&caDir, "ca-dir", "", "CA directory") cmd.Flags().StringVar(&issuingCA, "issuing-ca", "", "issuing CA file prefix") - cmd.Flags().StringVar(&certPath, "path", "", "path to the leaf certificate PEM") cmd.Flags().StringVar(&password, "password", "", "PFX password (default: changeit)") - _ = cmd.MarkFlagRequired("ca-dir") - _ = cmd.MarkFlagRequired("path") return cmd }