diff options
Diffstat (limited to 'flags.go')
-rw-r--r-- | flags.go | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/flags.go b/flags.go new file mode 100644 index 0000000..d7dc2ef --- /dev/null +++ b/flags.go @@ -0,0 +1,168 @@ +package main + +// This file handles the complete parameter assignment, as some parameters are +// often used by multiple functions. + +import ( + "crypto/elliptic" + "flag" + "fmt" + "io" + "os" + + "github.com/gibheer/pkilib" +) + +const ( + RsaLowerLength = 2048 + RsaUpperLength = 16384 +) + +var ( + EcdsaCurves = []int{224, 256, 384, 521} +) + +type ( + // holds all certificate related flags, which need parsing afterwards + certFlagsContainer struct { + serialNumber int // the serial number for the cert + commonName string // the common name used in the cert + dnsNames string // all alternative names in the certificate (comma separated list) + ipAddresses string // all IP addresses in the certificate (comma separated list) + country string // the country names which should end up in the cert (comma separated list) + organization string // the organization names (comma separated list) + organizationalUnit string // the organizational units (comma separated list) + locality string // the city or locality (comma separated list) + province string // the province name (comma separated list) + streetAddress string // the street addresses of the organization (comma separated list) + postalCode string // the postal codes of the locality + } + + // a container go gather all incoming flags for further processing + paramContainer struct { + outputPath string // path to output whatever is generated + cryptType string // type of something (private key) + length int // the length of something (private key) + privateKeyPath string // path to the private key + publicKeyPath string // path to the public key + signRequestPath string // path to the certificate sign request + certificateFlags *certFlagsContainer // container for certificate related flags + } + + // a container for the refined flags + flagSet struct { + PrivateKey pkilib.PrivateKey + Output io.WriteCloser + + // private key specific stuff + PrivateKeyGenerationFlags privateKeyGenerationFlags + } + + privateKeyGenerationFlags struct { + Type string // type of the private key (rsa, ecdsa) + Curve elliptic.Curve // curve for ecdsa + Size int // bitsize for rsa + } + + Flags struct { + flagset *flag.FlagSet // the flagset reference for printing the help + flag_container *paramContainer + Flags *flagSet // the end result of the flag setting + + check_list []flagCheck // list of all checks + } + + flagCheck func()(error) +) + +// create a new flag handler with the name of the subfunction +func NewFlags(method_name string) *Flags { + return &Flags{ + Flags: &flagSet{}, + flagset: flag.NewFlagSet(method_name, flag.ExitOnError), + check_list: make([]flagCheck, 0), + flag_container: ¶mContainer{}, + } +} + +// check all parameters for validity +func (f *Flags) Parse(options []string) error { + f.flagset.Parse(options) + for _, check := range f.check_list { + // TODO handle error in a betetr way (output specific help, not command help) + if err := check(); err != nil { return err } + } + return nil +} + +// add the private key option to the requested flags +func (f *Flags) AddPrivateKey() { + f.check_list = append(f.check_list, f.parsePrivateKey) + f.flagset.StringVar(&f.flag_container.privateKeyPath, "private-key", "", "path to the private key") +} + +// check the private key flag and load the private key +func (f *Flags) parsePrivateKey() error { + // check permissions of private key file + info, err := os.Stat(f.flag_container.privateKeyPath) + if err != nil { return fmt.Errorf("Error reading private key: %s", err) } + if info.Mode().Perm().String()[4:] != "------" { + return fmt.Errorf("private key file modifyable by others!") + } + + pk, err := ReadPrivateKeyFile(f.flag_container.privateKeyPath) + if err != nil { return fmt.Errorf("Error reading private key: %s", err) } + f.Flags.PrivateKey = pk + return nil +} + +// add the output parameter to the checklist +func (f *Flags) AddOutput() { + f.check_list = append(f.check_list, f.parseOutput) + f.flagset.StringVar(&f.flag_container.outputPath, "output", "STDOUT", "path to the output or STDOUT") +} + +// parse the output parameter and open the file handle +func (f *Flags) parseOutput() error { + if f.flag_container.outputPath == "STDOUT" { + f.Flags.Output = os.Stdout + return nil + } + var err error + f.Flags.Output, err = os.OpenFile( + f.flag_container.outputPath, + os.O_WRONLY | os.O_APPEND | os.O_CREATE, // do not kill users files! + 0600, + ) + if err != nil { return err } + return nil +} + +// This function adds the private key generation flags. +func (f *Flags) AddPrivateKeyGenerationFlags() { + f.check_list = append(f.check_list, f.parsePrivateKeyGenerationFlags) + f.flagset.StringVar(&f.flag_container.cryptType, "type", "ecdsa", "the type of the private key (ecdsa, rsa)") + f.flagset.IntVar( + &f.flag_container.length, + "length", 521, + fmt.Sprintf("%d - %d for rsa; %v for ecdsa", RsaLowerLength, RsaUpperLength, EcdsaCurves), + ) +} + +func (f *Flags) parsePrivateKeyGenerationFlags() error { + pk_type := f.flag_container.cryptType + f.Flags.PrivateKeyGenerationFlags.Type = pk_type + switch pk_type { + case "ecdsa": + switch f.flag_container.length { + case 224: f.Flags.PrivateKeyGenerationFlags.Curve = elliptic.P224() + case 256: f.Flags.PrivateKeyGenerationFlags.Curve = elliptic.P256() + case 384: f.Flags.PrivateKeyGenerationFlags.Curve = elliptic.P384() + case 521: f.Flags.PrivateKeyGenerationFlags.Curve = elliptic.P521() + default: return fmt.Errorf("Curve %d unknown!", f.flag_container.length) + } + case "rsa": f.Flags.PrivateKeyGenerationFlags.Size = f.flag_container.length + default: return fmt.Errorf("Type %s is unknown!", pk_type) + } + return nil +} |