aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGibheer <gibheer@gmail.com>2015-02-15 01:34:25 +0100
committerGibheer <gibheer@gmail.com>2015-02-15 01:34:25 +0100
commit16eb14db9f9b228ef88bcf1beb09cf823256dac1 (patch)
tree414ed9ba9f3e5679a7b0ae7b120e752d3f8ee2f6
parent2f9126dc6a2eab32316ec90e21688d31159f9e80 (diff)
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.
-rw-r--r--create_sign_request.go118
-rw-r--r--create_sign_request_test.go84
-rw-r--r--flags.go168
-rw-r--r--io.go41
-rw-r--r--main.go91
-rw-r--r--private_key.go160
-rw-r--r--public_key.go50
-rw-r--r--sign_input.go103
-rw-r--r--sign_request.go10
-rw-r--r--verify_signature.go161
10 files changed, 284 insertions, 702 deletions
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: &paramContainer{},
+ }
+}
+
+// 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 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))
- }
- 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))
- }
-}
-
-// 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
-}
+var (
+ ErrNoPKFound = errors.New("no private key found")
+)
-// 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
+// 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
+ }
+ raw_pk, err = readSectionFromFile(path, TypeLabelRSA)
+ if err == nil {
+ pk, err := pkilib.LoadPrivateKeyRsa(raw_pk)
+ if err != nil { return nil, err }
+ return pk, nil
+ }
+ 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
-}