From 16eb14db9f9b228ef88bcf1beb09cf823256dac1 Mon Sep 17 00:00:00 2001 From: Gibheer Date: Sun, 15 Feb 2015 01:34:25 +0100 Subject: [PATCH] redesign cli This is a major rebuilding of the CLI. The library part is split out into pkilib and the cli handles only the communication with the user, I/O and the library. The API will still look the same, but the code should be much better to grasp. Instead of repeating everything, more will be grouped together and reused. --- create_sign_request.go | 118 ------------------------- create_sign_request_test.go | 84 ------------------ flags.go | 168 ++++++++++++++++++++++++++++++++++++ io.go | 41 +++++++++ main.go | 91 ++++++++++--------- private_key.go | 156 +++++---------------------------- public_key.go | 50 ----------- sign_input.go | 103 ---------------------- sign_request.go | 10 --- verify_signature.go | 161 ---------------------------------- 10 files changed, 282 insertions(+), 700 deletions(-) delete mode 100644 create_sign_request.go delete mode 100644 create_sign_request_test.go create mode 100644 flags.go create mode 100644 io.go delete mode 100644 public_key.go delete mode 100644 sign_input.go delete mode 100644 sign_request.go delete mode 100644 verify_signature.go diff --git a/create_sign_request.go b/create_sign_request.go deleted file mode 100644 index 75b7993..0000000 --- a/create_sign_request.go +++ /dev/null @@ -1,118 +0,0 @@ -package main - -// create a sign request needed for the final certificate - -import ( - "crypto" - "crypto/rand" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "fmt" - "flag" - "io" - "net" - "os" - "reflect" - "regexp" -) - -type ( - SignFlags struct { - PrivateKeyPath string // path to the private key - Output string // path where to store the CSR - BaseAttributes pkix.Name - DNSNames []string // alternative names to the BaseAttributes.CommonName - IPAddresses []net.IP // alternative IP addresses - - private_key crypto.Signer - output_stream io.Writer // the output stream for the CSR - } -) - -var ( - COMMA_SPLIT = regexp.MustCompile(`,[[:space:]]?`) -) - -// create a sign request with a private key -func create_sign_request() { - flags := parse_sign_flags() - flags.private_key = load_private_key(flags.PrivateKeyPath) - - stream, err := open_output_stream(flags.Output) - if err != nil { - crash_with_help(2, fmt.Sprintf("Error when creating file %s: %s", flags.Output, err)) - } - defer stream.Close() - flags.output_stream = stream - - if err = create_csr(flags); err != nil { - fmt.Fprintln(os.Stderr, "Error when generating CSR: ", err) - os.Exit(3) - } -} - -// parse the flags to create a certificate sign request -func parse_sign_flags() SignFlags { - dns_names := "" // string to hold the alternative names - ips := "" // string to hold the alternative ips - var container struct { - Country, Organization, OrganizationalUnit, Locality, Province, - StreetAddress, PostalCode string - } - - flags := SignFlags{} - fs := flag.NewFlagSet("create-cert-sign", flag.ExitOnError) - fs.StringVar(&flags.PrivateKeyPath, "private-key", "", "path to the private key file") - fs.StringVar(&flags.Output, "output", "STDOUT", "path where the generated csr should be stored") - - flags.BaseAttributes = pkix.Name{} - fs.StringVar(&flags.BaseAttributes.CommonName, "common-name", "", "the name of the resource") - fs.StringVar(&flags.BaseAttributes.SerialNumber, "serial", "1", "serial number for the request") - fs.StringVar(&dns_names, "names", "", "alternative names (comma separated)") - fs.StringVar(&ips, "ips", "", "alternative IPs (comma separated)") - fs.StringVar(&container.Country, "country", "", "country of the organization") - fs.StringVar(&container.Organization, "organization", "", "the name of the organization") - fs.StringVar(&container.OrganizationalUnit, "org-unit", "", "the organizational unit") - fs.StringVar(&container.Locality, "city", "", "the city or locality") - fs.StringVar(&container.Province, "province", "", "the province") - fs.StringVar(&container.StreetAddress, "street", "", "the street address for the cert") - fs.StringVar(&container.PostalCode, "postal-code", "", "the postal code of the city") - fs.Parse(os.Args[2:]) - - // convert array flags to config structs - if dns_names != "" { - flags.DNSNames = COMMA_SPLIT.Split(dns_names, -1) - } - if ips != "" { - tmp_ips := COMMA_SPLIT.Split(ips, -1) - for _, sip := range tmp_ips { - flags.IPAddresses = append(flags.IPAddresses, net.ParseIP(sip)) - } - } - - container_type := reflect.ValueOf(container) - config_type := reflect.ValueOf(&flags.BaseAttributes).Elem() - for i := 0; i < container_type.NumField(); i++ { - field := container_type.Field(i) - new_field := config_type.FieldByName(container_type.Type().Field(i).Name) - new_field.Set(reflect.ValueOf(COMMA_SPLIT.Split(field.String(), -1))) - } - - return flags -} - -// generate the csr and print into flags.output_stream -func create_csr(flags SignFlags) (error) { - csr_template := &x509.CertificateRequest{ - Subject: flags.BaseAttributes, - DNSNames: flags.DNSNames, - IPAddresses: flags.IPAddresses, - } - csr_raw, err := x509.CreateCertificateRequest(rand.Reader, csr_template, flags.private_key) - if err != nil { return err } - - block := &pem.Block{Type: TypeLabelCSR, Bytes: csr_raw} - pem.Encode(flags.output_stream, block) - return nil -} diff --git a/create_sign_request_test.go b/create_sign_request_test.go deleted file mode 100644 index fef7db5..0000000 --- a/create_sign_request_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package main - -import ( - "bytes" - "crypto/x509" - "encoding/pem" - "io/ioutil" - "net" - "testing" -) - -type CSRTest struct { - ShouldBe []string - Set func(*SignFlags) - Fetch func(*x509.CertificateRequest) []string -} - -const ( - RAW_PRIVATE_KEY = `-----BEGIN EC PRIVATE KEY----- -MIHbAgEBBEFkAEFc5264Yo7Xo+yj3ZwaqdffTphGT3/8Q+pvi4ULmXaFiGoTkR5X -lKnlRUEp0I4Ra9U7GjLDtFLwTaLzdXuUT6AHBgUrgQQAI6GBiQOBhgAEAdW0usq0 -zEzvhR0u5ZSbOXRzg+TbICZGfOLy9KpKfz6I6suFOAO7f3fwDNOqMfyYUhtenMz7 -T/BKArg+v58UWHrwAb/UeI4l+OMOoMHYtNNO4nAjTdyY8yFSFY5syzKEYIBzUoLM -VSfuxBk5ZS2J478X1Vxacq03keDeAY43Oc80XBih ------END EC PRIVATE KEY-----` -) - -func SetupTest() (*SignFlags, *bytes.Buffer) { - p, _ := pem.Decode([]byte(RAW_PRIVATE_KEY)) - buf := bytes.NewBuffer(make([]byte, 0)) - - flags := &SignFlags{ - private_key: load_private_key_ecdsa(p), - output_stream: buf, - } - return flags, buf -} - -func TestCSRGeneration(t *testing.T) { - tests := []CSRTest { - { - []string{"foo"}, - func(f *SignFlags) { f.BaseAttributes.CommonName = "foo" }, - func(c *x509.CertificateRequest) []string { return []string{c.Subject.CommonName} }, - }, { - []string{"foo.com", "bar.com", "baz.com"}, - func(f *SignFlags) { f.DNSNames = []string{ "foo.com", "bar.com", "baz.com" }}, - func(c *x509.CertificateRequest) []string { return c.DNSNames }, - }, - { - []string{"127.0.0.1", "192.168.0.1"}, - func(f *SignFlags) { f.IPAddresses = []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("192.168.0.1") }}, - func(c *x509.CertificateRequest) []string { - res := make([]string, 0) - for _, ip := range c.IPAddresses { - res = append(res, ip.String()) - } - return res - }, - }, - } - for _, test := range tests { - flags, io := SetupTest() - test.Set(flags) - - create_csr(*flags) - res, _ := ioutil.ReadAll(io) - raw, _ := pem.Decode(res) - - csr, _ := x509.ParseCertificateRequest(raw.Bytes) - if !diff(test.ShouldBe, test.Fetch(csr)) { - t.Logf("Expected: %v\nbut got: %v", test.ShouldBe, test.Fetch(csr)) - t.Fail() - } - } -} - -func diff(a, b []string) bool { - if len(a) != len(b) { return false } - for i, e := range a { - if e != b[i] { return false } - } - return true -} 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 +} diff --git a/io.go b/io.go new file mode 100644 index 0000000..382044e --- /dev/null +++ b/io.go @@ -0,0 +1,41 @@ +package main + +// handle all io and de/encoding of data + +import ( + "encoding/pem" + "errors" + "io/ioutil" +) + +var ( + ErrBlockNotFound = errors.New("block not found") +) + +// load a pem section from a file +func readSectionFromFile(path, btype string) ([]byte, error) { + raw, err := readFile(path) + if err != nil { return raw, err } + + return decodeSection(raw, btype) +} + +// read a file completely and report possible errors +func readFile(path string) ([]byte, error) { + raw, err := ioutil.ReadFile(path) + if err != nil { return EmptyByteArray, err } + return raw, nil +} + +// decode a pem encoded file and search for the specified section +func decodeSection(data []byte, btype string) ([]byte, error) { + rest := data + for len(rest) > 0 { + var block *pem.Block + block, rest = pem.Decode(rest) + if block.Type == btype { + return block.Bytes, nil + } + } + return EmptyByteArray, ErrBlockNotFound +} diff --git a/main.go b/main.go index 7a6bc5e..7ee9396 100644 --- a/main.go +++ b/main.go @@ -2,69 +2,74 @@ package main import ( "fmt" - "io" "os" "path/filepath" -) -const ( - RsaLowerLength = 2048 - RsaUpperLength = 4096 - TypeLabelRSA = "RSA PRIVATE KEY" - TypeLabelECDSA = "EC PRIVATE KEY" - TypeLabelCSR = "CERTIFICATE REQUEST" - TypeLabelPubKey = "PUBLIC KEY" + "github.com/gibheer/pkilib" ) var ( - EcdsaLength = []int{224, 256, 384, 521} + EmptyByteArray = make([]byte, 0) ) +//const ( +// RsaLowerLength = 2048 +// RsaUpperLength = 4096 +// TypeLabelRSA = "RSA PRIVATE KEY" +// TypeLabelECDSA = "EC PRIVATE KEY" +// TypeLabelCSR = "CERTIFICATE REQUEST" +// TypeLabelPubKey = "PUBLIC KEY" +//) +// +//var ( +// EcdsaLength = []int{224, 256, 384, 521} +//) +// 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-cert-sign": create_sign_request() case "create-public": create_public_key() - case "help": print_modules() - case "info": info_on_file() - case "sign-request": sign_request() - case "sign-input": sign_input() - case "verify-signature": verify_signature() +// case "create-cert-sign": create_sign_request() +// case "help": print_modules() +// case "info": info_on_file() +// case "sign-request": sign_request() +// case "sign-input": sign_input() +// case "verify-signature": verify_signature() default: crash_with_help(1, "Command not supported!") } } -// get information on file (private key, sign request, certificate, ...) -func info_on_file() {} -// sign a certificate request to create a new certificate -func sign_request() {} +// create a private key +func create_private_key() { + fs := NewFlags("create-private") + fs.AddOutput() + fs.AddPrivateKeyGenerationFlags() + err := fs.Parse(program_args()) + if err != nil { crash_with_help(1, fmt.Sprintf("%s", err)) } -// open stream for given path -func open_output_stream(path string) (io.WriteCloser, error) { - switch path { - case "STDOUT": return os.Stdout, nil - case "STDERR": return os.Stderr, nil - default: return open_stream(path, os.O_WRONLY | os.O_CREATE | os.O_TRUNC) + var pk pkilib.Pemmer + switch fs.Flags.PrivateKeyGenerationFlags.Type { + case "ecdsa": pk, err = pkilib.NewPrivateKeyEcdsa(fs.Flags.PrivateKeyGenerationFlags.Curve) + case "rsa": pk, err = pkilib.NewPrivateKeyRsa(fs.Flags.PrivateKeyGenerationFlags.Size) } + if err != nil { crash_with_help(2, fmt.Sprintf("%s", err)) } + marsh_pem, err := pk.MarshalPem() + if err != nil { crash_with_help(2, fmt.Sprintf("%s", err)) } + _, err = marsh_pem.WriteTo(fs.Flags.Output) + if err != nil { crash_with_help(2, fmt.Sprintf("%s", err)) } } -func open_input_stream(path string) (io.ReadCloser, error) { - switch path { - case "STDIN": return os.Stdin, nil - default: return open_stream(path, os.O_RDONLY) - } -} +// create a public key derived from a private key +func create_public_key() { + fs := NewFlags("create-public") + fs.AddPrivateKey() + err := fs.Parse(program_args()) + if err != nil { crash_with_help(1, fmt.Sprintf("%s", err)) } -func open_stream(path string, flags int) (io.ReadWriteCloser, error) { - var err error - output_stream, err := os.OpenFile(path, flags, 0600) - if err != nil { - return nil, err - } - return output_stream, nil + fmt.Println(fs.Flags.PrivateKey.Public()) } // print the module help @@ -76,15 +81,21 @@ where 'command' is one of: create-cert-sign create a new certificate sign request help show this help info get info on a file - sign sign a certificate request + sign-request sign a certificate request sign-input sign a message with a private key verify-signature verify a signature `, filepath.Base(os.Args[0])) fmt.Println() } +// crash and provide a helpful message func crash_with_help(code int, message string) { fmt.Fprintln(os.Stderr, message) print_modules() os.Exit(code) } + +// return the arguments to the program +func program_args() []string { + return os.Args[2:] +} diff --git a/private_key.go b/private_key.go index 785b305..07ec3f8 100644 --- a/private_key.go +++ b/private_key.go @@ -1,145 +1,33 @@ package main -// generate an ecdsa or rsa private key - import ( - "crypto" - "crypto/elliptic" - "crypto/ecdsa" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "encoding/pem" - "flag" - "fmt" - "io" - "io/ioutil" - "os" + "errors" + "github.com/gibheer/pkilib" ) -type ( - CreateFlags struct { - CryptType string // rsa or ecdsa - CryptLength int // the bit length - Output string // a path or stream to output the private key to - - output_stream io.WriteCloser // the actual stream to the output - } +const ( + TypeLabelRSA = "RSA PRIVATE KEY" + TypeLabelECDSA = "EC PRIVATE KEY" ) -// create a new private key -func create_private_key() { - flags := parse_create_flags() +var ( + ErrNoPKFound = errors.New("no private key found") +) - var err error - flags.output_stream, err = open_output_stream(flags.Output) - if err != nil { - crash_with_help(2, fmt.Sprintf("Error when creating file %s: %s", flags.Output, err)) +// Read the private key from the path and try to figure out which type of key it +// might be. +func ReadPrivateKeyFile(path string) (pkilib.PrivateKey, error) { + raw_pk, err := readSectionFromFile(path, TypeLabelECDSA) + if err == nil { + pk, err := pkilib.LoadPrivateKeyEcdsa(raw_pk) + if err != nil { return nil, err } + return pk, nil } - defer flags.output_stream.Close() - - switch flags.CryptType { - case "rsa": create_private_key_rsa(flags) - case "ecdsa": create_private_key_ecdsa(flags) - default: crash_with_help(2, fmt.Sprintf("%s not supported!", flags.CryptType)) + raw_pk, err = readSectionFromFile(path, TypeLabelRSA) + if err == nil { + pk, err := pkilib.LoadPrivateKeyRsa(raw_pk) + if err != nil { return nil, err } + return pk, nil } -} - -// generate a rsa private key -func create_private_key_rsa(flags CreateFlags) { - if flags.CryptLength < 2048 { - crash_with_help(2, "Length is smaller than 2048!") - } - - priv, err := rsa.GenerateKey( rand.Reader, flags.CryptLength) - if err != nil { - fmt.Fprintln(os.Stderr, "Error: ", err) - os.Exit(3) - } - marshal := x509.MarshalPKCS1PrivateKey(priv) - block := &pem.Block{Type: TypeLabelRSA, Bytes: marshal} - pem.Encode(flags.output_stream, block) -} - -// generate a ecdsa private key -func create_private_key_ecdsa(flags CreateFlags) { - var curve elliptic.Curve - switch flags.CryptLength { - case 224: curve = elliptic.P224() - case 256: curve = elliptic.P256() - case 384: curve = elliptic.P384() - case 521: curve = elliptic.P521() - default: crash_with_help(2, "Unsupported crypt length!") - } - - priv, err := ecdsa.GenerateKey(curve, rand.Reader) - if err != nil { - fmt.Fprintln(os.Stderr, "Error: ", err) - os.Exit(3) - } - marshal, err := x509.MarshalECPrivateKey(priv) - if err != nil { - crash_with_help(2, fmt.Sprintf("Problems marshalling the private key: %s", err)) - } - block := &pem.Block{Type: TypeLabelECDSA, Bytes: marshal} - pem.Encode(flags.output_stream, block) -} - -// parse the flags to create a private key -func parse_create_flags() CreateFlags { - flags := CreateFlags{} - fs := flag.NewFlagSet("create-private", flag.ExitOnError) - fs.StringVar(&flags.CryptType, "type", "ecdsa", "which type to use to encrypt key (rsa, ecdsa)") - fs.IntVar(&flags.CryptLength, "length", 521, fmt.Sprintf( - "%i - %i for rsa; %v for ecdsa", RsaLowerLength, RsaUpperLength, EcdsaLength,)) - fs.StringVar(&flags.Output, "output", "STDOUT", "filename to store the private key") - fs.Parse(os.Args[2:]) - - return flags -} - -// load the private key stored at `path` -func load_private_key(path string) crypto.Signer { - if path == "" { - crash_with_help(2, "No path to private key supplied!") - } - - file, err := os.Open(path) - if err != nil { - crash_with_help(3, fmt.Sprintf("Error when opening private key: %s", err)) - } - defer file.Close() - - data, err := ioutil.ReadAll(file) - if err != nil { - crash_with_help(3, fmt.Sprintf("Error when reading private key: %s", err)) - } - - block, _ := pem.Decode(data) - if block.Type == TypeLabelRSA { - return load_private_key_rsa(block) - } else if block.Type == TypeLabelECDSA { - return load_private_key_ecdsa(block) - } else { - crash_with_help(2, "No valid private key file! Only RSA and ECDSA keys are allowed!") - return nil - } -} - -// parse rsa private key -func load_private_key_rsa(block *pem.Block) crypto.Signer { - key, err := x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - crash_with_help(3, fmt.Sprintf("Error parsing private key: %s", err)) - } - return key -} - -// parse ecdsa private key -func load_private_key_ecdsa(block *pem.Block) crypto.Signer { - key, err := x509.ParseECPrivateKey(block.Bytes) - if err != nil { - crash_with_help(3, fmt.Sprintf("Error parsing private key: %s", err)) - } - return key + return nil, ErrNoPKFound } diff --git a/public_key.go b/public_key.go deleted file mode 100644 index cbafc49..0000000 --- a/public_key.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -// create a public key from a private key - -import ( - "crypto/x509" - "encoding/pem" - "flag" - "fmt" - "io" - "os" -) - -type ( - PublicKeyFlags struct { - PrivateKeyPath string - Output string - - output_stream io.WriteCloser // the actual stream to the output - } -) - -func create_public_key() { - var err error - flags := parse_public_key_flags() - flags.output_stream, err = open_output_stream(flags.Output) - if err != nil { - crash_with_help(2, fmt.Sprintf("Error when creating file %s: %s", flags.Output, err)) - } - defer flags.output_stream.Close() - - priv_key := load_private_key(flags.PrivateKeyPath) - marshal, err := x509.MarshalPKIXPublicKey(priv_key.Public()) - if err != nil { - crash_with_help(2, fmt.Sprintf("Problems marshalling the public key: %s", err)) - } - - block := &pem.Block{Type: TypeLabelPubKey, Bytes: marshal} - pem.Encode(flags.output_stream, block) -} - -func parse_public_key_flags() PublicKeyFlags { - flags := PublicKeyFlags{} - fs := flag.NewFlagSet("create-public", flag.ExitOnError) - fs.StringVar(&flags.PrivateKeyPath, "private-key", "", "path to the private key file") - fs.StringVar(&flags.Output, "output", "STDOUT", "path where the generated public key should be stored") - fs.Parse(os.Args[2:]) - - return flags -} diff --git a/sign_input.go b/sign_input.go deleted file mode 100644 index c1ab9e0..0000000 --- a/sign_input.go +++ /dev/null @@ -1,103 +0,0 @@ -package main - -import ( - "crypto" - "crypto/rand" - "crypto/sha256" - "encoding/base64" - "errors" - "flag" - "fmt" - "io" - "io/ioutil" - "os" -// "crypto/ecdsa" -// "crypto/rsa" -) - -type ( - SignInputFlags struct { - Message string // the message to sign - MessageStream string // the message stream to sign - PrivateKeyPath string // path to the private key - Output string // a path or stream to output the private key to - Format string // the format of the output - - private_key crypto.Signer - output_stream io.Writer // the output stream for the CSR - input_stream io.Reader // the input stream to read the message from - } -) - -func sign_input() { - flags := parse_sign_input_flags() - if flags.Message != "" && flags.MessageStream != "" { - crash_with_help(2, "Only message or message file can be signed!") - } - flags.private_key = load_private_key(flags.PrivateKeyPath) - - output_stream, err := open_output_stream(flags.Output) - if err != nil { - crash_with_help(2, fmt.Sprintf("Error when creating file %s: %s", flags.Output, err)) - } - flags.output_stream = output_stream - defer output_stream.Close() - - if flags.MessageStream != "" { - input_stream, err := open_input_stream(flags.MessageStream) - if err != nil { - crash_with_help(2, fmt.Sprintf("Error when opening stream %s: %s", flags.MessageStream, err)) - } - flags.input_stream = input_stream - defer input_stream.Close() - } - - if err := create_signature(flags); err != nil { - fmt.Fprintln(os.Stderr, "Error when creating signature", err) - os.Exit(3) - } -} - -func parse_sign_input_flags() SignInputFlags { - flags := SignInputFlags{} - fs := flag.NewFlagSet("sign-input", flag.ExitOnError) - fs.StringVar(&flags.PrivateKeyPath, "private-key", "", "path to the private key file") - fs.StringVar(&flags.Output, "output", "STDOUT", "path where the generated signature should be stored (STDOUT, STDERR, file)") - fs.StringVar(&flags.Message, "message", "", "the message to sign") - fs.StringVar(&flags.MessageStream, "message-stream", "STDIN", "the path to the stream to sign (file, STDIN)") - fs.StringVar(&flags.Format, "format", "base64", "the output format (binary, base64)") - fs.Parse(os.Args[2:]) - - return flags -} - -func create_signature(flags SignInputFlags) error { - var message []byte - var err error - - if flags.MessageStream != "" { - message, err = ioutil.ReadAll(flags.input_stream) - if err != nil { return err } - } else { - message = []byte(flags.Message) - } - // compute sha256 of the message - hash := sha256.New() - length, _ := hash.Write(message) - if length != len(message) { return errors.New("Error when creating hash over message!") } - - // create signature of the hash using the private key - signature, err := flags.private_key.Sign( - rand.Reader, - hash.Sum([]byte("")), - nil, - ) - if err != nil { return err } - if flags.Format == "base64" { - flags.output_stream.Write([]byte(base64.StdEncoding.EncodeToString(signature))) - } else { - flags.output_stream.Write(signature) - } - flags.output_stream.Write([]byte("\n")) - return nil -} diff --git a/sign_request.go b/sign_request.go deleted file mode 100644 index 234408c..0000000 --- a/sign_request.go +++ /dev/null @@ -1,10 +0,0 @@ -package main - -import ( - -) - -// sign a certificate request to create a new certificate -func sign_request() { - -} diff --git a/verify_signature.go b/verify_signature.go deleted file mode 100644 index 2b2b16b..0000000 --- a/verify_signature.go +++ /dev/null @@ -1,161 +0,0 @@ -package main - -// verify a signature generated with a private key - -import ( - "crypto/ecdsa" - "crypto/sha256" - "crypto/x509" - "encoding/asn1" - "encoding/pem" - "encoding/base64" - "errors" - "flag" - "fmt" - "io" - "io/ioutil" - "math/big" - "os" - "strings" -) - -type ( - VerifySignatureFlags struct { - Message string // the message to sign - MessageStream string // the path to the input stream - PublicKeyPath string // path to the private key - Signature string // a path or stream to output the private key to - SignatureStream string // read signature from an input stream - Format string // the format of the signature - - message_stream io.Reader // the message stream - signature_stream io.Reader // the signature stream - } - // struct to load the signature into (which is basically two bigint in byte form) - Signature struct { - R, S *big.Int - } -) - -func verify_signature() { - flags := parse_verify_signature_flags() - if flags.SignatureStream == flags.MessageStream && - ( flags.Message == "" && flags.Signature == "") { - crash_with_help(2, "Signature and Message stream can't be the same source!") - } - - // open streams - if flags.Message == "" && flags.MessageStream != "" { - message_stream, err := open_input_stream(flags.MessageStream) - if err != nil { - crash_with_help(2, fmt.Sprintf("Error when opening stream %s: %s", flags.MessageStream, err)) - } - defer message_stream.Close() - flags.message_stream = message_stream - } - if flags.Signature == "" && flags.SignatureStream != "" { - signature_stream, err := open_input_stream(flags.SignatureStream) - if err != nil { - crash_with_help(2, fmt.Sprintf("Error when opening stream %s: %s", flags.SignatureStream, err)) - } - defer signature_stream.Close() - flags.signature_stream = signature_stream - } - - public_key, err := load_public_key_ecdsa(flags.PublicKeyPath) - if err != nil { - crash_with_help(2, fmt.Sprintf("Error when loading public key: %s", err)) - } - signature, err := load_signature(flags) - if err != nil { - crash_with_help(2, fmt.Sprintf("Error when loading the signature: %s", err)) - } - message, err := load_message(flags) - hash := sha256.New() - hash.Write([]byte(message)) - - success := ecdsa.Verify(public_key, hash.Sum(nil), signature.R, signature.S) - fmt.Println(success) -} - -// parse the parameters -func parse_verify_signature_flags() VerifySignatureFlags { - flags := VerifySignatureFlags{} - fs := flag.NewFlagSet("verify-signature", flag.ExitOnError) - fs.StringVar(&flags.PublicKeyPath, "public-key", "", "path to the public key file") - fs.StringVar(&flags.Signature, "signature", "", "path where the signature file can be found") - fs.StringVar(&flags.SignatureStream, "signature-stream", "", "the path to the stream of the signature (file, STDIN)") - fs.StringVar(&flags.Format, "format", "auto", "the input format of the signature (auto, binary, base64)") - fs.StringVar(&flags.Message, "message", "", "the message to validate") - fs.StringVar(&flags.MessageStream, "message-stream", "STDIN", "the path to the stream to validate (file, STDIN)") - fs.Parse(os.Args[2:]) - - return flags -} - -// load the private key from pem file -func load_public_key_ecdsa(path string) (*ecdsa.PublicKey, error) { - public_key_file, err := os.Open(path) - if err != nil { return nil, err } - public_key_pem, err := ioutil.ReadAll(public_key_file) - if err != nil { return nil, err } - public_key_file.Close() - - block, _ := pem.Decode(public_key_pem) - if block.Type != TypeLabelPubKey { - return nil, errors.New(fmt.Sprintf("No public key found in %s", path)) - } - - public_key, err := x509.ParsePKIXPublicKey(block.Bytes) - if err != nil { return nil, err } - return public_key.(*ecdsa.PublicKey), nil -} - -// parse the signature from asn1 file -func load_signature(flags VerifySignatureFlags) (*Signature, error) { - var signature_raw []byte - var err error - if flags.Message != "" { - signature_raw = []byte(flags.Message) - } else { - signature_raw, err = ioutil.ReadAll(flags.signature_stream) - if err != nil { return nil, err } - } - - switch strings.ToLower(flags.Format) { - case "auto": - sig, err := load_signature_base64(signature_raw) - if err != nil { - sig, err = load_signature_binary(signature_raw) - if err != nil { return nil, err } - return sig, nil - } - return sig, nil - case "base64": return load_signature_base64(signature_raw) - case "binary": return load_signature_binary(signature_raw) - default: return nil, errors.New("Unknown format!") - } -} - -// convert the signature from base64 into a signature -func load_signature_base64(signature_raw []byte) (*Signature, error) { - asn1_sig, err := base64.StdEncoding.DecodeString(string(signature_raw)) - if err != nil { return nil, err } - return load_signature_binary(asn1_sig) -} - -// convert the signature from asn1 into a signature -func load_signature_binary(signature_raw []byte) (*Signature, error) { - var signature Signature - _, err := asn1.Unmarshal(signature_raw, &signature) - if err != nil { return nil, err } - return &signature, nil -} - -// load the message from a stream or the parameter -func load_message(flags VerifySignatureFlags) (string, error) { - if flags.Message != "" { return flags.Message, nil } - message, err := ioutil.ReadAll(flags.message_stream) - if err != nil { return "", err } - return string(message), nil -}