From 479333ca7bf8fd9a76c358292e27b5ec9a07039e Mon Sep 17 00:00:00 2001 From: Aaron Lehmann Date: Wed, 15 Jul 2015 13:34:32 -0700 Subject: [PATCH] Add ExportRootKey and ImportRootKey functions Also add a unit test Signed-off-by: Aaron Lehmann --- keystoremanager/import_export.go | 30 ++++++++++++ keystoremanager/import_export_test.go | 69 ++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/keystoremanager/import_export.go b/keystoremanager/import_export.go index b36fdf112b..da48fbbd23 100644 --- a/keystoremanager/import_export.go +++ b/keystoremanager/import_export.go @@ -16,6 +16,36 @@ import ( "github.com/endophage/gotuf/data" ) +// ExportRootKey exports the specified root key to an io.Writer in PEM format. +// The key's existing encryption is preserved. +func (km *KeyStoreManager) ExportRootKey(dest io.Writer, keyID string) error { + pemBytes, err := km.rootKeyStore.Get(keyID) + if err != nil { + return err + } + + _, err = dest.Write(pemBytes) + return err +} + +// ImportRootKey imports a root in PEM format key from an io.Reader +// The key's existing encryption is preserved. The keyID parameter is +// necessary because otherwise we'd need the passphrase to decrypt the key +// in order to compute the ID. +func (km *KeyStoreManager) ImportRootKey(source io.Reader, keyID string) error { + pemBytes, err := ioutil.ReadAll(source) + if err != nil { + return err + } + + err = km.rootKeyStore.Add(keyID, pemBytes) + if err != nil { + return err + } + + return err +} + func moveKeysWithNewPassphrase(oldKeyStore, newKeyStore *trustmanager.KeyFileStore, outputPassphrase string) error { // List all files but no symlinks for _, f := range oldKeyStore.ListFiles(false) { diff --git a/keystoremanager/import_export_test.go b/keystoremanager/import_export_test.go index d270098205..0d63e37b8c 100644 --- a/keystoremanager/import_export_test.go +++ b/keystoremanager/import_export_test.go @@ -69,7 +69,7 @@ func TestImportExportZip(t *testing.T) { tempZipFile.Close() assert.NoError(t, err) - // Check the contents of the zip file + // Reopen the zip file for importing zipReader, err := zip.OpenReader(tempZipFilePath) assert.NoError(t, err, "could not open zip file") @@ -173,3 +173,70 @@ func TestImportExportZip(t *testing.T) { _, err = os.Stat(filepath.Join(tempBaseDir2, "private", "root_keys", rootKeyFilename)) assert.NoError(t, err, "missing root key") } + +func TestImportExportRootKey(t *testing.T) { + gun := "docker.com/notary" + oldPassphrase := "oldPassphrase" + + // Temporary directory where test files will be created + tempBaseDir, err := ioutil.TempDir("", "notary-test-") + defer os.RemoveAll(tempBaseDir) + + assert.NoError(t, err, "failed to create a temporary directory: %s", err) + + ts, _ := createTestServer(t) + defer ts.Close() + + repo, err := client.NewNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport) + assert.NoError(t, err, "error creating repo: %s", err) + + rootKeyID, err := repo.KeyStoreManager.GenRootKey(data.ECDSAKey.String(), oldPassphrase) + assert.NoError(t, err, "error generating root key: %s", err) + + rootCryptoService, err := repo.KeyStoreManager.GetRootCryptoService(rootKeyID, oldPassphrase) + assert.NoError(t, err, "error retrieving root key: %s", err) + + err = repo.Initialize(rootCryptoService) + assert.NoError(t, err, "error creating repository: %s", err) + + tempKeyFile, err := ioutil.TempFile("", "notary-test-export-") + tempKeyFilePath := tempKeyFile.Name() + defer os.Remove(tempKeyFilePath) + + err = repo.KeyStoreManager.ExportRootKey(tempKeyFile, rootKeyID) + assert.NoError(t, err) + tempKeyFile.Close() + + // Create new repo to test import + tempBaseDir2, err := ioutil.TempDir("", "notary-test-") + defer os.RemoveAll(tempBaseDir2) + + assert.NoError(t, err, "failed to create a temporary directory: %s", err) + + repo2, err := client.NewNotaryRepository(tempBaseDir2, gun, ts.URL, http.DefaultTransport) + assert.NoError(t, err, "error creating repo: %s", err) + + rootKeyID2, err := repo2.KeyStoreManager.GenRootKey(data.ECDSAKey.String(), "oldPassphrase") + assert.NoError(t, err, "error generating root key: %s", err) + + rootCryptoService2, err := repo2.KeyStoreManager.GetRootCryptoService(rootKeyID2, "oldPassphrase") + assert.NoError(t, err, "error retrieving root key: %s", err) + + err = repo2.Initialize(rootCryptoService2) + assert.NoError(t, err, "error creating repository: %s", err) + + // Check the contents of the zip file + keyReader, err := os.Open(tempKeyFilePath) + assert.NoError(t, err, "could not open key file") + + err = repo2.KeyStoreManager.ImportRootKey(keyReader, rootKeyID) + assert.NoError(t, err) + keyReader.Close() + + // Look for repo's root key in repo2 + // There should be a file named after the key ID of the root key we + // imported. + rootKeyFilename := rootKeyID + ".key" + _, err = os.Stat(filepath.Join(tempBaseDir2, "private", "root_keys", rootKeyFilename)) + assert.NoError(t, err, "missing root key") +}