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:
parent
ccaef440f4
commit
d983dbae54
351
flags.go
351
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 != "" {
|
||||
|
|
187
main.go
187
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)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue