From d983dbae543f93bf1c0019af1f24c11d4a1840ff Mon Sep 17 00:00:00 2001 From: Gibheer Date: Sat, 21 Mar 2015 18:50:55 +0100 Subject: [PATCH] rework the parameter management With this change it is now possible to provide help messages for all commands. This will help to further cleanup and minimize the code base. --- flags.go | 351 +++++++++++++++++++++++++++++++------------------------ main.go | 187 +++++++++++++---------------- 2 files changed, 278 insertions(+), 260 deletions(-) diff --git a/flags.go b/flags.go index d70120b..3b65d52 100644 --- a/flags.go +++ b/flags.go @@ -7,7 +7,6 @@ import ( "crypto/elliptic" "encoding/base64" "encoding/pem" - "flag" "fmt" "io" "io/ioutil" @@ -62,131 +61,186 @@ type ( signature string // a base64 encoded signature } - // a container for the refined flags - flagSet struct { - // loaded private key - PrivateKey pki.PrivateKey - // loaded public key - PublicKey pki.PublicKey - // the IO handler for input - Input io.ReadCloser - // the IO handler for output - Output io.WriteCloser - // signature from the args - Signature []byte - // private key specific stuff - PrivateKeyGenerationFlags privateKeyGenerationFlags - // a certificate filled with the parameters - CertificateData *pki.CertificateData - // the certificate sign request - CertificateSignRequest *pki.CertificateRequest - } - privateKeyGenerationFlags struct { Type string // type of the private key (rsa, ecdsa) Curve elliptic.Curve // curve for ecdsa Size int // bitsize for rsa } - Flags struct { - Name string // name of the sub function - 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 { - flagset := flag.NewFlagSet(method_name, flag.ExitOnError) - flags := &Flags{ - Name: method_name, - Flags: &flagSet{}, - flagset: flagset, - check_list: make([]flagCheck, 0), - flag_container: ¶mContainer{}, +var ( + CmdRoot = &Command { + Short: "A tool to manage keys and certificates.", + Long: `This tool provides a way to manage private and public keys, create +certificate requests and certificates and sign/verify messages.`, } - flagset.Usage = flags.Usage - return flags + + CmdCreatePrivateKey = &Command { + Use: "create-private", + Short: "create a private key", + Long: "Create an ecdsa or rsa key with this command", + Example: "create-private -type=ecdsa -length=521", + Run: create_private_key, + } + + CmdCreatePublicKey = &Command { + Use: "create-public", + Short: "create a public key from a private key", + Long: "Create a public key derived from a private key.", + Example: "create-public -private-key=foo.ecdsa", + Run: create_public_key, + } + + CmdSignInput = &Command { + Use: "sign-input", + Short: "sign a text using a private key", + Long: "Create a signature using a private key", + Example: "sign-input -private-key=foo.ecdsa -input=textfile", + Run: sign_input, + } + + CmdVerifyInput = &Command { + Use: "verify-input", + Short: "verify a text using a signature", + Long: "Verify a text using a signature and a public key.", + Example: "verify-input -public-key=foo.ecdsa.pub -input=textfile -signature=abc456", + Run: verify_input, + } + + CmdCreateSignRequest = &Command { + Use: "create-sign-request", + Short: "create a certificate sign request", + Long: "Create a certificate sign request.", + Example: "create-sign-request -private-key=foo.ecdsa -common-name=foo -serial=1", + Run: create_sign_request, + } + + CmdCreateCert = &Command { + Use: "create-cert", + Short: "create a certificate from a sign request", + Long: "Create a certificate based on a certificate sign request.", + Example: "create-cert -private-key=foo.ecdsa -csr-path=foo.csr", + Run: create_cert, + } + + // variable to hold the raw arguments before checking + flagContainer *paramContainer + + // loaded private key + FlagPrivateKey pki.PrivateKey + // loaded public key + FlagPublicKey pki.PublicKey + // the IO handler for input + FlagInput io.ReadCloser + // the IO handler for output + FlagOutput io.WriteCloser + // signature from the args + FlagSignature []byte + // private key specific stuff + FlagPrivateKeyGeneration privateKeyGenerationFlags + // a certificate filled with the parameters + FlagCertificateData *pki.CertificateData + // the certificate sign request + FlagCertificateSignRequest *pki.CertificateRequest +) + +func InitFlags() { + flagContainer = ¶mContainer{} + CmdRoot.AddCommand( + CmdCreatePrivateKey, + CmdCreatePublicKey, + CmdSignInput, + CmdVerifyInput, + CmdCreateSignRequest, + CmdCreateCert, + ) + + // private-key + InitFlagOutput(CmdCreatePrivateKey) + InitFlagPrivateKeyGeneration(CmdCreatePrivateKey) + // public-key + InitFlagOutput(CmdCreatePublicKey) + InitFlagPrivateKey(CmdCreatePublicKey) + // sign-input + InitFlagInput(CmdSignInput) + InitFlagPrivateKey(CmdSignInput) + InitFlagOutput(CmdSignInput) + // verify-input + InitFlagInput(CmdVerifyInput) + InitFlagPrivateKey(CmdVerifyInput) + InitFlagOutput(CmdVerifyInput) + InitFlagSignature(CmdVerifyInput) + // create-sign-request + InitFlagPrivateKey(CmdCreateSignRequest) + InitFlagOutput(CmdCreateSignRequest) + InitFlagCertificateFields(CmdCreateSignRequest) + // create-certificate + InitFlagPrivateKey(CmdCreateCert) + InitFlagOutput(CmdCreateCert) + InitFlagCSR(CmdCreateCert) } -// 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) +func checkFlags(checks... flagCheck) error { + for _, check := range checks { if err := check(); err != nil { - f.Usagef("%s", err) return err } } return nil } -// print a message with the usage part -func (f *Flags) Usagef(message string, args ...interface{}) { - fmt.Fprintf(os.Stderr, "error: " + message + "\n", args...) - f.Usage() -} - -// print the usage of the current flag set -func (f *Flags) Usage() { - fmt.Fprintf(os.Stderr, "usage: %s %s [options]\n", os.Args[0], f.Name) - fmt.Fprint(os.Stderr, "where options are:\n") - f.flagset.PrintDefaults() -} +//// print a message with the usage part +//func (f *Flags) Usagef(message string, args ...interface{}) { +// fmt.Fprintf(os.Stderr, "error: " + message + "\n", args...) +// f.flagset.Flags().Usage() +//} // 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") +func InitFlagPrivateKey(cmd *Command) { + cmd.Flags().StringVar(&flagContainer.privateKeyPath, "private-key", "", "path to the private key (required)") } // check the private key flag and load the private key -func (f *Flags) parsePrivateKey() error { - if f.flag_container.privateKeyPath == "" { return fmt.Errorf("No private key given!") } +func checkPrivateKey() error { + if flagContainer.privateKeyPath == "" { return fmt.Errorf("No private key given!") } // check permissions of private key file - info, err := os.Stat(f.flag_container.privateKeyPath) + info, err := os.Stat(flagContainer.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) + pk, err := ReadPrivateKeyFile(flagContainer.privateKeyPath) if err != nil { return fmt.Errorf("Error reading private key: %s", err) } - f.Flags.PrivateKey = pk + FlagPrivateKey = pk return nil } // add the public key flag -func (f *Flags) AddPublicKey() { - f.check_list = append(f.check_list, f.parsePublicKey) - f.flagset.StringVar(&f.flag_container.publicKeyPath, "public-key", "", "path to the public key") +func InitFlagPublicKey(cmd *Command) { + cmd.Flags().StringVar(&flagContainer.publicKeyPath, "public-key", "", "path to the public key (required)") } // parse public key flag -func (f *Flags) parsePublicKey() error { - if f.flag_container.publicKeyPath == "" { return fmt.Errorf("No public key given!") } +func checkPublicKey() error { + if flagContainer.publicKeyPath == "" { return fmt.Errorf("No public key given!") } - pu, err := ReadPublicKeyFile(f.flag_container.publicKeyPath) + pu, err := ReadPublicKeyFile(flagContainer.publicKeyPath) if err != nil { return fmt.Errorf("Error reading public key: %s", err) } - f.Flags.PublicKey = pu + FlagPublicKey = pu return nil } // add flag to load certificate sign request -func (f *Flags) AddCSR() { - f.check_list = append(f.check_list, f.parseCSR) - f.flagset.StringVar(&f.flag_container.signRequestPath, "csr-path", "", "path to the certificate sign request") +func InitFlagCSR(cmd *Command) { + cmd.Flags().StringVar(&flagContainer.signRequestPath, "csr-path", "", "path to the certificate sign request") } // parse the certificate sign request -func (f *Flags) parseCSR() error { - rest, err := ioutil.ReadFile(f.flag_container.signRequestPath) +func checkCSR() error { + rest, err := ioutil.ReadFile(flagContainer.signRequestPath) if err != nil { return fmt.Errorf("Error reading certificate sign request: %s", err) } var csr_asn1 []byte @@ -201,31 +255,29 @@ func (f *Flags) parseCSR() error { if len(csr_asn1) == 0 { return fmt.Errorf( "No certificate sign request found in %s", - f.flag_container.signRequestPath, + flagContainer.signRequestPath, ) } csr, err := pki.LoadCertificateSignRequest(csr_asn1) if err != nil { return fmt.Errorf("Invalid certificate sign request: %s", err) } - f.Flags.CertificateSignRequest = csr + FlagCertificateSignRequest = csr 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") +func InitFlagOutput(cmd *Command) { + cmd.Flags().StringVar(&flagContainer.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 +func checkOutput() error { + if flagContainer.outputPath == "STDOUT" { + FlagOutput = os.Stdout return nil } var err error - f.Flags.Output, err = os.OpenFile( - f.flag_container.outputPath, + FlagOutput, err = os.OpenFile( + flagContainer.outputPath, os.O_WRONLY | os.O_APPEND | os.O_CREATE, // do not kill users files! 0600, ) @@ -234,50 +286,49 @@ func (f *Flags) parseOutput() error { } // add the input parameter to load resources from -func (f *Flags) AddInput() { - f.check_list = append(f.check_list, f.parseInput) - f.flagset.StringVar(&f.flag_container.inputPath, "input", "STDIN", "path to the input or STDIN") +func InitFlagInput(cmd *Command) { + cmd.Flags().StringVar(&flagContainer.inputPath, "input", "STDIN", "path to the input or STDIN") } // parse the input parameter and open the file handle -func (f *Flags) parseInput() error { - if f.flag_container.inputPath == "STDIN" { - f.Flags.Input = os.Stdin +func checkInput() error { + if flagContainer.inputPath == "STDIN" { + FlagInput = os.Stdin return nil } var err error - f.Flags.Input, err = os.Open(f.flag_container.inputPath) + FlagInput, err = os.Open(flagContainer.inputPath) 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, +func InitFlagPrivateKeyGeneration(cmd *Command) { + cmd.Flags().StringVar(&flagContainer.cryptType, "type", "ecdsa", "the type of the private key (ecdsa, rsa)") + cmd.Flags().IntVar( + &flagContainer.length, "length", 521, - fmt.Sprintf("%d - %d for rsa; %v for ecdsa", RsaLowerLength, RsaUpperLength, EcdsaCurves), + fmt.Sprintf("%d - %d for rsa; one of %v for ecdsa", RsaLowerLength, RsaUpperLength, EcdsaCurves), ) } -func (f *Flags) parsePrivateKeyGenerationFlags() error { - pk_type := f.flag_container.cryptType - f.Flags.PrivateKeyGenerationFlags.Type = pk_type +// check the private key generation variables and move them to the work space +func checkPrivateKeyGeneration() error { + pk_type := flagContainer.cryptType + FlagPrivateKeyGeneration.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) + switch flagContainer.length { + case 224: FlagPrivateKeyGeneration.Curve = elliptic.P224() + case 256: FlagPrivateKeyGeneration.Curve = elliptic.P256() + case 384: FlagPrivateKeyGeneration.Curve = elliptic.P384() + case 521: FlagPrivateKeyGeneration.Curve = elliptic.P521() + default: return fmt.Errorf("Curve %d unknown!", flagContainer.length) } case "rsa": - size := f.flag_container.length + size := flagContainer.length if RsaLowerLength <= size && size <= RsaUpperLength { - f.Flags.PrivateKeyGenerationFlags.Size = size + FlagPrivateKeyGeneration.Size = size } else { return fmt.Errorf("Length of %d is not allowed for rsa!", size) } @@ -287,66 +338,64 @@ func (f *Flags) parsePrivateKeyGenerationFlags() error { } // add the signature flag to load a signature from a signing process -func (f *Flags) AddSignature() { - f.check_list = append(f.check_list, f.parseSignature) - f.flagset.StringVar(&f.flag_container.signature, "signature", "", "the base64 encoded signature to use for verification") +func InitFlagSignature(cmd *Command) { + cmd.Flags().StringVar(&flagContainer.signature, "signature", "", "the base64 encoded signature to use for verification") } // parse the signature flag -func (f *Flags) parseSignature() error { +func checkSignature() error { var err error - f.Flags.Signature, err = base64.StdEncoding.DecodeString(f.flag_container.signature) + FlagSignature, err = base64.StdEncoding.DecodeString(flagContainer.signature) if err != nil { return err } return nil } // add the certificate fields to the flags -func (f *Flags) AddCertificateFields() { - f.check_list = append(f.check_list, f.parseCertificateFields) - f.flagset.StringVar( - &f.flag_container.certificateFlags.manual.serialNumber, +func InitFlagCertificateFields(cmd *Command) { + cmd.Flags().StringVar( + &flagContainer.certificateFlags.manual.serialNumber, "serial", "1", "unique serial number of the CA"); - f.flagset.StringVar( - &f.flag_container.certificateFlags.manual.commonName, + cmd.Flags().StringVar( + &flagContainer.certificateFlags.manual.commonName, "common-name", "", "common name of the entity to certify"); - f.flagset.StringVar( - &f.flag_container.certificateFlags.manual.dnsNames, + cmd.Flags().StringVar( + &flagContainer.certificateFlags.manual.dnsNames, "dns-names", "", "comma separated list of alternative fqdn entries for the entity"); - f.flagset.StringVar( - &f.flag_container.certificateFlags.manual.emailAddresses, + cmd.Flags().StringVar( + &flagContainer.certificateFlags.manual.emailAddresses, "email-address", "", "comma separated list of alternative email entries for the entity"); - f.flagset.StringVar( - &f.flag_container.certificateFlags.manual.ipAddresses, + cmd.Flags().StringVar( + &flagContainer.certificateFlags.manual.ipAddresses, "ip-address", "", "comma separated list of alternative ip entries for the entity"); - f.flagset.StringVar( - &f.flag_container.certificateFlags.automatic.Country, + cmd.Flags().StringVar( + &flagContainer.certificateFlags.automatic.Country, "country", "", "comma separated list of countries the entitiy resides in"); - f.flagset.StringVar( - &f.flag_container.certificateFlags.automatic.Organization, + cmd.Flags().StringVar( + &flagContainer.certificateFlags.automatic.Organization, "organization", "", "comma separated list of organizations the entity belongs to"); - f.flagset.StringVar( - &f.flag_container.certificateFlags.automatic.OrganizationalUnit, + cmd.Flags().StringVar( + &flagContainer.certificateFlags.automatic.OrganizationalUnit, "organization-unit", "", "comma separated list of organization units or departments the entity belongs to"); - f.flagset.StringVar( - &f.flag_container.certificateFlags.automatic.Locality, + cmd.Flags().StringVar( + &flagContainer.certificateFlags.automatic.Locality, "locality", "", "comma separated list of localities or cities the entity resides in"); - f.flagset.StringVar( - &f.flag_container.certificateFlags.automatic.Province, + cmd.Flags().StringVar( + &flagContainer.certificateFlags.automatic.Province, "province", "", "comma separated list of provinces the entity resides in"); - f.flagset.StringVar( - &f.flag_container.certificateFlags.automatic.StreetAddress, + cmd.Flags().StringVar( + &flagContainer.certificateFlags.automatic.StreetAddress, "street-address", "", "comma separated list of street addresses the entity resides in"); - f.flagset.StringVar( - &f.flag_container.certificateFlags.automatic.PostalCode, + cmd.Flags().StringVar( + &flagContainer.certificateFlags.automatic.PostalCode, "postal-code", "", "comma separated list of postal codes of the localities"); } // parse the certificate fields into a raw certificate -func (f *Flags) parseCertificateFields() error { - f.Flags.CertificateData = pki.NewCertificateData() +func checkCertificateFields() error { + FlagCertificateData = pki.NewCertificateData() // convert the automatic flags - container_type := reflect.ValueOf(&f.flag_container.certificateFlags.automatic).Elem() - cert_data_type := reflect.ValueOf(&f.Flags.CertificateData.Subject).Elem() + container_type := reflect.ValueOf(&flagContainer.certificateFlags.automatic).Elem() + cert_data_type := reflect.ValueOf(&FlagCertificateData.Subject).Elem() for _, field := range []string{"Country", "Organization", "OrganizationalUnit", "Locality", "Province", "StreetAddress", "PostalCode"} { @@ -357,8 +406,8 @@ func (f *Flags) parseCertificateFields() error { } // convert the manual flags - data := f.Flags.CertificateData - raw_data := f.flag_container.certificateFlags.manual + data := FlagCertificateData + raw_data := flagContainer.certificateFlags.manual data.Subject.SerialNumber = raw_data.serialNumber data.Subject.CommonName = raw_data.commonName if raw_data.dnsNames != "" { diff --git a/main.go b/main.go index eb661e6..7764d69 100644 --- a/main.go +++ b/main.go @@ -8,107 +8,94 @@ import ( "io/ioutil" "math/big" "os" - "path/filepath" +// "path/filepath" "github.com/gibheer/pki" ) +const ( + ErrorProgram int = iota + ErrorFlagInput + ErrorInput +) + var ( EmptyByteArray = make([]byte, 0) ) func main() { - if len(os.Args) == 1 { - crash_with_help(1, "No module selected!") - } - switch os.Args[1] { - case "create-private": create_private_key() - case "create-public": create_public_key() - case "sign-input": sign_input() - case "verify-signature": verify_input() - case "create-cert-sign": create_sign_request() - case "create-cert": create_cert() - case "help": print_modules() - case "--help": print_modules() -// case "info": info_on_file() - default: crash_with_help(1, "Command not supported!") - } + InitFlags() + CmdRoot.Execute() } -// create a private key -func create_private_key() { - fs := NewFlags("create-private") - fs.AddOutput() - fs.AddPrivateKeyGenerationFlags() - err := fs.Parse(program_args()) - if err != nil { os.Exit(2) } +// create a new private key +func create_private_key(cmd *Command, args []string) { + err := checkFlags(checkOutput, checkPrivateKeyGeneration) + if err != nil { + crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err) + } var pk pki.Pemmer - switch fs.Flags.PrivateKeyGenerationFlags.Type { - case "ecdsa": pk, err = pki.NewPrivateKeyEcdsa(fs.Flags.PrivateKeyGenerationFlags.Curve) - case "rsa": pk, err = pki.NewPrivateKeyRsa(fs.Flags.PrivateKeyGenerationFlags.Size) + switch FlagPrivateKeyGeneration.Type { + case "ecdsa": pk, err = pki.NewPrivateKeyEcdsa(FlagPrivateKeyGeneration.Curve) + case "rsa": pk, err = pki.NewPrivateKeyRsa(FlagPrivateKeyGeneration.Size) + default: crash_with_help(cmd, ErrorInput, "Unknown private key type '%s'", FlagPrivateKeyGeneration.Type) } - if err != nil { os.Exit(2) } + if err != nil { crash_with_help(cmd, ErrorProgram, "Error creating private key: %s", err) } marsh_pem, err := pk.MarshalPem() - if err != nil { os.Exit(2) } - _, err = marsh_pem.WriteTo(fs.Flags.Output) - if err != nil { os.Exit(2) } + if err != nil { crash_with_help(cmd, ErrorProgram, "Error when marshalling to pem: %s", err) } + _, err = marsh_pem.WriteTo(FlagOutput) + if err != nil { crash_with_help(cmd, ErrorProgram, "Error when writing output: %s", err) } } // create a public key derived from a private key -func create_public_key() { - fs := NewFlags("create-public") - fs.AddPrivateKey() - fs.AddOutput() - err := fs.Parse(program_args()) - if err != nil { os.Exit(2) } +func create_public_key(cmd *Command, args []string) { + err := checkFlags(checkPrivateKey, checkOutput) + if err != nil { + crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err) + } var pub_key pki.Pemmer - pub_key = fs.Flags.PrivateKey.Public() + pub_key = FlagPrivateKey.Public() marsh_pem, err := pub_key.MarshalPem() - if err != nil { os.Exit(2) } - _, err = marsh_pem.WriteTo(fs.Flags.Output) - if err != nil { os.Exit(2) } + if err != nil { crash_with_help(cmd, ErrorProgram, "Error when marshalling to pem: %s", err) } + _, err = marsh_pem.WriteTo(FlagOutput) + if err != nil { crash_with_help(cmd, ErrorProgram, "Error when writing output: %s", err) } } // sign a message using he private key -func sign_input() { - fs := NewFlags("sign-input") - fs.AddPrivateKey() - fs.AddInput() - fs.AddOutput() - err := fs.Parse(program_args()) - if err != nil { os.Exit(2) } +func sign_input(cmd *Command, args []string) { + err := checkFlags(checkPrivateKey, checkInput, checkOutput) + if err != nil { + crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err) + } - message, err := ioutil.ReadAll(fs.Flags.Input) - if err != nil { crash_with_help(2, "Error reading input: %s", err) } - signature, err := fs.Flags.PrivateKey.Sign(message, crypto.SHA256) - if err != nil { crash_with_help(2, "Could not compute signature: %s", err) } - _, err = io.WriteString(fs.Flags.Output, base64.StdEncoding.EncodeToString(signature)) - if err != nil { crash_with_help(2, "Could not write to output: %s", err) } + message, err := ioutil.ReadAll(FlagInput) + if err != nil { crash_with_help(cmd, ErrorProgram, "Error reading input: %s", err) } + signature, err := FlagPrivateKey.Sign(message, crypto.SHA256) + if err != nil { crash_with_help(cmd, ErrorProgram, "Could not compute signature: %s", err) } + _, err = io.WriteString(FlagOutput, base64.StdEncoding.EncodeToString(signature)) + if err != nil { crash_with_help(cmd, ErrorProgram, "Could not write to output: %s", err) } // if we print to stderr, send a final line break to make the output nice - if fs.Flags.Output == os.Stdout { + if FlagOutput == os.Stdout { // we can ignore the result, as either Stdout did work or not - _, _ = io.WriteString(fs.Flags.Output, "\n") + _, _ = io.WriteString(FlagOutput, "\n") } } // verify a message using a signature and a public key -func verify_input() { - fs := NewFlags("sign-input") - fs.AddPublicKey() - fs.AddInput() - fs.AddOutput() - fs.AddSignature() - err := fs.Parse(program_args()) - if err != nil { os.Exit(2) } +func verify_input(cmd *Command, args []string) { + err := checkFlags(checkPrivateKey, checkInput, checkOutput, checkSignature) + if err != nil { + crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err) + } - signature := fs.Flags.Signature - message, err := ioutil.ReadAll(fs.Flags.Input) - if err != nil { crash_with_help(2, "Error reading input: %s", err) } - valid, err := fs.Flags.PublicKey.Verify(message, signature, crypto.SHA256) - if err != nil { crash_with_help(2, "Could not verify message with signature: %s", err) } + signature := FlagSignature + message, err := ioutil.ReadAll(FlagInput) + if err != nil { crash_with_help(cmd, ErrorProgram, "Error reading input: %s", err) } + valid, err := FlagPublicKey.Verify(message, signature, crypto.SHA256) + if err != nil { crash_with_help(cmd, ErrorProgram, "Could not verify message using signature: %s", err) } if valid { fmt.Println("valid") os.Exit(0) @@ -118,63 +105,45 @@ func verify_input() { } // create a certificate sign request -func create_sign_request() { - fs := NewFlags("create-cert-sign") - fs.AddPrivateKey() - fs.AddOutput() - fs.AddCertificateFields() - fs.Parse(program_args()) +func create_sign_request(cmd *Command, args []string) { + err := checkFlags(checkPrivateKey, checkOutput, checkCertificateFields) + if err != nil { + crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err) + } - csr, err := fs.Flags.CertificateData.ToCertificateRequest(fs.Flags.PrivateKey) - if err != nil { crash_with_help(2, "Could not create certificate sign request: %s", err) } + csr, err := FlagCertificateData.ToCertificateRequest(FlagPrivateKey) + if err != nil { crash_with_help(cmd, ErrorProgram, "Could not create certificate sign request: %s", err) } pem_block, err := csr.MarshalPem() - if err != nil { crash_with_help(2, "Could not covnert to pem: %s", err) } - _, err = pem_block.WriteTo(fs.Flags.Output) - if err != nil { crash_with_help(2, "Encoding didn't work: %s", err) } + if err != nil { crash_with_help(cmd, ErrorProgram, "Error when marshalling to pem: %s", err) } + _, err = pem_block.WriteTo(FlagOutput) + if err != nil { crash_with_help(cmd, ErrorProgram, "Could not write to output: %s", err) } } -func create_cert() { - fs := NewFlags("create-cert") - fs.AddPrivateKey() - fs.AddCSR() - fs.AddOutput() - fs.Parse(program_args()) +func create_cert(cmd *Command, args []string) { + err := checkFlags(checkPrivateKey, checkOutput, checkCSR) + if err != nil { + crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err) + } // TODO implement flags for all certificate options cert_opts := pki.CertificateOptions{} cert_opts.SerialNumber = big.NewInt(1) - cert, err := fs.Flags.CertificateSignRequest.ToCertificate( - fs.Flags.PrivateKey, + cert, err := FlagCertificateSignRequest.ToCertificate( + FlagPrivateKey, cert_opts, nil, ) - if err != nil { crash_with_help(2, "Error generating certificate: %s", err) } + if err != nil { crash_with_help(cmd, ErrorProgram, "Error generating certificate: %s", err) } pem_block, err := cert.MarshalPem() - if err != nil { crash_with_help(2, "Error converting to pem: %s", err) } - _, err = pem_block.WriteTo(fs.Flags.Output) - if err != nil { crash_with_help(2, "Output didn't work: %s", err) } -} - -// print the module help -func print_modules() { - fmt.Printf(`Usage: %s command args -where 'command' is one of: - create-private create a new private key - create-public create a public key from a private one - sign-input sign a message with a private key - verify-signature verify a signature - create-cert-sign create a new certificate sign request - create-cert sign a certificate request - help show this help - info get info on a file -`, filepath.Base(os.Args[0])) - fmt.Println() + if err != nil { crash_with_help(cmd, ErrorProgram, "Error when marshalling to pem: %s", err) } + _, err = pem_block.WriteTo(FlagOutput) + if err != nil { crash_with_help(cmd, ErrorProgram, "Could not write to output: %s", err) } } // crash and provide a helpful message -func crash_with_help(code int, message string, args ...interface{}) { +func crash_with_help(cmd *Command, code int, message string, args ...interface{}) { fmt.Fprintf(os.Stderr, message + "\n", args...) - print_modules() + cmd.Usage() os.Exit(code) }