bridge: implement keygen command

Tested using `/guardiand keygen /bar --desc foobar`.

ghstack-source-id: 9f96ce7c0c
Pull Request resolved: https://github.com/certusone/wormhole/pull/91
This commit is contained in:
Leo 2020-11-19 12:53:17 +01:00
parent d9f8174d76
commit 798ffec09c
3 changed files with 51 additions and 8 deletions

View File

@ -122,6 +122,17 @@ func rootLoggerName() string {
}
}
// lockMemory locks current and future pages in memory to protect secret keys from being swapped out to disk.
// It's possible (and strongly recommended) to deploy Wormhole such that keys are only ever
// stored in memory and never touch the disk. This is a privileged operation and requires CAP_IPC_LOCK.
func lockMemory() {
err := unix.Mlockall(syscall.MCL_CURRENT | syscall.MCL_FUTURE)
if err != nil {
fmt.Printf("Failed to lock memory: %v (CAP_IPC_LOCK missing?)\n", err)
os.Exit(1)
}
}
// BridgeCmd represents the bridge command
var BridgeCmd = &cobra.Command{
Use: "bridge",
@ -134,14 +145,7 @@ func runBridge(cmd *cobra.Command, args []string) {
fmt.Print(devwarning)
}
// Lock current and future pages in memory to protect secret keys from being swapped out to disk.
// It's possible (and strongly recommended) to deploy Wormhole such that keys are only ever
// stored in memory and never touch the disk. This is a privileged operation and requires CAP_IPC_LOCK.
err := unix.Mlockall(syscall.MCL_CURRENT | syscall.MCL_FUTURE)
if err != nil {
fmt.Printf("Failed to lock memory: %v (CAP_IPC_LOCK missing?)\n", err)
os.Exit(1)
}
lockMemory()
// Set up logging. The go-log zap wrapper that libp2p uses is compatible with our
// usage of zap in supervisor, which is nice.

View File

@ -2,16 +2,50 @@ package guardiand
import (
"crypto/ecdsa"
"crypto/rand"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/spf13/cobra"
"google.golang.org/protobuf/encoding/prototext"
"github.com/certusone/wormhole/bridge/pkg/devnet"
nodev1 "github.com/certusone/wormhole/bridge/pkg/proto/node/v1"
)
var keyDescription *string
func init() {
keyDescription = KeygenCmd.Flags().String("desc", "", "Human-readable key description (optional)")
}
var KeygenCmd = &cobra.Command{
Use: "keygen",
Short: "Create guardian key at the specified path",
Run: runKeygen,
Args: cobra.ExactArgs(1),
}
func runKeygen(cmd *cobra.Command, args []string) {
lockMemory()
log.Print("Creating new key at ", args[0])
gk, err := ecdsa.GenerateKey(ethcrypto.S256(), rand.Reader)
if err != nil {
log.Fatalf("failed to generate key: %v", err)
}
err = writeGuardianKey(gk, *keyDescription, args[0])
if err != nil {
log.Fatalf("failed to write key: %v", err)
}
}
// loadGuardianKey loads a serialized guardian key from disk.
func loadGuardianKey(filename string) (*ecdsa.PrivateKey, error) {
b, err := ioutil.ReadFile(filename)
@ -35,6 +69,10 @@ func loadGuardianKey(filename string) (*ecdsa.PrivateKey, error) {
// writeGuardianKey serializes a guardian key and writes it to disk.
func writeGuardianKey(key *ecdsa.PrivateKey, description string, filename string) error {
if _, err := os.Stat(filename); !os.IsNotExist(err) {
return errors.New("refusing to override existing key")
}
m := &nodev1.GuardianKey{
Description: description,
Data: ethcrypto.FromECDSA(key),

View File

@ -33,6 +33,7 @@ func init() {
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.guardiand.yaml)")
rootCmd.AddCommand(guardiand.BridgeCmd)
rootCmd.AddCommand(guardiand.KeygenCmd)
}
// initConfig reads in config file and ENV variables if set.