add private key handling

This also contains a couple fixes to the subject part.
This commit is contained in:
Gibheer 2017-05-28 23:55:39 +02:00
parent b9c2539073
commit bc8e1353af
8 changed files with 331 additions and 55 deletions

View File

@ -40,28 +40,16 @@ func main() {
err = setSubject(args, client) err = setSubject(args, client)
case `show-subj`: case `show-subj`:
err = showSubject(args, client) err = showSubject(args, client)
// case `list`: case `create-private`:
// err = listDescription(args, client) err = createPrivateKey(args, client)
// case `create-file`: case `delete-private`:
// err = createFile(args, client) err = deletePrivateKey(args, client)
// case `list-files`: case `list-private`:
// err = listFile(args, client) err = listPrivateKey(args, client)
// case `delete-file`: case `set-private`:
// err = deleteFile(args, client) err = setPrivateKey(args, client)
// case `create-private-key`: case `show-private`:
// err = createPrivateKey(args, client) err = showPrivateKey(args, client)
// case `get-private-key`:
// err = getPrivateKey(args, client)
// case `list-private-keys`:
// err = listPrivateKey(args, client)
// case `delete-private-key`:
// err = deletePrivateKey(args, client)
// case `create-public-key`:
// err = createPublicKey(args, client)
// case `list-public-keys`:
// err = listPublicKey(args, client)
// case `delete-public-key`:
// err = deletePublicKey(args, client)
default: default:
fmt.Printf("unknown subcommand '%s'\n", cmd) fmt.Printf("unknown subcommand '%s'\n", cmd)
printCommands() printCommands()

116
cmd/pkiadm/private_key.go Normal file
View File

@ -0,0 +1,116 @@
package main
import (
"encoding/base64"
"fmt"
"os"
"text/tabwriter"
"github.com/gibheer/pkiadm"
"github.com/pkg/errors"
flag "github.com/spf13/pflag"
)
func createPrivateKey(args []string, client *pkiadm.Client) error {
fs := flag.NewFlagSet("create-private", flag.ExitOnError)
fs.Usage = func() {
fmt.Printf("Usage of %s:\n", "pkiadm create-private")
fmt.Println(`
Create a new private key for different use cases. The supported types are rsa,
ecdsa and ed25519. Please keep in mind, that ed25519 is currently not supported
for certificate generation.
`)
fs.PrintDefaults()
}
pk := pkiadm.PrivateKey{}
fs.StringVar(&pk.ID, "id", "", "set the unique id for the new private key")
var pkType = fs.String("type", "rsa", "set the type of the private key (rsa, ecdsa, ed25519)")
fs.UintVar(&pk.Bits, "bits", 2048, "set the number of bits to use. For rsa it can be 1024 up to 32768, for ecdsa 224, 256, 384, 521. Ed25519 is set to 256 by default.")
fs.Parse(args)
pkT, err := pkiadm.StringToPrivateKeyType(*pkType)
if err != nil {
return err
}
pk.Type = pkT
if err := client.CreatePrivateKey(pk); err != nil {
return errors.Wrap(err, "could not create private key")
}
return nil
}
func setPrivateKey(args []string, client *pkiadm.Client) error {
fs := flag.NewFlagSet("set-private", flag.ExitOnError)
pk := pkiadm.PrivateKey{}
fs.StringVar(&pk.ID, "id", "", "set the id of the private key to change")
var pkType = fs.String("type", "rsa", "set the type of the private key (rsa, ecdsa, ed25519)")
fs.UintVar(&pk.Bits, "bits", 2048, "set the number of bits to use. For rsa it can be 1024 up to 32768, for ecdsa 224, 256, 384, 521. Ed25519 is set to 256 by default.")
fs.Parse(args)
pkT, err := pkiadm.StringToPrivateKeyType(*pkType)
if err != nil {
return err
}
pk.Type = pkT
fieldList := []string{}
for _, field := range []string{"type", "bits"} {
flag := fs.Lookup(field)
if flag.Changed {
fieldList = append(fieldList, field)
}
}
if err := client.SetPrivateKey(pk, fieldList); err != nil {
return err
}
return nil
}
func deletePrivateKey(args []string, client *pkiadm.Client) error {
fs := flag.NewFlagSet("delete-private", flag.ExitOnError)
var id = fs.String("id", "", "set the id of the private key to delete")
fs.Parse(args)
if err := client.DeletePrivateKey(*id); err != nil {
return err
}
return nil
}
func listPrivateKey(args []string, client *pkiadm.Client) error {
fs := flag.NewFlagSet("list-private", flag.ExitOnError)
fs.Parse(args)
pks, err := client.ListPrivateKey()
if err != nil {
return err
}
if len(pks) == 0 {
return nil
}
out := tabwriter.NewWriter(os.Stdout, 2, 2, 1, ' ', tabwriter.AlignRight)
fmt.Fprintf(out, "%s\t%s\t%s\t\n", "id", "type", "bits")
for _, pk := range pks {
fmt.Fprintf(out, "%s\t%s\t%d\t\n", pk.ID, pk.Type.String(), pk.Bits)
}
out.Flush()
return nil
}
func showPrivateKey(args []string, client *pkiadm.Client) error {
fs := flag.NewFlagSet("show-private", flag.ExitOnError)
var id = fs.String("id", "", "set the id of the private key to show")
fs.Parse(args)
pk, err := client.ShowPrivateKey(*id)
if err != nil {
return err
}
out := tabwriter.NewWriter(os.Stdout, 2, 2, 1, ' ', tabwriter.AlignRight)
fmt.Fprintf(out, "ID:\t%s\t\n", pk.ID)
fmt.Fprintf(out, "type:\t%s\t\n", pk.Type.String())
fmt.Fprintf(out, "bits:\t%d\t\n", pk.Bits)
fmt.Fprintf(out, "checksum:\t%s\t\n", base64.StdEncoding.EncodeToString(pk.Checksum))
out.Flush()
return nil
}

View File

@ -32,7 +32,6 @@ In most cases only the common name, organization name and the country is provide
} }
if err := client.CreateSubject(subj); err != nil { if err := client.CreateSubject(subj); err != nil {
fmt.Println("got an error")
return errors.Wrap(err, "could not create new subject") return errors.Wrap(err, "could not create new subject")
} }
return nil return nil

View File

@ -6,12 +6,7 @@ import (
"fmt" "fmt"
"github.com/gibheer/pki" "github.com/gibheer/pki"
) "github.com/gibheer/pkiadm"
const (
PKTRSA PrivateKeyType = iota
PKTECDSA
PKTED25519
) )
const ( const (
@ -23,24 +18,23 @@ const (
type ( type (
PrivateKey struct { PrivateKey struct {
ID string ID string
PKType PrivateKeyType PKType pkiadm.PrivateKeyType
Length uint Bits uint
Key []byte Key []byte
} }
PrivateKeyType uint
) )
func NewPrivateKey(id string, pkType PrivateKeyType, length uint) (*PrivateKey, error) { func NewPrivateKey(id string, pkType pkiadm.PrivateKeyType, bits uint) (*PrivateKey, error) {
if id == "" { if id == "" {
return nil, ENoIDGiven return nil, ENoIDGiven
} }
if err := verifyPK(pkType, length); err != nil { if err := verifyPK(pkType, bits); err != nil {
return nil, err return nil, err
} }
pk := PrivateKey{ pk := PrivateKey{
ID: id, ID: id,
PKType: pkType, PKType: pkType,
Length: length, Bits: bits,
} }
return &pk, nil return &pk, nil
} }
@ -67,13 +61,13 @@ func (p *PrivateKey) Refresh(_ *Storage) error {
err error err error
) )
switch p.PKType { switch p.PKType {
case PKTRSA: case pkiadm.PKTRSA:
key, err = pki.NewPrivateKeyRsa(int(p.Length)) key, err = pki.NewPrivateKeyRsa(int(p.Bits))
case PKTED25519: case pkiadm.PKTED25519:
key, err = pki.NewPrivateKeyEd25519() key, err = pki.NewPrivateKeyEd25519()
case PKTECDSA: case pkiadm.PKTECDSA:
var curve elliptic.Curve var curve elliptic.Curve
switch p.Length { switch p.Bits {
case 224: case 224:
curve = elliptic.P224() curve = elliptic.P224()
case 256: case 256:
@ -120,20 +114,20 @@ func (p *PrivateKey) GetKey() (pki.PrivateKey, error) {
return key, nil return key, nil
} }
func verifyPK(pkType PrivateKeyType, length uint) error { func verifyPK(pkType pkiadm.PrivateKeyType, bits uint) error {
switch pkType { switch pkType {
case PKTRSA: case pkiadm.PKTRSA:
if length < 1024 || length > 32768 { if bits < 1024 || bits > 32768 {
return ELengthOutOfBounds return ELengthOutOfBounds
} }
case PKTECDSA: case pkiadm.PKTECDSA:
switch length { switch bits {
case 224, 256, 384, 521: case 224, 256, 384, 521:
default: default:
return EWrongKeyLength return EWrongKeyLength
} }
case PKTED25519: case pkiadm.PKTED25519:
if length != 256 { if bits != 256 {
return EWrongKeyLengthED25519 return EWrongKeyLengthED25519
} }
default: default:
@ -142,9 +136,92 @@ func verifyPK(pkType PrivateKeyType, length uint) error {
return nil return nil
} }
//func (p *PrivateKey) MarshalJSON() ([]byte, error) { func (s *Server) CreatePrivateKey(inPk pkiadm.PrivateKey, res *pkiadm.Result) error {
// return json.Marshal(*p) s.lock()
//} defer s.unlock()
//func (p *PrivateKey) UnmarshalJSON(raw []byte) error {
// return json.Unmarshal(raw, p) pk, err := NewPrivateKey(inPk.ID, inPk.Type, inPk.Bits)
//} if err != nil {
res.SetError(err, "Could not create new private key '%s'", inPk.ID)
return nil
}
if err := s.storage.AddPrivateKey(pk); err != nil {
res.SetError(err, "Could not add private key '%s'", inPk.ID)
return nil
}
return nil
}
func (s *Server) SetPrivateKey(changeset pkiadm.PrivateKeyChange, res *pkiadm.Result) error {
s.lock()
defer s.unlock()
pk, err := s.storage.GetPrivateKey(ResourceName{ID: changeset.PrivateKey.ID, Type: RTPrivateKey})
if err != nil {
res.SetError(err, "Could not find private key '%s'", changeset.PrivateKey.ID)
return nil
}
for _, field := range changeset.FieldList {
switch field {
case "type":
pk.PKType = changeset.PrivateKey.Type
case "bits":
pk.Bits = changeset.PrivateKey.Bits
default:
res.SetError(fmt.Errorf("unknown field"), "unknown field '%s'", field)
return nil
}
}
if err := s.storage.Update(ResourceName{ID: pk.ID, Type: RTPrivateKey}); err != nil {
res.SetError(err, "Could not update private key '%s'", changeset.PrivateKey.ID)
return nil
}
return s.store(res)
}
func (s *Server) DeletePrivateKey(inPk pkiadm.ResourceName, res *pkiadm.Result) error {
s.lock()
defer s.unlock()
pk, err := s.storage.GetPrivateKey(ResourceName{ID: inPk.ID, Type: RTPrivateKey})
if err != nil {
res.SetError(err, "Could not find private key '%s'", inPk.ID)
return nil
}
if err := s.storage.Remove(pk); err != nil {
res.SetError(err, "Could not remove private key '%s'", pk.ID)
return nil
}
return s.store(res)
}
func (s *Server) ShowPrivateKey(inPk pkiadm.ResourceName, res *pkiadm.ResultPrivateKey) error {
s.lock()
defer s.unlock()
pk, err := s.storage.GetPrivateKey(ResourceName{ID: inPk.ID, Type: RTPrivateKey})
if err != nil {
res.Result.SetError(err, "Could not find private key '%s'", inPk.ID)
return nil
}
res.PrivateKeys = []pkiadm.PrivateKey{pkiadm.PrivateKey{
ID: pk.ID,
Type: pk.PKType,
Bits: pk.Bits,
Checksum: pk.Checksum(),
}}
return nil
}
func (s *Server) ListPrivateKey(filter pkiadm.Filter, res *pkiadm.ResultPrivateKey) error {
s.lock()
defer s.unlock()
for _, pk := range s.storage.PrivateKeys {
res.PrivateKeys = append(res.PrivateKeys, pkiadm.PrivateKey{
ID: pk.ID,
Type: pk.PKType,
Bits: pk.Bits,
Checksum: pk.Checksum(),
})
}
return nil
}

View File

@ -2,6 +2,7 @@ package main
import ( import (
"crypto/x509/pkix" "crypto/x509/pkix"
"fmt"
"github.com/gibheer/pkiadm" "github.com/gibheer/pkiadm"
) )
@ -90,10 +91,13 @@ func (s *Server) SetSubject(changeset pkiadm.SubjectChange, res *pkiadm.Result)
subj.Data.StreetAddress = changes.StreetAddress subj.Data.StreetAddress = changes.StreetAddress
case "code": case "code":
subj.Data.PostalCode = changes.PostalCode subj.Data.PostalCode = changes.PostalCode
default:
res.SetError(fmt.Errorf("unknown field"), "unknown field '%s'", field)
return nil
} }
} }
if err := s.storage.Update(ResourceName{ID: subj.ID, Type: RTSubject}); err != nil { if err := s.storage.Update(ResourceName{ID: subj.ID, Type: RTSubject}); err != nil {
res.SetError(err, "Could update resource '%s'", changeset.Subject.ID) res.SetError(err, "Could not update subject '%s'", changeset.Subject.ID)
return nil return nil
} }
return s.store(res) return s.store(res)

63
private_key.go Normal file
View File

@ -0,0 +1,63 @@
package pkiadm
const (
PKTRSA PrivateKeyType = iota
PKTECDSA
PKTED25519
PKTUnknown
)
type (
PrivateKey struct {
ID string
Type PrivateKeyType
Bits uint
Checksum []byte // This field is only set by the server
}
PrivateKeyChange struct {
PrivateKey PrivateKey
FieldList []string
}
ResultPrivateKey struct {
Result Result
PrivateKeys []PrivateKey
}
PrivateKeyType uint
)
// CreatePrivateKey sends a RPC request to create a new private key.
func (c *Client) CreatePrivateKey(pk PrivateKey) error {
return c.exec("CreatePrivateKey", pk)
}
func (c *Client) SetPrivateKey(pk PrivateKey, fieldList []string) error {
changeset := PrivateKeyChange{pk, fieldList}
return c.exec("SetPrivateKey", changeset)
}
func (c *Client) DeletePrivateKey(id string) error {
pk := ResourceName{ID: id, Type: RTPrivateKey}
return c.exec("DeletePrivateKey", pk)
}
func (c *Client) ListPrivateKey() ([]PrivateKey, error) {
result := &ResultPrivateKey{}
if err := c.query("ListPrivateKey", Filter{}, result); err != nil {
return []PrivateKey{}, err
}
if result.Result.HasError {
return []PrivateKey{}, result.Result.Error
}
return result.PrivateKeys, nil
}
func (c *Client) ShowPrivateKey(id string) (PrivateKey, error) {
pk := ResourceName{ID: id, Type: RTPrivateKey}
result := &ResultPrivateKey{}
if err := c.query("ShowPrivateKey", pk, result); err != nil {
return PrivateKey{}, err
}
if result.Result.HasError {
return PrivateKey{}, result.Result.Error
}
for _, privateKey := range result.PrivateKeys {
return privateKey, nil
}
return PrivateKey{}, nil
}

29
privatekeytype_string.go Normal file
View File

@ -0,0 +1,29 @@
// Code generated by "stringer -type PrivateKeyType"; DO NOT EDIT
package pkiadm
import "fmt"
const _PrivateKeyType_name = "rsaecdsaed25519"
var _PrivateKeyType_index = [...]uint8{0, 3, 8, 15}
func (i PrivateKeyType) String() string {
if i >= PrivateKeyType(len(_PrivateKeyType_index)-1) {
return fmt.Sprintf("PrivateKeyType(%d)", i)
}
return _PrivateKeyType_name[_PrivateKeyType_index[i]:_PrivateKeyType_index[i+1]]
}
func StringToPrivateKeyType(t string) (PrivateKeyType, error) {
switch t {
case "rsa":
return PKTRSA, nil
case "ecdsa":
return PKTECDSA, nil
case "ed25519":
return PKTED25519, nil
default:
return PKTUnknown, fmt.Errorf("unknown private key type")
}
}

View File

@ -39,7 +39,7 @@ func (c *Client) ShowSubject(id string) (Subject, error) {
subj := ResourceName{ID: id, Type: RTSubject} subj := ResourceName{ID: id, Type: RTSubject}
result := &ResultSubjects{} result := &ResultSubjects{}
if err := c.query("ShowSubject", subj, result); err != nil { if err := c.query("ShowSubject", subj, result); err != nil {
return Subject{}, nil return Subject{}, err
} }
if result.Result.HasError { if result.Result.HasError {
return Subject{}, result.Result.Error return Subject{}, result.Result.Error