Skip to content

Commit

Permalink
Refactor flag binding functions
Browse files Browse the repository at this point in the history
  • Loading branch information
dvob committed Jul 27, 2024
1 parent 19bae74 commit 157dee9
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 111 deletions.
10 changes: 8 additions & 2 deletions cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,15 @@ func NewCertificate(opts *CertificateOptions) *x509.Certificate {
Policies: opts.Policies,
}

if opts.MaxPathLen != nil {
cert.MaxPathLen = *opts.MaxPathLen
if opts.MaxPathLen == nil {
cert.MaxPathLen = -1
cert.MaxPathLenZero = false
} else if *opts.MaxPathLen == 0 {
cert.MaxPathLen = 0
cert.MaxPathLenZero = true
} else {
cert.MaxPathLen = *opts.MaxPathLen
cert.MaxPathLenZero = false
}

if cert.NotBefore.IsZero() {
Expand Down
5 changes: 3 additions & 2 deletions cmd/pcert/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ pcert create tls.crt
cmd.Flags().StringVarP(&createCommand.SignCertificateLocation, "sign-cert", "s", createCommand.SignCertificateLocation, "Certificate used to sign. If not specified a self-signed certificate is created")
cmd.Flags().StringVar(&createCommand.SignKeyLocation, "sign-key", createCommand.SignKeyLocation, "Key used to sign. If not specified but --sign-cert is specified we use the key file relative to the certificate specified with --sign-cert.")
cmd.Flags().StringSliceVar(&createCommand.Profiles, "profile", createCommand.Profiles, "Certificates profiles to apply (server, client, ca)")
BindCertificateOptionsFlags(cmd.Flags(), &createCommand.CertificateOptions)
BindKeyFlags(cmd.Flags(), &createCommand.KeyOptions)

registerCertFlags(cmd, &createCommand.CertificateOptions)
registerKeyFlags(cmd, &createCommand.KeyOptions)
return cmd
}
49 changes: 49 additions & 0 deletions cmd/pcert/flag_certificate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package main

import (
"fmt"
"net"
"time"

"github.com/dvob/pcert"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

func registerCertFlags(cmd *cobra.Command, certOpts *pcert.CertificateOptions) {
bindCertFlags(cmd.Flags(), certOpts)

_ = cmd.RegisterFlagCompletionFunc("sign-alg", signAlgorithmCompletionFunc)

_ = cmd.RegisterFlagCompletionFunc("key-usage", keyUsageCompletionFunc)
_ = cmd.RegisterFlagCompletionFunc("ext-key-usage", extKeyUsageCompletionFunc)
}

func bindCertFlags(fs *pflag.FlagSet, co *pcert.CertificateOptions) {
// SAN
fs.StringSliceVar(&co.DNSNames, "dns", []string{}, "DNS subject alternative name.")
fs.StringSliceVar(&co.EmailAddresses, "email", []string{}, "Email subject alternative name.")
fs.IPSliceVar(&co.IPAddresses, "ip", []net.IP{}, "IP subject alternative name.")
fs.Var(newURISliceValue(&co.URIs), "uri", "URI subject alternative name.")

// signature algorithm
fs.Var(newSignAlgValue(&co.SignatureAlgorithm), "sign-alg", "Signature Algorithm. See 'pcert list' for available algorithms.")

// validity duration
fs.Var(newTimeValue(&co.NotBefore), "not-before", fmt.Sprintf("Not valid before time in RFC3339 format (e.g. '%s').", time.Now().UTC().Format(time.RFC3339)))
fs.Var(newTimeValue(&co.NotAfter), "not-after", fmt.Sprintf("Not valid after time in RFC3339 format (e.g. '%s').", time.Now().Add(time.Hour*24*60).UTC().Format(time.RFC3339)))
fs.Var(newDurationValue(&co.Expiry), "expiry", "Validity period of the certificate. If --not-after is set this option has no effect.")

// subject
fs.Var(newSubjectValue(&co.Subject), "subject", "Subject in the form '/C=CH/O=My Org/OU=My Team'.")
bindSubjectFlags(fs, &co.Subject)

// basic constraints
fs.BoolVar(&co.BasicConstraintsValid, "basic-constraints", co.BasicConstraintsValid, "Add basic constraints extension.")
fs.BoolVar(&co.IsCA, "is-ca", co.IsCA, "Mark certificate as CA in the basic constraints. Only takes effect if --basic-constraints is true.")
fs.Var(newMaxPathLengthValue(co.MaxPathLen), "max-path-length", "Sets the max path length in the basic constraints.")

// key usage
fs.Var(newKeyUsageValue(&co.KeyUsage), "key-usage", "Set the key usage. See 'pcert list' for available key usages.")
fs.Var(newExtKeyUsageValue(&co.ExtKeyUsage), "ext-key-usage", "Set the extended key usage. See 'pcert list' for available extended key usages.")
}
18 changes: 18 additions & 0 deletions cmd/pcert/flag_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package main

import (
"github.com/dvob/pcert"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

func registerKeyFlags(cmd *cobra.Command, keyOpts *pcert.KeyOptions) {
bindKeyFlags(cmd.Flags(), keyOpts)

_ = cmd.RegisterFlagCompletionFunc("key-alg", keyAlgorithmCompletionFunc)
}

func bindKeyFlags(fs *pflag.FlagSet, keyOptions *pcert.KeyOptions) {
fs.Var(newKeyAlgorithmValue(&keyOptions.Algorithm), "key-alg", "Public key algorithm. See 'pcert list' for available algorithms.")
fs.IntVar(&keyOptions.Size, "key-size", keyOptions.Size, "Key Size. This defaults to 256 for ECDSA and to 2048 for RSA.")
}
31 changes: 15 additions & 16 deletions cmd/pcert/flag_maxpathlength.go
Original file line number Diff line number Diff line change
@@ -1,41 +1,40 @@
package main

import (
"crypto/x509"
"strconv"
)

type maxPathLengthValue struct {
cert *x509.Certificate
maxPathLen *int
}

func newMaxPathLengthValue(c *x509.Certificate) *maxPathLengthValue {
func newMaxPathLengthValue(maxPathLen *int) *maxPathLengthValue {
return &maxPathLengthValue{
cert: c,
maxPathLen: maxPathLen,
}
}

func (m *maxPathLengthValue) Type() string {
return "int|none"
return "int|-"
}

func (m *maxPathLengthValue) String() string {
if m.cert.MaxPathLen < 0 {
return "none"
if m.maxPathLen == nil {
return "-"
}
if m.cert.MaxPathLen == 0 && !m.cert.MaxPathLenZero {
return "none"
}
return strconv.Itoa(m.cert.MaxPathLen)
return strconv.Itoa(*m.maxPathLen)
}

func (m *maxPathLengthValue) Set(length string) error {
var err error
if length == "none" {
m.cert.MaxPathLen = -1
return nil
if length == "-" {
m.maxPathLen = nil
}

m.cert.MaxPathLen, err = strconv.Atoi(length)
return err
value, err := strconv.Atoi(length)
if err != nil {
return err
}
m.maxPathLen = &value
return nil
}
24 changes: 24 additions & 0 deletions cmd/pcert/flag_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"crypto/x509"
"net"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

func registerRequestFlags(cmd *cobra.Command, csr *x509.CertificateRequest) {
bindRequestFlags(cmd.Flags(), csr)

_ = cmd.RegisterFlagCompletionFunc("sign-alg", signAlgorithmCompletionFunc)
}

func bindRequestFlags(fs *pflag.FlagSet, csr *x509.CertificateRequest) {
fs.StringSliceVar(&csr.DNSNames, "dns", []string{}, "DNS subject alternative name.")
fs.StringSliceVar(&csr.EmailAddresses, "email", []string{}, "Email subject alternative name.")
fs.IPSliceVar(&csr.IPAddresses, "ip", []net.IP{}, "IP subject alternative name.")
fs.Var(newURISliceValue(&csr.URIs), "uri", "URI subject alternative name.")
fs.Var(newSignAlgValue(&csr.SignatureAlgorithm), "sign-alg", "Signature Algorithm. See 'pcert list' for available algorithms.")
fs.Var(newSubjectValue(&csr.Subject), "subject", "Subject in the form '/C=CH/O=My Org/OU=My Team'.")
}
15 changes: 15 additions & 0 deletions cmd/pcert/flag_subject.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,23 @@ import (
"crypto/x509/pkix"
"fmt"
"strings"

"github.com/spf13/pflag"
)

func bindSubjectFlags(fs *pflag.FlagSet, subject *pkix.Name) {
fs.StringSliceVar(&subject.Country, "subject-country", subject.Country, "subject country (C)")
fs.StringSliceVar(&subject.Organization, "subject-org", subject.Organization, "subject organization (O)")
fs.StringSliceVar(&subject.OrganizationalUnit, "subject-ou", subject.OrganizationalUnit, "subject organizational unit (OU)")
fs.StringSliceVar(&subject.Locality, "subject-locality", subject.Locality, "subject locality (L)")
fs.StringSliceVar(&subject.Province, "subject-province", subject.Province, "subject province (P)")
fs.StringSliceVar(&subject.StreetAddress, "subject-street-address", subject.StreetAddress, "subject street address (STREET)")
fs.StringSliceVar(&subject.PostalCode, "subject-postal-code", subject.PostalCode, "subject postal code (POSTALCODE)")
fs.StringVar(&subject.SerialNumber, "subject-serial-number", subject.SerialNumber, "subject serial number (SERIALNUMBER)")
fs.StringVar(&subject.CommonName, "subject-common-name", subject.CommonName, "subject common name (CN)")
fs.StringVarP(&subject.CommonName, "name", "n", subject.CommonName, "subject common name (CN). alias for --subject-common-name")
}

type subjectValue struct {
value *pkix.Name
}
Expand Down
85 changes: 0 additions & 85 deletions cmd/pcert/flags.go

This file was deleted.

7 changes: 2 additions & 5 deletions cmd/pcert/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,8 @@ func newRequestCmd() *cobra.Command {
},
}

BindKeyFlags(cmd.Flags(), &keyOpts)
RegisterKeyCompletionFuncs(cmd)

BindCertificateRequestFlags(cmd.Flags(), csr)
RegisterCertificateRequestCompletionFuncs(cmd)
registerRequestFlags(cmd, csr)
registerKeyFlags(cmd, &keyOpts)

return cmd
}
3 changes: 2 additions & 1 deletion cmd/pcert/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ func newSignCmd() *cobra.Command {
cmd.Flags().StringVar(&signKeyLocation, "sign-key", signKeyLocation, "Key used to sign. If not specified but --sign-cert is specified we use the key file relative to the certificate specified with --sign-cert.")

cmd.Flags().StringSliceVar(&profiles, "profile", profiles, "profile to set on the certificate (server, client, ca)")
BindCertificateOptionsFlags(cmd.Flags(), &certOpts)

registerCertFlags(cmd, &certOpts)

return cmd
}

0 comments on commit 157dee9

Please sign in to comment.