backup to a KeyFileStore and take out key remove

Signed-off-by: David Lawrence <david.lawrence@docker.com> (github: endophage)
This commit is contained in:
David Lawrence 2015-11-07 18:03:45 -08:00
parent 542c4a6d32
commit 91e8b9bcdb
3 changed files with 22 additions and 107 deletions

View File

@ -24,14 +24,13 @@ func NewNotaryRepository(baseDir, gun, baseURL string, rt http.RoundTripper,
retriever passphrase.Retriever) (*NotaryRepository, error) {
keysPath := filepath.Join(baseDir, notary.PrivDir)
backupPath := filepath.Join(baseDir, notary.BackupDir)
fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, retriever)
if err != nil {
return nil, fmt.Errorf("failed to create private key store in directory: %s", keysPath)
}
keyStoreManager, err := keystoremanager.NewKeyStoreManager(baseDir, fileKeyStore)
yubiKeyStore, _ := api.NewYubiKeyStore(backupPath, retriever)
yubiKeyStore, _ := api.NewYubiKeyStore(fileKeyStore, retriever)
var cryptoService signed.CryptoService
if yubiKeyStore == nil {
cryptoService = cryptoservice.NewCryptoService(gun, keyStoreManager.KeyStore)

View File

@ -22,10 +22,6 @@ import (
func init() {
cmdKey.AddCommand(cmdKeyList)
cmdKey.AddCommand(cmdKeyRemoveKey)
cmdKeyRemoveKey.Flags().StringVarP(&keyRemoveGUN, "gun", "g", "", "Globally unique name to remove keys for")
cmdKeyRemoveKey.Flags().BoolVarP(&keyRemoveRoot, "root", "r", false, "Remove root keys")
cmdKeyRemoveKey.Flags().BoolVarP(&keyRemoveYes, "yes", "y", false, "Answer yes to the removal question (no confirmation)")
cmdKey.AddCommand(cmdKeyGenerateRootKey)
cmdKeyExport.Flags().StringVarP(&keysExportGUN, "gun", "g", "", "Globally unique name to export keys for")
@ -57,17 +53,6 @@ var cmdRotateKey = &cobra.Command{
Run: keysRotate,
}
var keyRemoveGUN string
var keyRemoveRoot bool
var keyRemoveYes bool
var cmdKeyRemoveKey = &cobra.Command{
Use: "remove [ keyID ]",
Short: "Removes the key with the given keyID.",
Long: "remove the key with the given keyID from the local host.",
Run: keysRemoveKey,
}
var cmdKeyGenerateRootKey = &cobra.Command{
Use: "generate [ algorithm ]",
Short: "Generates a new root key with a given algorithm.",
@ -107,67 +92,6 @@ var cmdKeyImportRoot = &cobra.Command{
Run: keysImportRoot,
}
// keysRemoveKey deletes a private key based on ID
func keysRemoveKey(cmd *cobra.Command, args []string) {
if len(args) < 1 {
cmd.Usage()
fatalf("must specify the key ID of the key to remove")
}
parseConfig()
keysPath := filepath.Join(trustDir, notary.PrivDir)
backupPath := filepath.Join(trustDir, notary.BackupDir)
fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, retriever)
if err != nil {
fatalf("failed to create private key store in directory: %s", keysPath)
}
yubiStore, _ := api.NewYubiKeyStore(backupPath, retriever)
var cs signed.CryptoService
if yubiStore == nil {
cs = cryptoservice.NewCryptoService("", fileKeyStore)
} else {
cs = cryptoservice.NewCryptoService("", yubiStore, fileKeyStore)
}
keyID := args[0]
// This is an invalid ID
if len(keyID) != idSize {
fatalf("invalid key ID provided: %s", keyID)
}
keyMap := cs.ListAllKeys()
var key string
for k := range keyMap {
if filepath.Base(k) == keyID {
key = k
}
}
if key == "" {
fatalf("key with key ID: %s not found\n", keyID)
}
// List the key about to be removed
fmt.Println("Are you sure you want to remove the following key?")
fmt.Printf("%s\n(yes/no)\n", keyID)
// Ask for confirmation before removing the key, unless -y is passed
if !keyRemoveYes {
confirmed := askConfirm()
if !confirmed {
fatalf("aborting action.")
}
}
// Attempt to remove the key
err = cs.RemoveKey(key)
if err != nil {
fatalf("failed to remove key with key ID: %s, %v", keyID, err)
}
}
func keysList(cmd *cobra.Command, args []string) {
if len(args) > 0 {
cmd.Usage()
@ -177,12 +101,11 @@ func keysList(cmd *cobra.Command, args []string) {
parseConfig()
keysPath := filepath.Join(trustDir, notary.PrivDir)
backupPath := filepath.Join(trustDir, notary.BackupDir)
fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, retriever)
if err != nil {
fatalf("failed to create private key store in directory: %s", keysPath)
}
yubiStore, _ := api.NewYubiKeyStore(backupPath, retriever)
yubiStore, _ := api.NewYubiKeyStore(fileKeyStore, retriever)
var cs signed.CryptoService
if yubiStore == nil {
cs = cryptoservice.NewCryptoService("", fileKeyStore)
@ -239,12 +162,11 @@ func keysGenerateRootKey(cmd *cobra.Command, args []string) {
parseConfig()
keysPath := filepath.Join(trustDir, notary.PrivDir)
backupPath := filepath.Join(trustDir, notary.BackupDir)
fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, retriever)
if err != nil {
fatalf("failed to create private key store in directory: %s", keysPath)
}
yubiStore, err := api.NewYubiKeyStore(backupPath, retriever)
yubiStore, err := api.NewYubiKeyStore(fileKeyStore, retriever)
var cs signed.CryptoService
if err != nil {
cmd.Printf("No Yubikey detected, importing to local filesystem.")
@ -386,12 +308,11 @@ func keysImportRoot(cmd *cobra.Command, args []string) {
parseConfig()
keysPath := filepath.Join(trustDir, notary.PrivDir)
backupPath := filepath.Join(trustDir, notary.BackupDir)
fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, retriever)
if err != nil {
fatalf("failed to create private key store in directory: %s", keysPath)
}
yubiStore, err := api.NewYubiKeyStore(backupPath, retriever)
yubiStore, err := api.NewYubiKeyStore(fileKeyStore, retriever)
var cs signed.CryptoService
if err != nil {
cmd.Printf("No Yubikey detected, importing to local filesystem.")

View File

@ -12,13 +12,9 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"math/big"
"os"
"path"
"github.com/Sirupsen/logrus"
"github.com/docker/notary"
"github.com/docker/notary/passphrase"
"github.com/docker/notary/trustmanager"
"github.com/docker/notary/tuf/data"
@ -35,11 +31,11 @@ const (
var YUBIKEY_ROOT_KEY_ID = []byte{2}
type ErrBackupFailed struct {
path string
err string
}
func (err ErrBackupFailed) Error() string {
return fmt.Sprintf("Failed to backup private key to: %s", err.path)
return fmt.Sprintf("Failed to backup private key to: %s", err.err)
}
type yubiSlot struct {
@ -108,7 +104,15 @@ func (y *YubiPrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts
}
// addECDSAKey adds a key to the yubikey
func addECDSAKey(ctx *pkcs11.Ctx, session pkcs11.SessionHandle, privKey data.PrivateKey, pkcs11KeyID []byte, passRetriever passphrase.Retriever, role, backupPath string) error {
func addECDSAKey(
ctx *pkcs11.Ctx,
session pkcs11.SessionHandle,
privKey data.PrivateKey,
pkcs11KeyID []byte,
passRetriever passphrase.Retriever,
role string,
backupStore trustmanager.KeyStore,
) error {
logrus.Debugf("Got into add key with key: %s\n", privKey.ID())
// TODO(diogo): Figure out CKU_SO with yubikey
@ -165,14 +169,9 @@ func addECDSAKey(ctx *pkcs11.Ctx, session pkcs11.SessionHandle, privKey data.Pri
return fmt.Errorf("error importing: %v", err)
}
backupTo := path.Join(backupPath, privKey.ID())
err = ioutil.WriteFile(
backupTo,
privKey.Private(),
notary.PrivKeyPerms,
)
err = backupStore.AddKey(privKey.ID(), role, privKey)
if err != nil {
return ErrBackupFailed{path: backupTo}
return ErrBackupFailed{err: err.Error()}
}
return nil
@ -484,21 +483,17 @@ func getNextEmptySlot(ctx *pkcs11.Ctx, session pkcs11.SessionHandle) ([]byte, er
type YubiKeyStore struct {
passRetriever passphrase.Retriever
keys map[string]yubiSlot
backupPath string
backupStore trustmanager.KeyStore
}
func NewYubiKeyStore(backupPath string, passphraseRetriever passphrase.Retriever) (*YubiKeyStore, error) {
err := os.MkdirAll(backupPath, notary.PrivKeyPerms)
if err != nil {
return nil, err
}
func NewYubiKeyStore(backupStore trustmanager.KeyStore, passphraseRetriever passphrase.Retriever) (*YubiKeyStore, error) {
s := &YubiKeyStore{
passRetriever: passphraseRetriever,
keys: make(map[string]yubiSlot),
backupPath: backupPath,
backupStore: backupStore,
}
s.ListKeys() // populate keys field
return s, err
return s, nil
}
func (s *YubiKeyStore) ListKeys() map[string]string {
@ -542,7 +537,7 @@ func (s *YubiKeyStore) AddKey(keyID, role string, privKey data.PrivateKey) error
return err
}
logrus.Debugf("Using yubikey slot %v", slot)
err = addECDSAKey(ctx, session, privKey, slot, s.passRetriever, role, s.backupPath)
err = addECDSAKey(ctx, session, privKey, slot, s.passRetriever, role, s.backupStore)
if err == nil {
s.keys[privKey.ID()] = yubiSlot{
role: role,