0
0
Fork 0

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.
This commit is contained in:
Gibheer 2015-03-21 18:50:55 +01:00
parent ccaef440f4
commit d983dbae54
2 changed files with 278 additions and 260 deletions

351
flags.go
View File

@ -7,7 +7,6 @@ import (
"crypto/elliptic" "crypto/elliptic"
"encoding/base64" "encoding/base64"
"encoding/pem" "encoding/pem"
"flag"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -62,131 +61,186 @@ type (
signature string // a base64 encoded signature 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 { privateKeyGenerationFlags struct {
Type string // type of the private key (rsa, ecdsa) Type string // type of the private key (rsa, ecdsa)
Curve elliptic.Curve // curve for ecdsa Curve elliptic.Curve // curve for ecdsa
Size int // bitsize for rsa 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) flagCheck func()(error)
) )
// create a new flag handler with the name of the subfunction var (
func NewFlags(method_name string) *Flags { CmdRoot = &Command {
flagset := flag.NewFlagSet(method_name, flag.ExitOnError) Short: "A tool to manage keys and certificates.",
flags := &Flags{ Long: `This tool provides a way to manage private and public keys, create
Name: method_name, certificate requests and certificates and sign/verify messages.`,
Flags: &flagSet{},
flagset: flagset,
check_list: make([]flagCheck, 0),
flag_container: &paramContainer{},
} }
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 = &paramContainer{}
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 checkFlags(checks... flagCheck) error {
func (f *Flags) Parse(options []string) error { for _, check := range checks {
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 { if err := check(); err != nil {
f.Usagef("%s", err)
return err return err
} }
} }
return nil return nil
} }
// print a message with the usage part //// print a message with the usage part
func (f *Flags) Usagef(message string, args ...interface{}) { //func (f *Flags) Usagef(message string, args ...interface{}) {
fmt.Fprintf(os.Stderr, "error: " + message + "\n", args...) // fmt.Fprintf(os.Stderr, "error: " + message + "\n", args...)
f.Usage() // f.flagset.Flags().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()
}
// add the private key option to the requested flags // add the private key option to the requested flags
func (f *Flags) AddPrivateKey() { func InitFlagPrivateKey(cmd *Command) {
f.check_list = append(f.check_list, f.parsePrivateKey) cmd.Flags().StringVar(&flagContainer.privateKeyPath, "private-key", "", "path to the private key (required)")
f.flagset.StringVar(&f.flag_container.privateKeyPath, "private-key", "", "path to the private key")
} }
// check the private key flag and load the private key // check the private key flag and load the private key
func (f *Flags) parsePrivateKey() error { func checkPrivateKey() error {
if f.flag_container.privateKeyPath == "" { return fmt.Errorf("No private key given!") } if flagContainer.privateKeyPath == "" { return fmt.Errorf("No private key given!") }
// check permissions of private key file // 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 err != nil { return fmt.Errorf("Error reading private key: %s", err) }
if info.Mode().Perm().String()[4:] != "------" { if info.Mode().Perm().String()[4:] != "------" {
return fmt.Errorf("private key file modifyable by others!") 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) } if err != nil { return fmt.Errorf("Error reading private key: %s", err) }
f.Flags.PrivateKey = pk FlagPrivateKey = pk
return nil return nil
} }
// add the public key flag // add the public key flag
func (f *Flags) AddPublicKey() { func InitFlagPublicKey(cmd *Command) {
f.check_list = append(f.check_list, f.parsePublicKey) cmd.Flags().StringVar(&flagContainer.publicKeyPath, "public-key", "", "path to the public key (required)")
f.flagset.StringVar(&f.flag_container.publicKeyPath, "public-key", "", "path to the public key")
} }
// parse public key flag // parse public key flag
func (f *Flags) parsePublicKey() error { func checkPublicKey() error {
if f.flag_container.publicKeyPath == "" { return fmt.Errorf("No public key given!") } 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) } if err != nil { return fmt.Errorf("Error reading public key: %s", err) }
f.Flags.PublicKey = pu FlagPublicKey = pu
return nil return nil
} }
// add flag to load certificate sign request // add flag to load certificate sign request
func (f *Flags) AddCSR() { func InitFlagCSR(cmd *Command) {
f.check_list = append(f.check_list, f.parseCSR) cmd.Flags().StringVar(&flagContainer.signRequestPath, "csr-path", "", "path to the certificate sign request")
f.flagset.StringVar(&f.flag_container.signRequestPath, "csr-path", "", "path to the certificate sign request")
} }
// parse the certificate sign request // parse the certificate sign request
func (f *Flags) parseCSR() error { func checkCSR() error {
rest, err := ioutil.ReadFile(f.flag_container.signRequestPath) rest, err := ioutil.ReadFile(flagContainer.signRequestPath)
if err != nil { return fmt.Errorf("Error reading certificate sign request: %s", err) } if err != nil { return fmt.Errorf("Error reading certificate sign request: %s", err) }
var csr_asn1 []byte var csr_asn1 []byte
@ -201,31 +255,29 @@ func (f *Flags) parseCSR() error {
if len(csr_asn1) == 0 { if len(csr_asn1) == 0 {
return fmt.Errorf( return fmt.Errorf(
"No certificate sign request found in %s", "No certificate sign request found in %s",
f.flag_container.signRequestPath, flagContainer.signRequestPath,
) )
} }
csr, err := pki.LoadCertificateSignRequest(csr_asn1) csr, err := pki.LoadCertificateSignRequest(csr_asn1)
if err != nil { return fmt.Errorf("Invalid certificate sign request: %s", err) } if err != nil { return fmt.Errorf("Invalid certificate sign request: %s", err) }
f.Flags.CertificateSignRequest = csr FlagCertificateSignRequest = csr
return nil return nil
} }
// add the output parameter to the checklist func InitFlagOutput(cmd *Command) {
func (f *Flags) AddOutput() { cmd.Flags().StringVar(&flagContainer.outputPath, "output", "STDOUT", "path to the output or STDOUT")
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 // parse the output parameter and open the file handle
func (f *Flags) parseOutput() error { func checkOutput() error {
if f.flag_container.outputPath == "STDOUT" { if flagContainer.outputPath == "STDOUT" {
f.Flags.Output = os.Stdout FlagOutput = os.Stdout
return nil return nil
} }
var err error var err error
f.Flags.Output, err = os.OpenFile( FlagOutput, err = os.OpenFile(
f.flag_container.outputPath, flagContainer.outputPath,
os.O_WRONLY | os.O_APPEND | os.O_CREATE, // do not kill users files! os.O_WRONLY | os.O_APPEND | os.O_CREATE, // do not kill users files!
0600, 0600,
) )
@ -234,50 +286,49 @@ func (f *Flags) parseOutput() error {
} }
// add the input parameter to load resources from // add the input parameter to load resources from
func (f *Flags) AddInput() { func InitFlagInput(cmd *Command) {
f.check_list = append(f.check_list, f.parseInput) cmd.Flags().StringVar(&flagContainer.inputPath, "input", "STDIN", "path to the input or STDIN")
f.flagset.StringVar(&f.flag_container.inputPath, "input", "STDIN", "path to the input or STDIN")
} }
// parse the input parameter and open the file handle // parse the input parameter and open the file handle
func (f *Flags) parseInput() error { func checkInput() error {
if f.flag_container.inputPath == "STDIN" { if flagContainer.inputPath == "STDIN" {
f.Flags.Input = os.Stdin FlagInput = os.Stdin
return nil return nil
} }
var err error var err error
f.Flags.Input, err = os.Open(f.flag_container.inputPath) FlagInput, err = os.Open(flagContainer.inputPath)
if err != nil { return err } if err != nil { return err }
return nil return nil
} }
// This function adds the private key generation flags. // This function adds the private key generation flags.
func (f *Flags) AddPrivateKeyGenerationFlags() { func InitFlagPrivateKeyGeneration(cmd *Command) {
f.check_list = append(f.check_list, f.parsePrivateKeyGenerationFlags) cmd.Flags().StringVar(&flagContainer.cryptType, "type", "ecdsa", "the type of the private key (ecdsa, rsa)")
f.flagset.StringVar(&f.flag_container.cryptType, "type", "ecdsa", "the type of the private key (ecdsa, rsa)") cmd.Flags().IntVar(
f.flagset.IntVar( &flagContainer.length,
&f.flag_container.length,
"length", 521, "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 { // check the private key generation variables and move them to the work space
pk_type := f.flag_container.cryptType func checkPrivateKeyGeneration() error {
f.Flags.PrivateKeyGenerationFlags.Type = pk_type pk_type := flagContainer.cryptType
FlagPrivateKeyGeneration.Type = pk_type
switch pk_type { switch pk_type {
case "ecdsa": case "ecdsa":
switch f.flag_container.length { switch flagContainer.length {
case 224: f.Flags.PrivateKeyGenerationFlags.Curve = elliptic.P224() case 224: FlagPrivateKeyGeneration.Curve = elliptic.P224()
case 256: f.Flags.PrivateKeyGenerationFlags.Curve = elliptic.P256() case 256: FlagPrivateKeyGeneration.Curve = elliptic.P256()
case 384: f.Flags.PrivateKeyGenerationFlags.Curve = elliptic.P384() case 384: FlagPrivateKeyGeneration.Curve = elliptic.P384()
case 521: f.Flags.PrivateKeyGenerationFlags.Curve = elliptic.P521() case 521: FlagPrivateKeyGeneration.Curve = elliptic.P521()
default: return fmt.Errorf("Curve %d unknown!", f.flag_container.length) default: return fmt.Errorf("Curve %d unknown!", flagContainer.length)
} }
case "rsa": case "rsa":
size := f.flag_container.length size := flagContainer.length
if RsaLowerLength <= size && size <= RsaUpperLength { if RsaLowerLength <= size && size <= RsaUpperLength {
f.Flags.PrivateKeyGenerationFlags.Size = size FlagPrivateKeyGeneration.Size = size
} else { } else {
return fmt.Errorf("Length of %d is not allowed for rsa!", size) 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 // add the signature flag to load a signature from a signing process
func (f *Flags) AddSignature() { func InitFlagSignature(cmd *Command) {
f.check_list = append(f.check_list, f.parseSignature) cmd.Flags().StringVar(&flagContainer.signature, "signature", "", "the base64 encoded signature to use for verification")
f.flagset.StringVar(&f.flag_container.signature, "signature", "", "the base64 encoded signature to use for verification")
} }
// parse the signature flag // parse the signature flag
func (f *Flags) parseSignature() error { func checkSignature() error {
var err 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 } if err != nil { return err }
return nil return nil
} }
// add the certificate fields to the flags // add the certificate fields to the flags
func (f *Flags) AddCertificateFields() { func InitFlagCertificateFields(cmd *Command) {
f.check_list = append(f.check_list, f.parseCertificateFields) cmd.Flags().StringVar(
f.flagset.StringVar( &flagContainer.certificateFlags.manual.serialNumber,
&f.flag_container.certificateFlags.manual.serialNumber,
"serial", "1", "unique serial number of the CA"); "serial", "1", "unique serial number of the CA");
f.flagset.StringVar( cmd.Flags().StringVar(
&f.flag_container.certificateFlags.manual.commonName, &flagContainer.certificateFlags.manual.commonName,
"common-name", "", "common name of the entity to certify"); "common-name", "", "common name of the entity to certify");
f.flagset.StringVar( cmd.Flags().StringVar(
&f.flag_container.certificateFlags.manual.dnsNames, &flagContainer.certificateFlags.manual.dnsNames,
"dns-names", "", "comma separated list of alternative fqdn entries for the entity"); "dns-names", "", "comma separated list of alternative fqdn entries for the entity");
f.flagset.StringVar( cmd.Flags().StringVar(
&f.flag_container.certificateFlags.manual.emailAddresses, &flagContainer.certificateFlags.manual.emailAddresses,
"email-address", "", "comma separated list of alternative email entries for the entity"); "email-address", "", "comma separated list of alternative email entries for the entity");
f.flagset.StringVar( cmd.Flags().StringVar(
&f.flag_container.certificateFlags.manual.ipAddresses, &flagContainer.certificateFlags.manual.ipAddresses,
"ip-address", "", "comma separated list of alternative ip entries for the entity"); "ip-address", "", "comma separated list of alternative ip entries for the entity");
f.flagset.StringVar( cmd.Flags().StringVar(
&f.flag_container.certificateFlags.automatic.Country, &flagContainer.certificateFlags.automatic.Country,
"country", "", "comma separated list of countries the entitiy resides in"); "country", "", "comma separated list of countries the entitiy resides in");
f.flagset.StringVar( cmd.Flags().StringVar(
&f.flag_container.certificateFlags.automatic.Organization, &flagContainer.certificateFlags.automatic.Organization,
"organization", "", "comma separated list of organizations the entity belongs to"); "organization", "", "comma separated list of organizations the entity belongs to");
f.flagset.StringVar( cmd.Flags().StringVar(
&f.flag_container.certificateFlags.automatic.OrganizationalUnit, &flagContainer.certificateFlags.automatic.OrganizationalUnit,
"organization-unit", "", "comma separated list of organization units or departments the entity belongs to"); "organization-unit", "", "comma separated list of organization units or departments the entity belongs to");
f.flagset.StringVar( cmd.Flags().StringVar(
&f.flag_container.certificateFlags.automatic.Locality, &flagContainer.certificateFlags.automatic.Locality,
"locality", "", "comma separated list of localities or cities the entity resides in"); "locality", "", "comma separated list of localities or cities the entity resides in");
f.flagset.StringVar( cmd.Flags().StringVar(
&f.flag_container.certificateFlags.automatic.Province, &flagContainer.certificateFlags.automatic.Province,
"province", "", "comma separated list of provinces the entity resides in"); "province", "", "comma separated list of provinces the entity resides in");
f.flagset.StringVar( cmd.Flags().StringVar(
&f.flag_container.certificateFlags.automatic.StreetAddress, &flagContainer.certificateFlags.automatic.StreetAddress,
"street-address", "", "comma separated list of street addresses the entity resides in"); "street-address", "", "comma separated list of street addresses the entity resides in");
f.flagset.StringVar( cmd.Flags().StringVar(
&f.flag_container.certificateFlags.automatic.PostalCode, &flagContainer.certificateFlags.automatic.PostalCode,
"postal-code", "", "comma separated list of postal codes of the localities"); "postal-code", "", "comma separated list of postal codes of the localities");
} }
// parse the certificate fields into a raw certificate // parse the certificate fields into a raw certificate
func (f *Flags) parseCertificateFields() error { func checkCertificateFields() error {
f.Flags.CertificateData = pki.NewCertificateData() FlagCertificateData = pki.NewCertificateData()
// convert the automatic flags // convert the automatic flags
container_type := reflect.ValueOf(&f.flag_container.certificateFlags.automatic).Elem() container_type := reflect.ValueOf(&flagContainer.certificateFlags.automatic).Elem()
cert_data_type := reflect.ValueOf(&f.Flags.CertificateData.Subject).Elem() cert_data_type := reflect.ValueOf(&FlagCertificateData.Subject).Elem()
for _, field := range []string{"Country", "Organization", "OrganizationalUnit", for _, field := range []string{"Country", "Organization", "OrganizationalUnit",
"Locality", "Province", "StreetAddress", "PostalCode"} { "Locality", "Province", "StreetAddress", "PostalCode"} {
@ -357,8 +406,8 @@ func (f *Flags) parseCertificateFields() error {
} }
// convert the manual flags // convert the manual flags
data := f.Flags.CertificateData data := FlagCertificateData
raw_data := f.flag_container.certificateFlags.manual raw_data := flagContainer.certificateFlags.manual
data.Subject.SerialNumber = raw_data.serialNumber data.Subject.SerialNumber = raw_data.serialNumber
data.Subject.CommonName = raw_data.commonName data.Subject.CommonName = raw_data.commonName
if raw_data.dnsNames != "" { if raw_data.dnsNames != "" {

187
main.go
View File

@ -8,107 +8,94 @@ import (
"io/ioutil" "io/ioutil"
"math/big" "math/big"
"os" "os"
"path/filepath" // "path/filepath"
"github.com/gibheer/pki" "github.com/gibheer/pki"
) )
const (
ErrorProgram int = iota
ErrorFlagInput
ErrorInput
)
var ( var (
EmptyByteArray = make([]byte, 0) EmptyByteArray = make([]byte, 0)
) )
func main() { func main() {
if len(os.Args) == 1 { InitFlags()
crash_with_help(1, "No module selected!") CmdRoot.Execute()
}
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!")
}
} }
// create a private key // create a new private key
func create_private_key() { func create_private_key(cmd *Command, args []string) {
fs := NewFlags("create-private") err := checkFlags(checkOutput, checkPrivateKeyGeneration)
fs.AddOutput() if err != nil {
fs.AddPrivateKeyGenerationFlags() crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err)
err := fs.Parse(program_args()) }
if err != nil { os.Exit(2) }
var pk pki.Pemmer var pk pki.Pemmer
switch fs.Flags.PrivateKeyGenerationFlags.Type { switch FlagPrivateKeyGeneration.Type {
case "ecdsa": pk, err = pki.NewPrivateKeyEcdsa(fs.Flags.PrivateKeyGenerationFlags.Curve) case "ecdsa": pk, err = pki.NewPrivateKeyEcdsa(FlagPrivateKeyGeneration.Curve)
case "rsa": pk, err = pki.NewPrivateKeyRsa(fs.Flags.PrivateKeyGenerationFlags.Size) 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() marsh_pem, err := pk.MarshalPem()
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(fs.Flags.Output) _, err = marsh_pem.WriteTo(FlagOutput)
if err != nil { os.Exit(2) } if err != nil { crash_with_help(cmd, ErrorProgram, "Error when writing output: %s", err) }
} }
// create a public key derived from a private key // create a public key derived from a private key
func create_public_key() { func create_public_key(cmd *Command, args []string) {
fs := NewFlags("create-public") err := checkFlags(checkPrivateKey, checkOutput)
fs.AddPrivateKey() if err != nil {
fs.AddOutput() crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err)
err := fs.Parse(program_args()) }
if err != nil { os.Exit(2) }
var pub_key pki.Pemmer var pub_key pki.Pemmer
pub_key = fs.Flags.PrivateKey.Public() pub_key = FlagPrivateKey.Public()
marsh_pem, err := pub_key.MarshalPem() marsh_pem, err := pub_key.MarshalPem()
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(fs.Flags.Output) _, err = marsh_pem.WriteTo(FlagOutput)
if err != nil { os.Exit(2) } if err != nil { crash_with_help(cmd, ErrorProgram, "Error when writing output: %s", err) }
} }
// sign a message using he private key // sign a message using he private key
func sign_input() { func sign_input(cmd *Command, args []string) {
fs := NewFlags("sign-input") err := checkFlags(checkPrivateKey, checkInput, checkOutput)
fs.AddPrivateKey() if err != nil {
fs.AddInput() crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err)
fs.AddOutput() }
err := fs.Parse(program_args())
if err != nil { os.Exit(2) }
message, err := ioutil.ReadAll(fs.Flags.Input) message, err := ioutil.ReadAll(FlagInput)
if err != nil { crash_with_help(2, "Error reading input: %s", err) } if err != nil { crash_with_help(cmd, ErrorProgram, "Error reading input: %s", err) }
signature, err := fs.Flags.PrivateKey.Sign(message, crypto.SHA256) signature, err := FlagPrivateKey.Sign(message, crypto.SHA256)
if err != nil { crash_with_help(2, "Could not compute signature: %s", err) } if err != nil { crash_with_help(cmd, ErrorProgram, "Could not compute signature: %s", err) }
_, err = io.WriteString(fs.Flags.Output, base64.StdEncoding.EncodeToString(signature)) _, err = io.WriteString(FlagOutput, base64.StdEncoding.EncodeToString(signature))
if err != nil { crash_with_help(2, "Could not write to output: %s", err) } 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 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 // 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 // verify a message using a signature and a public key
func verify_input() { func verify_input(cmd *Command, args []string) {
fs := NewFlags("sign-input") err := checkFlags(checkPrivateKey, checkInput, checkOutput, checkSignature)
fs.AddPublicKey() if err != nil {
fs.AddInput() crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err)
fs.AddOutput() }
fs.AddSignature()
err := fs.Parse(program_args())
if err != nil { os.Exit(2) }
signature := fs.Flags.Signature signature := FlagSignature
message, err := ioutil.ReadAll(fs.Flags.Input) message, err := ioutil.ReadAll(FlagInput)
if err != nil { crash_with_help(2, "Error reading input: %s", err) } if err != nil { crash_with_help(cmd, ErrorProgram, "Error reading input: %s", err) }
valid, err := fs.Flags.PublicKey.Verify(message, signature, crypto.SHA256) valid, err := FlagPublicKey.Verify(message, signature, crypto.SHA256)
if err != nil { crash_with_help(2, "Could not verify message with signature: %s", err) } if err != nil { crash_with_help(cmd, ErrorProgram, "Could not verify message using signature: %s", err) }
if valid { if valid {
fmt.Println("valid") fmt.Println("valid")
os.Exit(0) os.Exit(0)
@ -118,63 +105,45 @@ func verify_input() {
} }
// create a certificate sign request // create a certificate sign request
func create_sign_request() { func create_sign_request(cmd *Command, args []string) {
fs := NewFlags("create-cert-sign") err := checkFlags(checkPrivateKey, checkOutput, checkCertificateFields)
fs.AddPrivateKey() if err != nil {
fs.AddOutput() crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err)
fs.AddCertificateFields() }
fs.Parse(program_args())
csr, err := fs.Flags.CertificateData.ToCertificateRequest(fs.Flags.PrivateKey) csr, err := FlagCertificateData.ToCertificateRequest(FlagPrivateKey)
if err != nil { crash_with_help(2, "Could not create certificate sign request: %s", err) } if err != nil { crash_with_help(cmd, ErrorProgram, "Could not create certificate sign request: %s", err) }
pem_block, err := csr.MarshalPem() pem_block, err := csr.MarshalPem()
if err != nil { crash_with_help(2, "Could not covnert to pem: %s", err) } if err != nil { crash_with_help(cmd, ErrorProgram, "Error when marshalling to pem: %s", err) }
_, err = pem_block.WriteTo(fs.Flags.Output) _, err = pem_block.WriteTo(FlagOutput)
if err != nil { crash_with_help(2, "Encoding didn't work: %s", err) } if err != nil { crash_with_help(cmd, ErrorProgram, "Could not write to output: %s", err) }
} }
func create_cert() { func create_cert(cmd *Command, args []string) {
fs := NewFlags("create-cert") err := checkFlags(checkPrivateKey, checkOutput, checkCSR)
fs.AddPrivateKey() if err != nil {
fs.AddCSR() crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err)
fs.AddOutput() }
fs.Parse(program_args())
// TODO implement flags for all certificate options // TODO implement flags for all certificate options
cert_opts := pki.CertificateOptions{} cert_opts := pki.CertificateOptions{}
cert_opts.SerialNumber = big.NewInt(1) cert_opts.SerialNumber = big.NewInt(1)
cert, err := fs.Flags.CertificateSignRequest.ToCertificate( cert, err := FlagCertificateSignRequest.ToCertificate(
fs.Flags.PrivateKey, FlagPrivateKey,
cert_opts, cert_opts,
nil, 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() pem_block, err := cert.MarshalPem()
if err != nil { crash_with_help(2, "Error converting to pem: %s", err) } if err != nil { crash_with_help(cmd, ErrorProgram, "Error when marshalling to pem: %s", err) }
_, err = pem_block.WriteTo(fs.Flags.Output) _, err = pem_block.WriteTo(FlagOutput)
if err != nil { crash_with_help(2, "Output didn't work: %s", err) } if err != nil { crash_with_help(cmd, ErrorProgram, "Could not write to output: %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()
} }
// crash and provide a helpful message // 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...) fmt.Fprintf(os.Stderr, message + "\n", args...)
print_modules() cmd.Usage()
os.Exit(code) os.Exit(code)
} }