mirror of https://github.com/docker/docs.git
				
				
				
			Merge pull request #49 from docker/key_locations
Key locations Signed-off-by: David Lawrence <david.lawrence@docker.com> Signed-off-by: David Lawrence <dclwrnc@gmail.com> (github: endophage)
This commit is contained in:
		
						commit
						189118164d
					
				|  | @ -23,6 +23,7 @@ import ( | ||||||
| 	"github.com/docker/notary/server" | 	"github.com/docker/notary/server" | ||||||
| 	"github.com/docker/notary/server/storage" | 	"github.com/docker/notary/server/storage" | ||||||
| 	"github.com/docker/notary/trustmanager" | 	"github.com/docker/notary/trustmanager" | ||||||
|  | 	"github.com/docker/notary/tuf/data" | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| 	"golang.org/x/net/context" | 	"golang.org/x/net/context" | ||||||
|  | @ -50,10 +51,7 @@ func setupServer() *httptest.Server { | ||||||
| 	ctx := context.WithValue( | 	ctx := context.WithValue( | ||||||
| 		context.Background(), "metaStore", storage.NewMemStorage()) | 		context.Background(), "metaStore", storage.NewMemStorage()) | ||||||
| 
 | 
 | ||||||
| 	// Do not pass one of the const KeyAlgorithms here as the value! Passing a
 | 	ctx = context.WithValue(ctx, "keyAlgorithm", data.ECDSAKey) | ||||||
| 	// string is in itself good test that we are handling it correctly as we
 |  | ||||||
| 	// will be receiving a string from the configuration.
 |  | ||||||
| 	ctx = context.WithValue(ctx, "keyAlgorithm", "ecdsa") |  | ||||||
| 
 | 
 | ||||||
| 	// Eat the logs instead of spewing them out
 | 	// Eat the logs instead of spewing them out
 | ||||||
| 	var b bytes.Buffer | 	var b bytes.Buffer | ||||||
|  | @ -181,19 +179,24 @@ func GetKeys(t *testing.T, tempDir string) ([]string, []string) { | ||||||
| func assertNumKeys(t *testing.T, tempDir string, numRoot, numSigning int, | func assertNumKeys(t *testing.T, tempDir string, numRoot, numSigning int, | ||||||
| 	rootOnDisk bool) ([]string, []string) { | 	rootOnDisk bool) ([]string, []string) { | ||||||
| 
 | 
 | ||||||
|  | 	uniqueKeys := make(map[string]struct{}) | ||||||
| 	root, signing := GetKeys(t, tempDir) | 	root, signing := GetKeys(t, tempDir) | ||||||
| 	assert.Len(t, root, numRoot) |  | ||||||
| 	assert.Len(t, signing, numSigning) | 	assert.Len(t, signing, numSigning) | ||||||
| 	for _, rootKeyID := range root { | 	for i, rootKeyLine := range root { | ||||||
|  | 		keyID := strings.Split(rootKeyLine, "-")[0] | ||||||
|  | 		keyID = strings.TrimSpace(keyID) | ||||||
|  | 		root[i] = keyID | ||||||
|  | 		uniqueKeys[keyID] = struct{}{} | ||||||
| 		_, err := os.Stat(filepath.Join( | 		_, err := os.Stat(filepath.Join( | ||||||
| 			tempDir, "private", "root_keys", rootKeyID+"_root.key")) | 			tempDir, "private", "root_keys", keyID+"_root.key")) | ||||||
| 		// os.IsExist checks to see if the error is because a file already
 | 		// os.IsExist checks to see if the error is because a file already
 | ||||||
| 		// exist, and hence doesn't actually the right funciton to use here
 | 		// exist, and hence doesn't actually the right funciton to use here
 | ||||||
| 		assert.Equal(t, rootOnDisk, !os.IsNotExist(err)) | 		assert.Equal(t, rootOnDisk, !os.IsNotExist(err)) | ||||||
| 
 | 
 | ||||||
| 		// this function is declared is in the build-tagged setup files
 | 		// this function is declared is in the build-tagged setup files
 | ||||||
| 		verifyRootKeyOnHardware(t, rootKeyID) | 		verifyRootKeyOnHardware(t, keyID) | ||||||
| 	} | 	} | ||||||
|  | 	assert.Len(t, uniqueKeys, numRoot) | ||||||
| 	return root, signing | 	return root, signing | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -245,7 +248,7 @@ func TestClientKeyGenerationRotation(t *testing.T) { | ||||||
| 	assertNumKeys(t, tempDir, 0, 0, true) | 	assertNumKeys(t, tempDir, 0, 0, true) | ||||||
| 
 | 
 | ||||||
| 	// generate root key produces a single root key and no other keys
 | 	// generate root key produces a single root key and no other keys
 | ||||||
| 	_, err = runCommand(t, tempDir, "key", "generate", "ecdsa") | 	_, err = runCommand(t, tempDir, "key", "generate", data.ECDSAKey) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assertNumKeys(t, tempDir, 1, 0, true) | 	assertNumKeys(t, tempDir, 1, 0, true) | ||||||
| 
 | 
 | ||||||
|  | @ -345,7 +348,7 @@ func TestClientKeyImportExportRootAndSigning(t *testing.T) { | ||||||
| 
 | 
 | ||||||
| 	_, err = runCommand(t, dirs[1], "key", "import", zipfile) | 	_, err = runCommand(t, dirs[1], "key", "import", zipfile) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assertNumKeys(t, dirs[1], 1, 4, true) // all keys should be there
 | 	assertNumKeys(t, dirs[1], 1, 4, !rootOnHardware()) // all keys should be there
 | ||||||
| 
 | 
 | ||||||
| 	// can list and publish to both repos using imported keys
 | 	// can list and publish to both repos using imported keys
 | ||||||
| 	for _, gun := range []string{"gun1", "gun2"} { | 	for _, gun := range []string{"gun1", "gun2"} { | ||||||
|  | @ -383,7 +386,7 @@ func exportRoot(t *testing.T, exportTo string) string { | ||||||
| 	defer os.RemoveAll(tempDir) | 	defer os.RemoveAll(tempDir) | ||||||
| 
 | 
 | ||||||
| 	// generate root key produces a single root key and no other keys
 | 	// generate root key produces a single root key and no other keys
 | ||||||
| 	_, err = runCommand(t, tempDir, "key", "generate", "ecdsa") | 	_, err = runCommand(t, tempDir, "key", "generate", data.ECDSAKey) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	oldRoot, _ := assertNumKeys(t, tempDir, 1, 0, true) | 	oldRoot, _ := assertNumKeys(t, tempDir, 1, 0, true) | ||||||
| 
 | 
 | ||||||
|  | @ -505,7 +508,6 @@ func TestClientCertInteraction(t *testing.T) { | ||||||
| 	_, err = runCommand(t, tempDir, "cert", "remove", certID, "-y", "-g", "") | 	_, err = runCommand(t, tempDir, "cert", "remove", certID, "-y", "-g", "") | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assertNumCerts(t, tempDir, 0) | 	assertNumCerts(t, tempDir, 0) | ||||||
| 
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMain(m *testing.M) { | func TestMain(m *testing.M) { | ||||||
|  |  | ||||||
|  | @ -7,7 +7,11 @@ import ( | ||||||
| 	"sort" | 	"sort" | ||||||
| 	"strings" | 	"strings" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/docker/notary" | ||||||
| 	notaryclient "github.com/docker/notary/client" | 	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/docker/notary/tuf/data" | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
|  | @ -93,16 +97,20 @@ func keysList(cmd *cobra.Command, args []string) { | ||||||
| 
 | 
 | ||||||
| 	parseConfig() | 	parseConfig() | ||||||
| 
 | 
 | ||||||
| 	cs := getCryptoService(cmd, trustDir, retriever, true) | 	stores := getKeyStores(cmd, trustDir, retriever, true) | ||||||
| 
 | 
 | ||||||
| 	// Get a map of all the keys/roles
 | 	keys := make(map[trustmanager.KeyStore]map[string]string) | ||||||
| 	keysMap := cs.ListAllKeys() | 	for _, store := range stores { | ||||||
|  | 		keys[store] = store.ListKeys() | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	cmd.Println("") | 	cmd.Println("") | ||||||
| 	cmd.Println("# Root keys: ") | 	cmd.Println("# Root keys: ") | ||||||
|  | 	for store, keysMap := range keys { | ||||||
| 		for k, v := range keysMap { | 		for k, v := range keysMap { | ||||||
| 			if v == "root" { | 			if v == "root" { | ||||||
| 			cmd.Println(k) | 				cmd.Println(k, "-", store.Name()) | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -110,17 +118,20 @@ func keysList(cmd *cobra.Command, args []string) { | ||||||
| 	cmd.Println("# Signing keys: ") | 	cmd.Println("# Signing keys: ") | ||||||
| 
 | 
 | ||||||
| 	// Get a list of all the keys
 | 	// Get a list of all the keys
 | ||||||
|  | 	for store, keysMap := range keys { | ||||||
| 		var sortedKeys []string | 		var sortedKeys []string | ||||||
| 		for k := range keysMap { | 		for k := range keysMap { | ||||||
| 			sortedKeys = append(sortedKeys, k) | 			sortedKeys = append(sortedKeys, k) | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
| 		// Sort the list of all the keys
 | 		// Sort the list of all the keys
 | ||||||
| 		sort.Strings(sortedKeys) | 		sort.Strings(sortedKeys) | ||||||
| 
 | 
 | ||||||
| 		// Print a sorted list of the key/role
 | 		// Print a sorted list of the key/role
 | ||||||
| 		for _, k := range sortedKeys { | 		for _, k := range sortedKeys { | ||||||
| 			if keysMap[k] != "root" { | 			if keysMap[k] != "root" { | ||||||
| 			printKey(cmd, k, keysMap[k]) | 				printKey(cmd, k, keysMap[k], store.Name()) | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -143,7 +154,10 @@ func keysGenerateRootKey(cmd *cobra.Command, args []string) { | ||||||
| 
 | 
 | ||||||
| 	parseConfig() | 	parseConfig() | ||||||
| 
 | 
 | ||||||
| 	cs := getCryptoService(cmd, trustDir, retriever, true) | 	cs := cryptoservice.NewCryptoService( | ||||||
|  | 		"", | ||||||
|  | 		getKeyStores(cmd, trustDir, retriever, true)..., | ||||||
|  | 	) | ||||||
| 
 | 
 | ||||||
| 	pubKey, err := cs.Create(data.CanonicalRootRole, algorithm) | 	pubKey, err := cs.Create(data.CanonicalRootRole, algorithm) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -164,7 +178,10 @@ func keysExport(cmd *cobra.Command, args []string) { | ||||||
| 
 | 
 | ||||||
| 	parseConfig() | 	parseConfig() | ||||||
| 
 | 
 | ||||||
| 	cs := getCryptoService(cmd, trustDir, retriever, false) | 	cs := cryptoservice.NewCryptoService( | ||||||
|  | 		"", | ||||||
|  | 		getKeyStores(cmd, trustDir, retriever, true)..., | ||||||
|  | 	) | ||||||
| 
 | 
 | ||||||
| 	exportFile, err := os.Create(exportFilename) | 	exportFile, err := os.Create(exportFilename) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -204,7 +221,10 @@ func keysExportRoot(cmd *cobra.Command, args []string) { | ||||||
| 
 | 
 | ||||||
| 	parseConfig() | 	parseConfig() | ||||||
| 
 | 
 | ||||||
| 	cs := getCryptoService(cmd, trustDir, retriever, false) | 	cs := cryptoservice.NewCryptoService( | ||||||
|  | 		"", | ||||||
|  | 		getKeyStores(cmd, trustDir, retriever, true)..., | ||||||
|  | 	) | ||||||
| 
 | 
 | ||||||
| 	exportFile, err := os.Create(exportFilename) | 	exportFile, err := os.Create(exportFilename) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -236,7 +256,10 @@ func keysImport(cmd *cobra.Command, args []string) { | ||||||
| 
 | 
 | ||||||
| 	parseConfig() | 	parseConfig() | ||||||
| 
 | 
 | ||||||
| 	cs := getCryptoService(cmd, trustDir, retriever, false) | 	cs := cryptoservice.NewCryptoService( | ||||||
|  | 		"", | ||||||
|  | 		getKeyStores(cmd, trustDir, retriever, true)..., | ||||||
|  | 	) | ||||||
| 
 | 
 | ||||||
| 	zipReader, err := zip.OpenReader(importFilename) | 	zipReader, err := zip.OpenReader(importFilename) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -262,7 +285,10 @@ func keysImportRoot(cmd *cobra.Command, args []string) { | ||||||
| 
 | 
 | ||||||
| 	parseConfig() | 	parseConfig() | ||||||
| 
 | 
 | ||||||
| 	cs := getCryptoService(cmd, trustDir, retriever, true) | 	cs := cryptoservice.NewCryptoService( | ||||||
|  | 		"", | ||||||
|  | 		getKeyStores(cmd, trustDir, retriever, true)..., | ||||||
|  | 	) | ||||||
| 
 | 
 | ||||||
| 	importFile, err := os.Open(importFilename) | 	importFile, err := os.Open(importFilename) | ||||||
| 	if err != nil { | 	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) | 	keyID := filepath.Base(keyPath) | ||||||
| 	gun := filepath.Dir(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) { | func keysRotate(cmd *cobra.Command, args []string) { | ||||||
|  | @ -299,3 +325,26 @@ func keysRotate(cmd *cobra.Command, args []string) { | ||||||
| 		fatalf(err.Error()) | 		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 && yubiStore != nil { | ||||||
|  | 			// Note that the order is important, since we want to prioritize
 | ||||||
|  | 			// the yubikey store
 | ||||||
|  | 			ks = []trustmanager.KeyStore{yubiStore, fileKeyStore} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ks | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -3,22 +3,12 @@ | ||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"path/filepath" | 	"errors" | ||||||
| 
 | 
 | ||||||
| 	"github.com/docker/notary" |  | ||||||
| 	"github.com/docker/notary/cryptoservice" |  | ||||||
| 	"github.com/docker/notary/passphrase" | 	"github.com/docker/notary/passphrase" | ||||||
| 	"github.com/docker/notary/trustmanager" | 	"github.com/docker/notary/trustmanager" | ||||||
| 	"github.com/spf13/cobra" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func getCryptoService(cmd *cobra.Command, directory string, | func getYubiKeyStore(fileKeyStore trustmanager.KeyStore, ret passphrase.Retriever) (trustmanager.KeyStore, error) { | ||||||
| 	ret passphrase.Retriever, _ bool) *cryptoservice.CryptoService { | 	return nil, errors.New("Not built with hardware support") | ||||||
| 
 |  | ||||||
| 	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) |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -3,38 +3,10 @@ | ||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"path/filepath" |  | ||||||
| 
 |  | ||||||
| 	"github.com/docker/notary" |  | ||||||
| 	"github.com/docker/notary/cryptoservice" |  | ||||||
| 	"github.com/docker/notary/passphrase" | 	"github.com/docker/notary/passphrase" | ||||||
| 	"github.com/docker/notary/trustmanager" | 	"github.com/docker/notary/trustmanager" | ||||||
| 	"github.com/spf13/cobra" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Build a CryptoService, optionally including a hardware keystore.  Returns
 | func getYubiKeyStore(fileKeyStore trustmanager.KeyStore, ret passphrase.Retriever) (trustmanager.KeyStore, error) { | ||||||
| // the CryptoService and whether or not a hardware keystore was included.
 | 	return trustmanager.NewYubiKeyStore(fileKeyStore, ret) | ||||||
| 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) |  | ||||||
| 	if err != nil { |  | ||||||
| 		fatalf("Failed to create private key store in directory: %s", keysPath) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	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...) |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -197,11 +197,20 @@ func (cs *CryptoService) ImportKeysZip(zipReader zip.Reader) error { | ||||||
| 		if keyName[len(keyName)-5:] == "_root" { | 		if keyName[len(keyName)-5:] == "_root" { | ||||||
| 			keyName = "root" | 			keyName = "root" | ||||||
| 		} | 		} | ||||||
|  | 		// try to import the key to all key stores. As long as one of them
 | ||||||
|  | 		// succeeds, consider it a success
 | ||||||
|  | 		var tmpErr error | ||||||
| 		for _, ks := range cs.keyStores { | 		for _, ks := range cs.keyStores { | ||||||
| 			if err := ks.ImportKey(pemBytes, keyName); err != nil { | 			if err := ks.ImportKey(pemBytes, keyName); err != nil { | ||||||
| 				return err | 				tmpErr = err | ||||||
|  | 			} else { | ||||||
|  | 				tmpErr = nil | ||||||
|  | 				break | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		if tmpErr != nil { | ||||||
|  | 			return tmpErr | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
|  |  | ||||||
|  | @ -58,6 +58,11 @@ func NewKeyDBStore(passphraseRetriever passphrase.Retriever, defaultPassAlias, d | ||||||
| 		cachedKeys:       cachedKeys}, nil | 		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,
 | // 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
 | // we always use Key IDs as name, and don't support aliases
 | ||||||
| func (s *KeyDBStore) AddKey(name, alias string, privKey data.PrivateKey) error { | func (s *KeyDBStore) AddKey(name, alias string, privKey data.PrivateKey) error { | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| package trustmanager | package trustmanager | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"sync" | 	"sync" | ||||||
|  | @ -44,6 +45,12 @@ func NewKeyFileStore(baseDir string, passphraseRetriever passphrase.Retriever) ( | ||||||
| 		cachedKeys: cachedKeys}, nil | 		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
 | // 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 { | func (s *KeyFileStore) AddKey(name, alias string, privKey data.PrivateKey) error { | ||||||
| 	s.Lock() | 	s.Lock() | ||||||
|  | @ -96,6 +103,12 @@ func NewKeyMemoryStore(passphraseRetriever passphrase.Retriever) *KeyMemoryStore | ||||||
| 		cachedKeys: cachedKeys} | 		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
 | // 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 { | func (s *KeyMemoryStore) AddKey(name, alias string, privKey data.PrivateKey) error { | ||||||
| 	s.Lock() | 	s.Lock() | ||||||
|  |  | ||||||
|  | @ -46,6 +46,7 @@ type KeyStore interface { | ||||||
| 	RemoveKey(name string) error | 	RemoveKey(name string) error | ||||||
| 	ExportKey(name string) ([]byte, error) | 	ExportKey(name string) ([]byte, error) | ||||||
| 	ImportKey(pemBytes []byte, alias string) error | 	ImportKey(pemBytes []byte, alias string) error | ||||||
|  | 	Name() string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type cachedKey struct { | type cachedKey struct { | ||||||
|  |  | ||||||
|  | @ -398,12 +398,12 @@ func ED25519ToPrivateKey(privKeyBytes []byte) (data.PrivateKey, error) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func blockType(k data.PrivateKey) (string, error) { | func blockType(k data.PrivateKey) (string, error) { | ||||||
| 	switch k.(type) { | 	switch k.Algorithm() { | ||||||
| 	case *data.RSAPrivateKey: | 	case data.RSAKey, data.RSAx509Key: | ||||||
| 		return "RSA PRIVATE KEY", nil | 		return "RSA PRIVATE KEY", nil | ||||||
| 	case *data.ECDSAPrivateKey: | 	case data.ECDSAKey, data.ECDSAx509Key: | ||||||
| 		return "EC PRIVATE KEY", nil | 		return "EC PRIVATE KEY", nil | ||||||
| 	case *data.ED25519PrivateKey: | 	case data.ED25519Key: | ||||||
| 		return "ED25519 PRIVATE KEY", nil | 		return "ED25519 PRIVATE KEY", nil | ||||||
| 	default: | 	default: | ||||||
| 		return "", fmt.Errorf("algorithm %s not supported", k.Algorithm()) | 		return "", fmt.Errorf("algorithm %s not supported", k.Algorithm()) | ||||||
|  |  | ||||||
|  | @ -580,6 +580,12 @@ func NewYubiKeyStore(backupStore KeyStore, passphraseRetriever passphrase.Retrie | ||||||
| 	return s, nil | 	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 { | func (s *YubiKeyStore) ListKeys() map[string]string { | ||||||
| 	if len(s.keys) > 0 { | 	if len(s.keys) > 0 { | ||||||
| 		return buildKeyMap(s.keys) | 		return buildKeyMap(s.keys) | ||||||
|  | @ -701,13 +707,16 @@ func (s *YubiKeyStore) ExportKey(keyID string) ([]byte, error) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ImportKey imports a root key into a Yubikey
 | // ImportKey imports a root key into a Yubikey
 | ||||||
| func (s *YubiKeyStore) ImportKey(pemBytes []byte, keyID string) error { | func (s *YubiKeyStore) ImportKey(pemBytes []byte, keyPath string) error { | ||||||
| 	logrus.Debugf("Attempting to import: %s key inside of YubiKeyStore", keyID) | 	logrus.Debugf("Attempting to import: %s key inside of YubiKeyStore", keyPath) | ||||||
| 	privKey, _, err := GetPasswdDecryptBytes( | 	privKey, _, err := GetPasswdDecryptBytes( | ||||||
| 		s.passRetriever, pemBytes, "", "imported root") | 		s.passRetriever, pemBytes, "", "imported root") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  | 	if keyPath != data.CanonicalRootRole { | ||||||
|  | 		return fmt.Errorf("yubikey only supports storing root keys") | ||||||
|  | 	} | ||||||
| 	return s.addKey(privKey.ID(), "root", privKey, false) | 	return s.addKey(privKey.ID(), "root", privKey, false) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -129,7 +129,7 @@ func TestImportKey(t *testing.T) { | ||||||
| 	pemBytes, err := EncryptPrivateKey(privKey, "passphrase") | 	pemBytes, err := EncryptPrivateKey(privKey, "passphrase") | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 
 | 
 | ||||||
| 	err = store.ImportKey(pemBytes, privKey.ID()) | 	err = store.ImportKey(pemBytes, "root") | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 
 | 
 | ||||||
| 	// key is not in backup store
 | 	// key is not in backup store
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue