From 9f921135f7d99b2dbf38115dee8fa76212772e0e Mon Sep 17 00:00:00 2001 From: stephen mcquay Date: Sun, 25 Feb 2018 03:11:40 -0800 Subject: [PATCH] Adds pm key create --- keyring/keyring.go | 106 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 9 deletions(-) diff --git a/keyring/keyring.go b/keyring/keyring.go index 24b8634..591845b 100644 --- a/keyring/keyring.go +++ b/keyring/keyring.go @@ -1,7 +1,6 @@ package keyring import ( - "log" "os" "path/filepath" @@ -11,18 +10,107 @@ import ( "mcquay.me/fs" ) +// NewKeyPair creates and adds a new OpenPGP keypair to an existing keyring. func NewKeyPair(root, name, email string) error { - pgpDir := filepath.Join(root, "var", "lib", "pm", "pgp") - if !fs.Exists(pgpDir) { - if err := os.MkdirAll(pgpDir, 0755); err != nil { - return errors.Wrap(err, "mk pgp dir") - } + if err := ensureDir(root); err != nil { + return errors.Wrap(err, "can't find or create pgp dir") + } + srn, prn := getNames(root) + secs, pubs, err := getELs(srn, prn) + if err != nil { + return errors.Wrap(err, "getting existing keyrings") } - e, err := openpgp.NewEntity(name, "pm", email, nil) + fresh, err := openpgp.NewEntity(name, "pm", email, nil) if err != nil { errors.Wrap(err, "new entity") } - log.Printf("%+v", e) - return errors.New("NYI") + + pr, err := os.Create(prn) + if err != nil { + return errors.Wrap(err, "opening pubring") + } + sr, err := os.Create(srn) + if err != nil { + return errors.Wrap(err, "opening secring") + } + + for _, e := range secs { + if err := e.SerializePrivate(sr, nil); err != nil { + return errors.Wrapf(err, "serializing old private key: %v", e.PrimaryKey.KeyIdString()) + } + } + // order is critical here; if we don't serialize the private key of fresh + // first, the later steps fail. + if err := fresh.SerializePrivate(sr, nil); err != nil { + return errors.Wrapf(err, "serializing fresh private %v", fresh.PrimaryKey.KeyIdString()) + } + if err := sr.Close(); err != nil { + return errors.Wrap(err, "closing secring") + } + + for _, e := range pubs { + if err := e.Serialize(pr); err != nil { + return errors.Wrapf(err, "serializing %v", e.PrimaryKey.KeyIdString()) + } + } + if err := fresh.Serialize(pr); err != nil { + return errors.Wrapf(err, "serializing %v", fresh.PrimaryKey.KeyIdString()) + } + if err := pr.Close(); err != nil { + return errors.Wrap(err, "closing pubring") + } + return nil +} + +func pGPDir(root string) string { + return filepath.Join(root, "var", "lib", "pm", "pgp") +} + +func ensureDir(root string) error { + d := pGPDir(root) + if !fs.Exists(d) { + if err := os.MkdirAll(d, 0700); err != nil { + return errors.Wrap(err, "mk pgp dir") + } + } + return nil +} + +func getNames(root string) (string, string) { + srn := filepath.Join(pGPDir(root), "secring.gpg") + prn := filepath.Join(pGPDir(root), "pubring.gpg") + return srn, prn +} + +func getELs(secring, pubring string) (openpgp.EntityList, openpgp.EntityList, error) { + var sr, pr openpgp.EntityList + if fs.Exists(secring) { + f, err := os.Open(secring) + if err != nil { + return nil, nil, errors.Wrap(err, "opening secring") + } + sr, err = openpgp.ReadKeyRing(f) + if err != nil { + return nil, nil, errors.Wrap(err, "read sec key ring") + } + if err := f.Close(); err != nil { + return nil, nil, errors.Wrap(err, "closing keyring") + } + } + + if fs.Exists(pubring) { + f, err := os.Open(pubring) + if err != nil { + return nil, nil, errors.Wrap(err, "opening pubring") + } + pr, err = openpgp.ReadKeyRing(f) + if err != nil { + return nil, nil, errors.Wrap(err, "read pub key ring") + } + if err := f.Close(); err != nil { + return nil, nil, errors.Wrap(err, "closing keyring") + } + } + return sr, pr, nil }