diff --git a/cmd/notary/keys.go b/cmd/notary/keys.go index 6104edd987..218b68e67a 100644 --- a/cmd/notary/keys.go +++ b/cmd/notary/keys.go @@ -7,7 +7,11 @@ import ( "sort" "strings" + "github.com/docker/notary" notaryclient "github.com/docker/notary/client" + "github.com/docker/notary/cryptoservice" + "github.com/docker/notary/passphrase" + "github.com/docker/notary/trustmanager" "github.com/docker/notary/tuf/data" "github.com/spf13/cobra" @@ -93,16 +97,20 @@ func keysList(cmd *cobra.Command, args []string) { parseConfig() - cs := getCryptoService(cmd, trustDir, retriever, true) + stores := getKeyStores(cmd, trustDir, retriever, true) - // Get a map of all the keys/roles - keysMap := cs.ListAllKeys() + keys := make(map[trustmanager.KeyStore]map[string]string) + for _, store := range stores { + keys[store] = store.ListKeys() + } cmd.Println("") cmd.Println("# Root keys: ") - for k, v := range keysMap { - if v == "root" { - cmd.Println(k) + for store, keysMap := range keys { + for k, v := range keysMap { + if v == "root" { + cmd.Println(k, " - ", store.Name()) + } } } @@ -110,17 +118,20 @@ func keysList(cmd *cobra.Command, args []string) { cmd.Println("# Signing keys: ") // Get a list of all the keys - var sortedKeys []string - for k := range keysMap { - sortedKeys = append(sortedKeys, k) - } - // Sort the list of all the keys - sort.Strings(sortedKeys) + for store, keysMap := range keys { + var sortedKeys []string + for k := range keysMap { + sortedKeys = append(sortedKeys, k) + } - // Print a sorted list of the key/role - for _, k := range sortedKeys { - if keysMap[k] != "root" { - printKey(cmd, k, keysMap[k]) + // Sort the list of all the keys + sort.Strings(sortedKeys) + + // Print a sorted list of the key/role + for _, k := range sortedKeys { + if keysMap[k] != "root" { + printKey(cmd, k, keysMap[k], store.Name()) + } } } } @@ -143,7 +154,10 @@ func keysGenerateRootKey(cmd *cobra.Command, args []string) { parseConfig() - cs := getCryptoService(cmd, trustDir, retriever, true) + cs := cryptoservice.NewCryptoService( + "", + getKeyStores(cmd, trustDir, retriever, true)..., + ) pubKey, err := cs.Create(data.CanonicalRootRole, algorithm) if err != nil { @@ -164,7 +178,10 @@ func keysExport(cmd *cobra.Command, args []string) { parseConfig() - cs := getCryptoService(cmd, trustDir, retriever, false) + cs := cryptoservice.NewCryptoService( + "", + getKeyStores(cmd, trustDir, retriever, true)..., + ) exportFile, err := os.Create(exportFilename) if err != nil { @@ -204,7 +221,10 @@ func keysExportRoot(cmd *cobra.Command, args []string) { parseConfig() - cs := getCryptoService(cmd, trustDir, retriever, false) + cs := cryptoservice.NewCryptoService( + "", + getKeyStores(cmd, trustDir, retriever, true)..., + ) exportFile, err := os.Create(exportFilename) if err != nil { @@ -236,7 +256,10 @@ func keysImport(cmd *cobra.Command, args []string) { parseConfig() - cs := getCryptoService(cmd, trustDir, retriever, false) + cs := cryptoservice.NewCryptoService( + "", + getKeyStores(cmd, trustDir, retriever, true)..., + ) zipReader, err := zip.OpenReader(importFilename) if err != nil { @@ -262,7 +285,10 @@ func keysImportRoot(cmd *cobra.Command, args []string) { parseConfig() - cs := getCryptoService(cmd, trustDir, retriever, true) + cs := cryptoservice.NewCryptoService( + "", + getKeyStores(cmd, trustDir, retriever, true)..., + ) importFile, err := os.Open(importFilename) if err != nil { @@ -277,10 +303,10 @@ func keysImportRoot(cmd *cobra.Command, args []string) { } } -func printKey(cmd *cobra.Command, keyPath, alias string) { +func printKey(cmd *cobra.Command, keyPath, alias, loc string) { keyID := filepath.Base(keyPath) gun := filepath.Dir(keyPath) - cmd.Printf("%s - %s - %s\n", gun, alias, keyID) + cmd.Printf("%s - %s - %s - %s\n", gun, alias, keyID, loc) } func keysRotate(cmd *cobra.Command, args []string) { @@ -299,3 +325,28 @@ func keysRotate(cmd *cobra.Command, args []string) { fatalf(err.Error()) } } + +func getKeyStores(cmd *cobra.Command, directory string, + ret passphrase.Retriever, withHardware bool) []trustmanager.KeyStore { + + keysPath := filepath.Join(directory, notary.PrivDir) + fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, ret) + if err != nil { + fatalf("Failed to create private key store in directory: %s", keysPath) + } + + ks := []trustmanager.KeyStore{fileKeyStore} + + if withHardware { + yubiStore, err := getYubiKeyStore(fileKeyStore, ret) + if err != nil { + cmd.Println("No YubiKey detected - using local filesystem only.") + } else { + // Note that the order is important, since we want to prioritize + // the yubikey store + ks = []trustmanager.KeyStore{yubiStore, fileKeyStore} + } + } + + return ks +} diff --git a/cmd/notary/keys_nonpkcs11.go b/cmd/notary/keys_nonpkcs11.go index 31179d02e6..543cf3b2d5 100644 --- a/cmd/notary/keys_nonpkcs11.go +++ b/cmd/notary/keys_nonpkcs11.go @@ -3,22 +3,10 @@ package main import ( - "path/filepath" - - "github.com/docker/notary" - "github.com/docker/notary/cryptoservice" "github.com/docker/notary/passphrase" "github.com/docker/notary/trustmanager" - "github.com/spf13/cobra" ) -func getCryptoService(cmd *cobra.Command, directory string, - ret passphrase.Retriever, _ bool) *cryptoservice.CryptoService { - - keysPath := filepath.Join(directory, notary.PrivDir) - fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, ret) - if err != nil { - fatalf("Failed to create private key store in directory: %s", keysPath) - } - return cryptoservice.NewCryptoService("", fileKeyStore) +func getYubiKeyStore(fileKeyStore trustmanager.KeyStore, ret passphrase.Retriever) (trustmanager.KeyStore, error) { + return nil, errors.New("Not built with hardware support") } diff --git a/cmd/notary/keys_pkcs11.go b/cmd/notary/keys_pkcs11.go index e1df821d12..438d92df53 100644 --- a/cmd/notary/keys_pkcs11.go +++ b/cmd/notary/keys_pkcs11.go @@ -3,38 +3,14 @@ package main import ( - "path/filepath" - - "github.com/docker/notary" - "github.com/docker/notary/cryptoservice" "github.com/docker/notary/passphrase" "github.com/docker/notary/trustmanager" - "github.com/spf13/cobra" ) -// Build a CryptoService, optionally including a hardware keystore. Returns -// the CryptoService and whether or not a hardware keystore was included. -func getCryptoService(cmd *cobra.Command, directory string, - ret passphrase.Retriever, withHardware bool) *cryptoservice.CryptoService { - - keysPath := filepath.Join(directory, notary.PrivDir) - fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, ret) +func getYubiKeyStore(fileKeyStore trustmanager.KeyStore, ret passphrase.Retriever) (trustmanager.KeyStore, error) { + yubiStore, err := trustmanager.NewYubiKeyStore(fileKeyStore, ret) if err != nil { - fatalf("Failed to create private key store in directory: %s", keysPath) + return nil, err } - - ks := []trustmanager.KeyStore{fileKeyStore} - - if withHardware { - yubiStore, err := trustmanager.NewYubiKeyStore(fileKeyStore, ret) - if err != nil { - cmd.Println("No YubiKey detected - using local filesystem only.") - } else { - // Note that the order is important, since we want to prioritize - // the yubikey store - ks = []trustmanager.KeyStore{yubiStore, fileKeyStore} - } - } - - return cryptoservice.NewCryptoService("", ks...) + return yubiStore, nil } diff --git a/signer/keydbstore/keydbstore.go b/signer/keydbstore/keydbstore.go index c3e89a190c..e6b989351e 100644 --- a/signer/keydbstore/keydbstore.go +++ b/signer/keydbstore/keydbstore.go @@ -58,6 +58,11 @@ func NewKeyDBStore(passphraseRetriever passphrase.Retriever, defaultPassAlias, d cachedKeys: cachedKeys}, nil } +// Name returns a user friendly name for the storage location +func (s KeyDBStore) Name() string { + return "database" +} + // AddKey stores the contents of a private key. Both name and alias are ignored, // we always use Key IDs as name, and don't support aliases func (s *KeyDBStore) AddKey(name, alias string, privKey data.PrivateKey) error { diff --git a/trustmanager/keyfilestore.go b/trustmanager/keyfilestore.go index 18b8969b00..d734473e7c 100644 --- a/trustmanager/keyfilestore.go +++ b/trustmanager/keyfilestore.go @@ -1,6 +1,7 @@ package trustmanager import ( + "fmt" "path/filepath" "strings" "sync" @@ -44,6 +45,12 @@ func NewKeyFileStore(baseDir string, passphraseRetriever passphrase.Retriever) ( cachedKeys: cachedKeys}, nil } +// Name returns a user friendly name for the location this store +// keeps its data +func (s KeyFileStore) Name() string { + return fmt.Sprintf("file (%s)", s.SimpleFileStore.BaseDir()) +} + // AddKey stores the contents of a PEM-encoded private key as a PEM block func (s *KeyFileStore) AddKey(name, alias string, privKey data.PrivateKey) error { s.Lock() @@ -96,6 +103,12 @@ func NewKeyMemoryStore(passphraseRetriever passphrase.Retriever) *KeyMemoryStore cachedKeys: cachedKeys} } +// Name returns a user friendly name for the location this store +// keeps its data +func (s KeyMemoryStore) Name() string { + return "memory" +} + // AddKey stores the contents of a PEM-encoded private key as a PEM block func (s *KeyMemoryStore) AddKey(name, alias string, privKey data.PrivateKey) error { s.Lock() diff --git a/trustmanager/keystore.go b/trustmanager/keystore.go index 4a06d9962e..88a0e3d774 100644 --- a/trustmanager/keystore.go +++ b/trustmanager/keystore.go @@ -46,6 +46,7 @@ type KeyStore interface { RemoveKey(name string) error ExportKey(name string) ([]byte, error) ImportKey(pemBytes []byte, alias string) error + Name() string } type cachedKey struct { diff --git a/trustmanager/yubikeystore.go b/trustmanager/yubikeystore.go index 6945944c8c..0a1f7fbd69 100644 --- a/trustmanager/yubikeystore.go +++ b/trustmanager/yubikeystore.go @@ -580,6 +580,12 @@ func NewYubiKeyStore(backupStore KeyStore, passphraseRetriever passphrase.Retrie return s, nil } +// Name returns a user friendly name for the location this store +// keeps its data +func (s YubiKeyStore) Name() string { + return "yubikey" +} + func (s *YubiKeyStore) ListKeys() map[string]string { if len(s.keys) > 0 { return buildKeyMap(s.keys)