pm/keyring/keyring.go

117 lines
2.9 KiB
Go
Raw Normal View History

package keyring
2018-02-25 01:45:56 -08:00
import (
2018-02-25 01:52:57 -08:00
"os"
"path/filepath"
2018-02-25 01:45:56 -08:00
"github.com/pkg/errors"
"golang.org/x/crypto/openpgp"
2018-02-25 01:52:57 -08:00
"mcquay.me/fs"
2018-02-25 01:45:56 -08:00
)
2018-02-25 03:11:40 -08:00
// NewKeyPair creates and adds a new OpenPGP keypair to an existing keyring.
func NewKeyPair(root, name, email string) error {
2018-02-25 03:11:40 -08:00
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")
2018-02-25 01:52:57 -08:00
}
2018-02-25 03:11:40 -08:00
fresh, err := openpgp.NewEntity(name, "pm", email, nil)
2018-02-25 01:45:56 -08:00
if err != nil {
errors.Wrap(err, "new entity")
}
2018-02-25 03:11:40 -08:00
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
}