diff options
| -rw-r--r-- | create_sign_request.go | 118 | ||||
| -rw-r--r-- | create_sign_request_test.go | 84 | ||||
| -rw-r--r-- | flags.go | 168 | ||||
| -rw-r--r-- | io.go | 41 | ||||
| -rw-r--r-- | main.go | 91 | ||||
| -rw-r--r-- | private_key.go | 156 | ||||
| -rw-r--r-- | public_key.go | 50 | ||||
| -rw-r--r-- | sign_input.go | 103 | ||||
| -rw-r--r-- | sign_request.go | 10 | ||||
| -rw-r--r-- | verify_signature.go | 161 | 
10 files changed, 282 insertions, 700 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: ¶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 +} @@ -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 +} @@ -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 -  } -} +var ( +  ErrNoPKFound = errors.New("no private key found") +) -// 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)) +// 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    } -  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)) +  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 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 -} | 
