diff --git a/cmd/pm/main.go b/cmd/pm/main.go index 8d7ae59..bbbcc0f 100644 --- a/cmd/pm/main.go +++ b/cmd/pm/main.go @@ -20,6 +20,7 @@ const keyUsage = `pm keyring: interact with pm's OpenPGP keyring subcommands: create (c) -- create a fresh keypair export (e) -- export a public key to stdout + import (i) -- import a public key from stdin list (ls) -- list configured key info ` @@ -80,6 +81,10 @@ func main() { if err := keyring.Export(root, os.Stdout, email); err != nil { fatalf("exporting public key for %q: %v\n", email, err) } + case "i", "import": + if err := keyring.Import(root, os.Stdin); err != nil { + fatalf("importing key: %v\n", err) + } default: fatalf("unknown keyring subcommand: %q\n\nusage: %v", sub, keyUsage) } diff --git a/keyring/keyring.go b/keyring/keyring.go index dfb221d..d35ed8d 100644 --- a/keyring/keyring.go +++ b/keyring/keyring.go @@ -134,6 +134,55 @@ func Export(root string, w io.Writer, email string) error { return nil } +// Import parses public key information from w and adds it to the public +// keyring. +func Import(root string, w io.Reader) error { + el, err := openpgp.ReadArmoredKeyRing(w) + if err != nil { + return errors.Wrap(err, "reading keyring") + } + + if err := ensureDir(root); err != nil { + return errors.Wrap(err, "can't find or create pgp dir") + } + srn, prn := getNames(root) + _, pubs, err := getELs(srn, prn) + if err != nil { + return errors.Wrap(err, "getting existing keyrings") + } + + foreign := openpgp.EntityList{} + exist := map[uint64]bool{} + for _, p := range pubs { + exist[p.PrimaryKey.KeyId] = true + } + + for _, e := range el { + if _, ok := exist[e.PrimaryKey.KeyId]; !ok { + foreign = append(foreign, e) + } + } + if len(foreign) < 1 { + return errors.New("no new key material found") + } + + pubs = append(pubs, foreign...) + + pr, err := os.Create(prn) + if err != nil { + return errors.Wrap(err, "opening pubring") + } + for _, e := range pubs { + if err := e.Serialize(pr); err != nil { + return errors.Wrapf(err, "serializing %v", e.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") }