From 03a6bb5dc482b585e79ae62eb9369360369eb5c3 Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Tue, 1 Aug 2017 18:11:45 -0700 Subject: [PATCH 1/3] notary client interface Signed-off-by: David Lawrence (github: endophage) --- client/backwards_compatibility_test.go | 19 ++-- client/client.go | 39 ++++--- client/client_test.go | 100 +++++++++--------- client/interface.go | 46 +++++++++ cmd/notary/keys.go | 2 +- cmd/notary/keys_test.go | 10 +- cmd/notary/repo_factory.go | 45 ++++++++ cmd/notary/tuf.go | 138 +++++-------------------- storage/filestore.go | 2 +- utils/configuration_linux_test.go | 44 ++++++++ utils/configuration_test.go | 40 ------- 11 files changed, 257 insertions(+), 228 deletions(-) create mode 100644 client/interface.go create mode 100644 cmd/notary/repo_factory.go create mode 100644 utils/configuration_linux_test.go diff --git a/client/backwards_compatibility_test.go b/client/backwards_compatibility_test.go index edbc247bf..141a6037d 100644 --- a/client/backwards_compatibility_test.go +++ b/client/backwards_compatibility_test.go @@ -35,12 +35,16 @@ func requireValidFixture(t *testing.T, notaryRepo *NotaryRepository) { // recursively copies the contents of one directory into another - ignores // symlinks func recursiveCopy(sourceDir, targetDir string) error { + sourceDir, err := filepath.Abs(sourceDir) + if err != nil { + return err + } return filepath.Walk(sourceDir, func(fp string, fi os.FileInfo, err error) error { if err != nil { return err } - targetFP := filepath.Join(targetDir, strings.TrimPrefix(fp, sourceDir+"/")) + targetFP := filepath.Join(targetDir, strings.TrimPrefix(fp, sourceDir)) if fi.IsDir() { return os.MkdirAll(targetFP, fi.Mode()) @@ -68,7 +72,7 @@ func recursiveCopy(sourceDir, targetDir string) error { if err != nil { return err } - return nil + return out.Sync() }) } @@ -91,7 +95,8 @@ func Test0Dot1Migration(t *testing.T) { require.NoError(t, err, "error creating repo: %s", err) // check that root_keys and tuf_keys are gone and that all corect keys are present and have the correct headers - files, _ := ioutil.ReadDir(filepath.Join(tmpDir, notary.PrivDir)) + files, err := ioutil.ReadDir(filepath.Join(tmpDir, notary.PrivDir)) + require.NoError(t, err) require.Equal(t, files[0].Name(), "7fc757801b9bab4ec9e35bfe7a6b61668ff6f4c81b5632af19e6c728ab799599.key") targKey, err := os.OpenFile(filepath.Join(tmpDir, notary.PrivDir, "7fc757801b9bab4ec9e35bfe7a6b61668ff6f4c81b5632af19e6c728ab799599.key"), os.O_RDONLY, notary.PrivExecPerms) require.NoError(t, err) @@ -220,10 +225,10 @@ func Test0Dot1RepoFormat(t *testing.T) { require.Len(t, targets, 2) // Also check that we can add/remove keys by rotating keys - oldTargetsKeys := repo.CryptoService.ListKeys(data.CanonicalTargetsRole) + oldTargetsKeys := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) require.NoError(t, repo.RotateKey(data.CanonicalTargetsRole, false, nil)) require.NoError(t, repo.Publish()) - newTargetsKeys := repo.CryptoService.ListKeys(data.CanonicalTargetsRole) + newTargetsKeys := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) require.Len(t, oldTargetsKeys, 1) require.Len(t, newTargetsKeys, 1) @@ -287,10 +292,10 @@ func Test0Dot3RepoFormat(t *testing.T) { require.Equal(t, data.RoleName("targets/releases"), delegations[0].Name) // Also check that we can add/remove keys by rotating keys - oldTargetsKeys := repo.CryptoService.ListKeys(data.CanonicalTargetsRole) + oldTargetsKeys := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) require.NoError(t, repo.RotateKey(data.CanonicalTargetsRole, false, nil)) require.NoError(t, repo.Publish()) - newTargetsKeys := repo.CryptoService.ListKeys(data.CanonicalTargetsRole) + newTargetsKeys := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) require.Len(t, oldTargetsKeys, 1) require.Len(t, newTargetsKeys, 1) diff --git a/client/client.go b/client/client.go index 5ca766678..d1f668cb2 100644 --- a/client/client.go +++ b/client/client.go @@ -45,7 +45,7 @@ type NotaryRepository struct { changelist changelist.Changelist cache store.MetadataStore remoteStore store.RemoteStore - CryptoService signed.CryptoService + cryptoService signed.CryptoService tufRepo *tuf.Repo invalid *tuf.Repo // known data that was parsable but deemed invalid roundTrip http.RoundTripper @@ -120,7 +120,7 @@ func NewNotaryRepository(baseDir string, gun data.GUN, baseURL string, remoteSto changelist: cl, cache: cache, remoteStore: remoteStore, - CryptoService: cryptoService, + cryptoService: cryptoService, trustPinning: trustPinning, LegacyVersions: 0, // By default, don't sign with legacy roles } @@ -182,6 +182,11 @@ func rootCertKey(gun data.GUN, privKey data.PrivateKey) (data.PublicKey, error) return x509PublicKey, nil } +// CryptoService is the getter for the repository's CryptoService +func (r *NotaryRepository) CryptoService() signed.CryptoService { + return r.cryptoService +} + // initialize initializes the notary repository with a set of rootkeys, root certificates and roles. func (r *NotaryRepository) initialize(rootKeyIDs []string, rootCerts []data.PublicKey, serverManagedRoles ...data.RoleName) error { @@ -234,7 +239,7 @@ func (r *NotaryRepository) initialize(rootKeyIDs []string, rootCerts []data.Publ return err } - r.tufRepo = tuf.NewRepo(r.CryptoService) + r.tufRepo = tuf.NewRepo(r.CryptoService()) if err := r.tufRepo.InitRoot( rootRole, @@ -264,7 +269,7 @@ func (r *NotaryRepository) initialize(rootKeyIDs []string, rootCerts []data.Publ func (r *NotaryRepository) createNewPublicKeyFromKeyIDs(keyIDs []string) ([]data.PublicKey, error) { publicKeys := []data.PublicKey{} - privKeys, err := getAllPrivKeys(keyIDs, r.CryptoService) + privKeys, err := getAllPrivKeys(keyIDs, r.CryptoService()) if err != nil { return nil, err } @@ -298,7 +303,7 @@ func (r *NotaryRepository) publicKeysOfKeyIDs(keyIDs []string, pubKeys []data.Pu // forms matching key pairs func matchKeyIdsWithPubKeys(r *NotaryRepository, ids []string, pubKeys []data.PublicKey) error { for i := 0; i < len(ids); i++ { - privKey, _, err := r.CryptoService.GetPrivateKey(ids[i]) + privKey, _, err := r.CryptoService().GetPrivateKey(ids[i]) if err != nil { return fmt.Errorf("could not get the private key matching id %v: %v", ids[i], err) } @@ -348,7 +353,7 @@ func (r *NotaryRepository) InitializeWithCertificate(rootKeyIDs []string, rootCe if len(rootKeyIDs) == 0 && len(rootCerts) != 0 { rootKeyIDs = []string{} availableRootKeyIDs := make(map[string]bool) - for _, k := range nRepo.CryptoService.ListKeys(data.CanonicalRootRole) { + for _, k := range nRepo.CryptoService().ListKeys(data.CanonicalRootRole) { availableRootKeyIDs[k] = true } @@ -376,7 +381,7 @@ func (r *NotaryRepository) initializeRoles(rootKeys []data.PublicKey, localRoles for _, role := range localRoles { // This is currently hardcoding the keys to ECDSA. var key data.PublicKey - key, err = r.CryptoService.Create(role, r.gun, data.ECDSAKey) + key, err = r.CryptoService().Create(role, r.gun, data.ECDSAKey) if err != nil { return } @@ -928,7 +933,7 @@ func signTargets(updates map[data.RoleName][]byte, repo *tuf.Repo, initialPublis // snapshots are supported, if the snapshot metadata fails to load, that's ok. // This assumes that bootstrapRepo is only used by Publish() or RotateKey() func (r *NotaryRepository) bootstrapRepo() error { - b := tuf.NewRepoBuilder(r.gun, r.CryptoService, r.trustPinning) + b := tuf.NewRepoBuilder(r.gun, r.CryptoService(), r.trustPinning) logrus.Debugf("Loading trusted collection.") @@ -1063,10 +1068,10 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufClient, e minVersion := 1 // the old root on disk should not be validated against any trust pinning configuration // because if we have an old root, it itself is the thing that pins trust - oldBuilder := tuf.NewRepoBuilder(r.gun, r.CryptoService, trustpinning.TrustPinConfig{}) + oldBuilder := tuf.NewRepoBuilder(r.gun, r.CryptoService(), trustpinning.TrustPinConfig{}) // by default, we want to use the trust pinning configuration on any new root that we download - newBuilder := tuf.NewRepoBuilder(r.gun, r.CryptoService, r.trustPinning) + newBuilder := tuf.NewRepoBuilder(r.gun, r.CryptoService(), r.trustPinning) // Try to read root from cache first. We will trust this root until we detect a problem // during update which will cause us to download a new root and perform a rotation. @@ -1080,7 +1085,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufClient, e // again, the root on disk is the source of trust pinning, so use an empty trust // pinning configuration - newBuilder = tuf.NewRepoBuilder(r.gun, r.CryptoService, trustpinning.TrustPinConfig{}) + newBuilder = tuf.NewRepoBuilder(r.gun, r.CryptoService(), trustpinning.TrustPinConfig{}) if err := newBuilder.Load(data.CanonicalRootRole, rootJSON, minVersion, false); err != nil { // Ok, the old root is expired - we want to download a new one. But we want to use the @@ -1170,7 +1175,7 @@ func (r *NotaryRepository) pubKeyListForRotation(role data.RoleName, serverManag // If no new keys are passed in, we generate one if len(newKeys) == 0 { pubKeyList = make(data.KeyList, 0, 1) - pubKey, err = r.CryptoService.Create(role, r.gun, data.ECDSAKey) + pubKey, err = r.CryptoService().Create(role, r.gun, data.ECDSAKey) pubKeyList = append(pubKeyList, pubKey) } if err != nil { @@ -1181,7 +1186,7 @@ func (r *NotaryRepository) pubKeyListForRotation(role data.RoleName, serverManag if len(newKeys) > 0 { pubKeyList = make(data.KeyList, 0, len(newKeys)) for _, keyID := range newKeys { - pubKey = r.CryptoService.GetKey(keyID) + pubKey = r.CryptoService().GetKey(keyID) if pubKey == nil { return nil, fmt.Errorf("unable to find key: %s", keyID) } @@ -1204,7 +1209,7 @@ func (r *NotaryRepository) pubKeysToCerts(role data.RoleName, pubKeyList data.Ke } for i, pubKey := range pubKeyList { - privKey, loadedRole, err := r.CryptoService.GetPrivateKey(pubKey.ID()) + privKey, loadedRole, err := r.CryptoService().GetPrivateKey(pubKey.ID()) if err != nil { return nil, err } @@ -1279,3 +1284,9 @@ func DeleteTrustData(baseDir string, gun data.GUN, URL string, rt http.RoundTrip } return nil } + +// SetLegacyVersions allows the number of legacy versions of the root +// to be inspected for old signing keys to be configured. +func (r NotaryRepository) SetLegacyVersions(n int) { + r.LegacyVersions = n +} diff --git a/client/client_test.go b/client/client_test.go index 19de26f58..2853dc137 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -195,7 +195,7 @@ func createRepoAndKey(t *testing.T, rootType, tempBaseDir, gun, url string) (*No tempBaseDir, data.GUN(gun), url, http.DefaultTransport, rec.retriever, trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) - rootPubKey, err := testutils.CreateOrAddKey(repo.CryptoService, data.CanonicalRootRole, repo.gun, rootType) + rootPubKey, err := testutils.CreateOrAddKey(repo.CryptoService(), data.CanonicalRootRole, repo.gun, rootType) require.NoError(t, err, "error generating root key: %s", err) rec.requireCreated(t, []string{data.CanonicalRootRole.String()}, @@ -365,7 +365,7 @@ func TestInitRepositoryWithCerts(t *testing.T) { //create extra key pairs if necessary for i := 0; i < tc.extraKeys; i++ { - key, err := repo.CryptoService.Create(data.CanonicalRootRole, repo.gun, data.ECDSAKey) + key, err := repo.CryptoService().Create(data.CanonicalRootRole, repo.gun, data.ECDSAKey) require.NoError(t, err, "error creating %v-th key: %v", i, err) pubKeyIDs = append(pubKeyIDs, key.ID()) } @@ -373,7 +373,7 @@ func TestInitRepositoryWithCerts(t *testing.T) { // assign pubKeys if necessary var pubKeys []data.PublicKey for i := 0; i < tc.numberOfCerts; i++ { - pubKeys = append(pubKeys, repo.CryptoService.GetKey(pubKeyIDs[i])) + pubKeys = append(pubKeys, repo.CryptoService().GetKey(pubKeyIDs[i])) } if !strings.Contains(tc.name, "unmatched key pairs") { @@ -413,8 +413,8 @@ func TestMatchKeyIDsWithPublicKeys(t *testing.T) { // set up repo and keys repo, _, keyID := createRepoAndKey(t, data.ECDSAKey, tempBaseDir, "docker.com/notary", ts.URL) - publicKey := repo.CryptoService.GetKey(keyID) - privateKey, _, err := repo.CryptoService.GetPrivateKey(keyID) + publicKey := repo.CryptoService().GetKey(keyID) + privateKey, _, err := repo.CryptoService().GetPrivateKey(keyID) require.NoError(t, err, "private key should exist in keystore") // 1. create a repository and obtain its root key id, use the key id to get the corresponding @@ -443,7 +443,7 @@ func TestMatchKeyIDsWithPublicKeys(t *testing.T) { require.NoError(t, err, "public key should be matched with its corresponding private key") // 4. match a non matching key pair, expect error - pub2, err := repo.CryptoService.Create(data.CanonicalRootRole, "docker.com/notary", data.ECDSAKey) + pub2, err := repo.CryptoService().Create(data.CanonicalRootRole, "docker.com/notary", data.ECDSAKey) require.NoError(t, err, "error generating root key: %s", err) err = matchKeyIdsWithPubKeys(repo, []string{pub2.ID()}, []data.PublicKey{publicKey}) require.Error(t, err, "validating a non-matching key pair should fail but didn't") @@ -701,7 +701,7 @@ func testInitRepoAttemptsExceeded(t *testing.T, rootType string) { repo, err := NewFileCachedNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, retriever, trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) - rootPubKey, err := testutils.CreateOrAddKey(repo.CryptoService, data.CanonicalRootRole, repo.gun, rootType) + rootPubKey, err := testutils.CreateOrAddKey(repo.CryptoService(), data.CanonicalRootRole, repo.gun, rootType) require.NoError(t, err, "error generating root key: %s", err) retriever = passphrase.ConstantRetriever("incorrect password") @@ -740,7 +740,7 @@ func testInitRepoPasswordInvalid(t *testing.T, rootType string) { repo, err := NewFileCachedNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, retriever, trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) - rootPubKey, err := testutils.CreateOrAddKey(repo.CryptoService, data.CanonicalRootRole, repo.gun, rootType) + rootPubKey, err := testutils.CreateOrAddKey(repo.CryptoService(), data.CanonicalRootRole, repo.gun, rootType) require.NoError(t, err, "error generating root key: %s", err) // repo.CryptoService’s FileKeyStore caches the unlocked private key, so to test @@ -1177,7 +1177,7 @@ func fakeServerData(t *testing.T, repo *NotaryRepository, mux *http.ServeMux, timestampKey, ok := keys[data.CanonicalTimestampRole.String()] require.True(t, ok) // Add timestamp key via the server's cryptoservice so it can sign - repo.CryptoService.AddKey(data.CanonicalTimestampRole, repo.gun, timestampKey) + repo.CryptoService().AddKey(data.CanonicalTimestampRole, repo.gun, timestampKey) savedTUFRepo := repo.tufRepo // in case this is overwritten @@ -1390,7 +1390,7 @@ func testListTargetWithDelegates(t *testing.T, rootType string) { currentTarget := addTarget(t, repo, "current", "../fixtures/intermediate-ca.crt") // setup delegated targets/level1 role - k, err := testutils.CreateOrAddKey(repo.CryptoService, "targets/level1", repo.gun, rootType) + k, err := testutils.CreateOrAddKey(repo.CryptoService(), "targets/level1", repo.gun, rootType) require.NoError(t, err) err = repo.tufRepo.UpdateDelegationKeys("targets/level1", []data.PublicKey{k}, []string{}, 1) require.NoError(t, err) @@ -1400,7 +1400,7 @@ func testListTargetWithDelegates(t *testing.T, rootType string) { otherTarget := addTarget(t, repo, "other", "../fixtures/root-ca.crt", "targets/level1") // setup delegated targets/level2 role - k, err = testutils.CreateOrAddKey(repo.CryptoService, "targets/level2", repo.gun, rootType) + k, err = testutils.CreateOrAddKey(repo.CryptoService(), "targets/level2", repo.gun, rootType) require.NoError(t, err) err = repo.tufRepo.UpdateDelegationKeys("targets/level2", []data.PublicKey{k}, []string{}, 1) require.NoError(t, err) @@ -1432,7 +1432,7 @@ func testListTargetWithDelegates(t *testing.T, rootType string) { // setup delegated targets/level1/level2 role separately, which can only modify paths prefixed with "level2" // This is done separately due to target shadowing - k, err = testutils.CreateOrAddKey(repo.CryptoService, "targets/level1/level2", repo.gun, rootType) + k, err = testutils.CreateOrAddKey(repo.CryptoService(), "targets/level1/level2", repo.gun, rootType) require.NoError(t, err) err = repo.tufRepo.UpdateDelegationKeys("targets/level1/level2", []data.PublicKey{k}, []string{}, 1) require.NoError(t, err) @@ -1544,7 +1544,7 @@ func TestListTargetRestrictsDelegationPaths(t *testing.T) { require.NoError(t, err, "error creating repository: %s", err) // setup delegated targets/level1 role - k, err := repo.CryptoService.Create("targets/level1", repo.gun, data.ECDSAKey) + k, err := repo.CryptoService().Create("targets/level1", repo.gun, data.ECDSAKey) require.NoError(t, err) err = repo.tufRepo.UpdateDelegationKeys("targets/level1", []data.PublicKey{k}, []string{}, 1) require.NoError(t, err) @@ -1987,11 +1987,11 @@ func testPublishNoOneHasSnapshotKey(t *testing.T, rootType string) { snapshotRole, ok := repo.tufRepo.Root.Signed.Roles[data.CanonicalSnapshotRole] require.True(t, ok) for _, keyID := range snapshotRole.KeyIDs { - repo.CryptoService.RemoveKey(keyID) + repo.CryptoService().RemoveKey(keyID) } // ensure that the cryptoservice no longer has any snapshot keys - require.Len(t, repo.CryptoService.ListKeys(data.CanonicalSnapshotRole), 0) + require.Len(t, repo.CryptoService().ListKeys(data.CanonicalSnapshotRole), 0) // Publish something addTarget(t, repo, "v1", "../fixtures/intermediate-ca.crt") @@ -2139,7 +2139,7 @@ func TestPublishSnapshotLocalKeysCreatedFirst(t *testing.T) { rootPubKey, err := cs.Create(data.CanonicalRootRole, gun, data.ECDSAKey) require.NoError(t, err, "error generating root key: %s", err) - repo.CryptoService = cannotCreateKeys{CryptoService: cs} + repo.cryptoService = cannotCreateKeys{CryptoService: cs} err = repo.Initialize([]string{rootPubKey.ID()}, data.CanonicalSnapshotRole) require.Error(t, err) @@ -2148,12 +2148,12 @@ func TestPublishSnapshotLocalKeysCreatedFirst(t *testing.T) { } func createKey(t *testing.T, repo *NotaryRepository, role data.RoleName, x509 bool) data.PublicKey { - key, err := repo.CryptoService.Create(role, repo.gun, data.ECDSAKey) + key, err := repo.CryptoService().Create(role, repo.gun, data.ECDSAKey) require.NoError(t, err, "error creating key") if x509 { start := time.Now().AddDate(0, 0, -1) - privKey, _, err := repo.CryptoService.GetPrivateKey(key.ID()) + privKey, _, err := repo.CryptoService().GetPrivateKey(key.ID()) require.NoError(t, err) cert, err := cryptoservice.GenerateCertificate( privKey, data.GUN(role), start, start.AddDate(1, 0, 0), @@ -2370,9 +2370,9 @@ func TestPublishTargetsDelegationNoTargetsKeyNeeded(t *testing.T) { rec.clear() // remove targets key - it is not even needed - targetsKeys := repo.CryptoService.ListKeys(data.CanonicalTargetsRole) + targetsKeys := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) require.Len(t, targetsKeys, 1) - require.NoError(t, repo.CryptoService.RemoveKey(targetsKeys[0])) + require.NoError(t, repo.CryptoService().RemoveKey(targetsKeys[0])) requirePublishToRolesSucceeds(t, repo, []data.RoleName{"targets/a/b"}, []data.RoleName{"targets/a/b"}) @@ -2405,11 +2405,11 @@ func TestPublishTargetsDelegationSuccessNeedsToDownloadRoles(t *testing.T) { defer os.RemoveAll(delgRepo.baseDir) // create a key on the owner repo - aKey, err := ownerRepo.CryptoService.Create("targets/a", gun, data.ECDSAKey) + aKey, err := ownerRepo.CryptoService().Create("targets/a", gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") // create a key on the delegated repo - bKey, err := delgRepo.CryptoService.Create("targets/a/b", gun, data.ECDSAKey) + bKey, err := delgRepo.CryptoService().Create("targets/a/b", gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") // clear metadata and unencrypted private key cache @@ -2470,11 +2470,11 @@ func TestPublishTargetsDelegationFromTwoRepos(t *testing.T) { defer os.RemoveAll(repo2.baseDir) // create keys for each repo - key1, err := repo1.CryptoService.Create("targets/a", repo1.gun, data.ECDSAKey) + key1, err := repo1.CryptoService().Create("targets/a", repo1.gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") // create a key on the delegated repo - key2, err := repo2.CryptoService.Create("targets/a", repo2.gun, data.ECDSAKey) + key2, err := repo2.CryptoService().Create("targets/a", repo2.gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") // delegation includes both keys @@ -2544,7 +2544,7 @@ func TestPublishRemoveDelegationKeyFromDelegationRole(t *testing.T) { defer os.RemoveAll(delgRepo.baseDir) // create a key on the delegated repo - aKey, err := delgRepo.CryptoService.Create("targets/a", delgRepo.gun, data.ECDSAKey) + aKey, err := delgRepo.CryptoService().Create("targets/a", delgRepo.gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") // owner creates delegation, adds the delegated key to it, and publishes it @@ -2559,7 +2559,7 @@ func TestPublishRemoveDelegationKeyFromDelegationRole(t *testing.T) { // owner revokes delegation // note there is no removekeyfromdelegation yet, so here's a hack to do so - newKey, err := ownerRepo.CryptoService.Create("targets/a", ownerRepo.gun, data.ECDSAKey) + newKey, err := ownerRepo.CryptoService().Create("targets/a", ownerRepo.gun, data.ECDSAKey) require.NoError(t, err) tdJSON, err := json.Marshal(&changelist.TUFDelegation{ NewThreshold: 1, @@ -2608,7 +2608,7 @@ func TestPublishRemoveDelegation(t *testing.T) { defer os.RemoveAll(delgRepo.baseDir) // create a key on the delegated repo - aKey, err := delgRepo.CryptoService.Create("targets/a", delgRepo.gun, data.ECDSAKey) + aKey, err := delgRepo.CryptoService().Create("targets/a", delgRepo.gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") // owner creates delegation, adds the delegated key to it, and publishes it @@ -2643,7 +2643,7 @@ func TestPublishSucceedsDespiteDelegationCorrupt(t *testing.T) { repo, _ := initializeRepo(t, data.ECDSAKey, "docker.com/notary", ts.URL, false) defer os.RemoveAll(repo.baseDir) - delgKey, err := repo.CryptoService.Create("targets/a", repo.gun, data.ECDSAKey) + delgKey, err := repo.CryptoService().Create("targets/a", repo.gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") require.NoError(t, @@ -2666,7 +2666,7 @@ func TestRotateKeyInvalidRole(t *testing.T) { defer os.RemoveAll(repo.baseDir) // create a delegation - pubKey, err := repo.CryptoService.Create("targets/releases", data.GUN("docker.com/notary"), data.ECDSAKey) + pubKey, err := repo.CryptoService().Create("targets/releases", data.GUN("docker.com/notary"), data.ECDSAKey) require.NoError(t, err) require.NoError(t, repo.AddDelegation("targets/releases", []data.PublicKey{pubKey}, []string{""})) require.NoError(t, repo.Publish()) @@ -2817,7 +2817,7 @@ func requireRotationSuccessful(t *testing.T, repo1 *NotaryRepository, keysToRota canonicalID, err := utils.CanonicalKeyID(oldPubKey) require.NoError(t, err) - _, _, err = repo.CryptoService.GetPrivateKey(canonicalID) + _, _, err = repo.CryptoService().GetPrivateKey(canonicalID) switch roleName { case data.CanonicalRootRole: require.NoError(t, err) @@ -2834,7 +2834,7 @@ func requireRotationSuccessful(t *testing.T, repo1 *NotaryRepository, keysToRota canonicalID, err := utils.CanonicalKeyID(pubKey) require.NoError(t, err) - key, _, err := repo.CryptoService.GetPrivateKey(canonicalID) + key, _, err := repo.CryptoService().GetPrivateKey(canonicalID) if isRemoteKey { require.Error(t, err) require.Nil(t, key) @@ -3130,9 +3130,9 @@ func TestRotateRootKeyProvided(t *testing.T) { require.NoError(t, err) // Key loaded from file (just generating it here) - rootPublicKey, err := authorRepo.CryptoService.Create(data.CanonicalRootRole, "", data.ECDSAKey) + rootPublicKey, err := authorRepo.CryptoService().Create(data.CanonicalRootRole, "", data.ECDSAKey) require.NoError(t, err) - rootPrivateKey, _, err := authorRepo.CryptoService.GetPrivateKey(rootPublicKey.ID()) + rootPrivateKey, _, err := authorRepo.CryptoService().GetPrivateKey(rootPublicKey.ID()) require.NoError(t, err) // Fail to rotate to bad key @@ -3312,9 +3312,9 @@ func TestAddDelegationChangefileValid(t *testing.T) { repo, _ := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - targetKeyIds := repo.CryptoService.ListKeys(data.CanonicalTargetsRole) + targetKeyIds := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) require.NotEmpty(t, targetKeyIds) - targetPubKey := repo.CryptoService.GetKey(targetKeyIds[0]) + targetPubKey := repo.CryptoService().GetKey(targetKeyIds[0]) require.NotNil(t, targetPubKey) err := repo.AddDelegation(data.CanonicalRootRole, []data.PublicKey{targetPubKey}, []string{""}) @@ -3350,9 +3350,9 @@ func TestAddDelegationChangefileApplicable(t *testing.T) { repo, _ := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - targetKeyIds := repo.CryptoService.ListKeys(data.CanonicalTargetsRole) + targetKeyIds := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) require.NotEmpty(t, targetKeyIds) - targetPubKey := repo.CryptoService.GetKey(targetKeyIds[0]) + targetPubKey := repo.CryptoService().GetKey(targetKeyIds[0]) require.NotNil(t, targetPubKey) // this hierarchy has to be right to be applied @@ -3382,9 +3382,9 @@ func TestAddDelegationChangefileApplicable(t *testing.T) { // to be propagated. func TestAddDelegationErrorWritingChanges(t *testing.T) { testErrorWritingChangefiles(t, func(repo *NotaryRepository) error { - targetKeyIds := repo.CryptoService.ListKeys(data.CanonicalTargetsRole) + targetKeyIds := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) require.NotEmpty(t, targetKeyIds) - targetPubKey := repo.CryptoService.GetKey(targetKeyIds[0]) + targetPubKey := repo.CryptoService().GetKey(targetKeyIds[0]) require.NotNil(t, targetPubKey) return repo.AddDelegation("targets/a", []data.PublicKey{targetPubKey}, []string{""}) @@ -3401,7 +3401,7 @@ func TestRemoveDelegationChangefileValid(t *testing.T) { repo, rootKeyID := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - rootPubKey := repo.CryptoService.GetKey(rootKeyID) + rootPubKey := repo.CryptoService().GetKey(rootKeyID) require.NotNil(t, rootPubKey) err := repo.RemoveDelegationKeys(data.CanonicalRootRole, []string{rootKeyID}) @@ -3432,7 +3432,7 @@ func TestRemoveDelegationChangefileApplicable(t *testing.T) { repo, rootKeyID := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - rootPubKey := repo.CryptoService.GetKey(rootKeyID) + rootPubKey := repo.CryptoService().GetKey(rootKeyID) require.NotNil(t, rootPubKey) // add a delegation first so it can be removed @@ -3468,7 +3468,7 @@ func TestClearAllPathsDelegationChangefileApplicable(t *testing.T) { repo, rootKeyID := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - rootPubKey := repo.CryptoService.GetKey(rootKeyID) + rootPubKey := repo.CryptoService().GetKey(rootKeyID) require.NotNil(t, rootPubKey) // add a delegation first so it can be removed @@ -3498,10 +3498,10 @@ func TestFullAddDelegationChangefileApplicable(t *testing.T) { repo, rootKeyID := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - rootPubKey := repo.CryptoService.GetKey(rootKeyID) + rootPubKey := repo.CryptoService().GetKey(rootKeyID) require.NotNil(t, rootPubKey) - key2, err := repo.CryptoService.Create("user", repo.gun, data.ECDSAKey) + key2, err := repo.CryptoService().Create("user", repo.gun, data.ECDSAKey) require.NoError(t, err) var delegationName data.RoleName = "targets/a" @@ -3540,10 +3540,10 @@ func TestFullRemoveDelegationChangefileApplicable(t *testing.T) { repo, rootKeyID := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - rootPubKey := repo.CryptoService.GetKey(rootKeyID) + rootPubKey := repo.CryptoService().GetKey(rootKeyID) require.NotNil(t, rootPubKey) - key2, err := repo.CryptoService.Create("user", repo.gun, data.ECDSAKey) + key2, err := repo.CryptoService().Create("user", repo.gun, data.ECDSAKey) require.NoError(t, err) key2CanonicalID, err := utils.CanonicalKeyID(key2) require.NoError(t, err) @@ -3966,7 +3966,7 @@ func TestGetAllTargetInfo(t *testing.T) { targetsCurrentTarget := addTarget(t, repo, "current", "../fixtures/intermediate-ca.crt") // setup delegated targets/level1 role with targets current and other - k, err := repo.CryptoService.Create("targets/level1", repo.gun, rootType) + k, err := repo.CryptoService().Create("targets/level1", repo.gun, rootType) require.NoError(t, err) key1 := k err = repo.tufRepo.UpdateDelegationKeys("targets/level1", []data.PublicKey{k}, []string{}, 1) @@ -3977,7 +3977,7 @@ func TestGetAllTargetInfo(t *testing.T) { level1OtherTarget := addTarget(t, repo, "other", "../fixtures/root-ca.crt", "targets/level1") // setup delegated targets/level2 role with targets current and level2 - k, err = repo.CryptoService.Create("targets/level2", repo.gun, rootType) + k, err = repo.CryptoService().Create("targets/level2", repo.gun, rootType) require.NoError(t, err) key2 := k err = repo.tufRepo.UpdateDelegationKeys("targets/level2", []data.PublicKey{k}, []string{}, 1) @@ -4008,7 +4008,7 @@ func TestGetAllTargetInfo(t *testing.T) { // setup delegated targets/level1/level2 role separately, which can only modify paths prefixed with "level2" // add level2 to targets/level1/level2 - k, err = repo.CryptoService.Create("targets/level1/level2", repo.gun, rootType) + k, err = repo.CryptoService().Create("targets/level1/level2", repo.gun, rootType) require.NoError(t, err) key3 := k err = repo.tufRepo.UpdateDelegationKeys("targets/level1/level2", []data.PublicKey{k}, []string{}, 1) @@ -4038,7 +4038,7 @@ func TestGetAllTargetInfo(t *testing.T) { level2Level2 = expectation{role: "targets/level2", target: "level2"} level1Level2Level2 = expectation{role: "targets/level1/level2", target: "level2"} ) - targetsKey := repo.CryptoService.ListKeys(data.CanonicalTargetsRole)[0] + targetsKey := repo.CryptoService().ListKeys(data.CanonicalTargetsRole)[0] allExpected := map[expectation]TargetSignedStruct{ targetCurrent: { Target: *targetsCurrentTarget, diff --git a/client/interface.go b/client/interface.go new file mode 100644 index 000000000..f0058b40a --- /dev/null +++ b/client/interface.go @@ -0,0 +1,46 @@ +package client + +import ( + "github.com/docker/notary/client/changelist" + "github.com/docker/notary/tuf/data" + "github.com/docker/notary/tuf/signed" +) + +// Repository represents the set of options that must be supported over a TUF repo. +type Repository interface { + // General management operations + Initialize(rootKeyIDs []string, serverManagedRoles ...data.RoleName) error + Publish() error + + // Target Operations + AddTarget(target *Target, roles ...data.RoleName) error + RemoveTarget(targetName string, roles ...data.RoleName) error + ListTargets(roles ...data.RoleName) ([]*TargetWithRole, error) + GetTargetByName(name string, roles ...data.RoleName) (*TargetWithRole, error) + GetAllTargetMetadataByName(name string) ([]TargetSignedStruct, error) + + // Changelist operations + GetChangelist() (changelist.Changelist, error) + + // Role operations + ListRoles() ([]RoleWithSignatures, error) + GetDelegationRoles() ([]data.Role, error) + AddDelegation(name data.RoleName, delegationKeys []data.PublicKey, paths []string) error + AddDelegationRoleAndKeys(name data.RoleName, delegationKeys []data.PublicKey) error + AddDelegationPaths(name data.RoleName, paths []string) error + RemoveDelegationKeysAndPaths(name data.RoleName, keyIDs, paths []string) error + RemoveDelegationRole(name data.RoleName) error + RemoveDelegationPaths(name data.RoleName, paths []string) error + RemoveDelegationKeys(name data.RoleName, keyIDs []string) error + ClearDelegationPaths(name data.RoleName) error + + // Witness and other re-signing operations + Witness(roles ...data.RoleName) ([]data.RoleName, error) + + // Key Operations + RotateKey(role data.RoleName, serverManagesKey bool, keyList []string) error + + CryptoService() signed.CryptoService + SetLegacyVersions(int) + GetGUN() data.GUN +} diff --git a/cmd/notary/keys.go b/cmd/notary/keys.go index d111fc72b..24f8b80f4 100644 --- a/cmd/notary/keys.go +++ b/cmd/notary/keys.go @@ -324,7 +324,7 @@ func (k *keyCommander) keysRotate(cmd *cobra.Command, args []string) error { if err != nil { return err } - err = nRepo.CryptoService.AddKey(rotateKeyRole, gun, privKey) + err = nRepo.CryptoService().AddKey(rotateKeyRole, gun, privKey) if err != nil { return fmt.Errorf("Error importing key: %v", err) } diff --git a/cmd/notary/keys_test.go b/cmd/notary/keys_test.go index e9012da3d..91a12a85e 100644 --- a/cmd/notary/keys_test.go +++ b/cmd/notary/keys_test.go @@ -337,13 +337,13 @@ func setUpRepo(t *testing.T, tempBaseDir string, gun data.GUN, ret notary.PassRe tempBaseDir, gun, ts.URL, http.DefaultTransport, ret, trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) - rootPubKey, err := repo.CryptoService.Create(data.CanonicalRootRole, "", data.ECDSAKey) + rootPubKey, err := repo.CryptoService().Create(data.CanonicalRootRole, "", data.ECDSAKey) require.NoError(t, err, "error generating root key: %s", err) err = repo.Initialize([]string{rootPubKey.ID()}) require.NoError(t, err) - return ts, repo.CryptoService.ListAllKeys() + return ts, repo.CryptoService().ListAllKeys() } // The command line uses NotaryRepository's RotateKey - this is just testing @@ -383,7 +383,7 @@ func TestRotateKeyRemoteServerManagesKey(t *testing.T) { require.NoError(t, err, "unable to get changelist: %v", err) require.Len(t, cl.List(), 0, "expected the changes to have been published") - finalKeys := repo.CryptoService.ListAllKeys() + finalKeys := repo.CryptoService().ListAllKeys() // no keys have been created, since a remote key was specified if role == data.CanonicalSnapshotRole.String() { require.Len(t, finalKeys, 2) @@ -438,7 +438,7 @@ func TestRotateKeyBothKeys(t *testing.T) { require.Len(t, cl.List(), 0) // two new keys have been created, and the old keys should still be gone - newKeys := repo.CryptoService.ListAllKeys() + newKeys := repo.CryptoService().ListAllKeys() // there should be 3 keys - snapshot, targets, and root require.Len(t, newKeys, 3) @@ -499,7 +499,7 @@ func TestRotateKeyRootIsInteractive(t *testing.T) { require.NoError(t, err, "error creating repo: %s", err) // There should still just be one root key (and one targets and one snapshot) - allKeys := repo.CryptoService.ListAllKeys() + allKeys := repo.CryptoService().ListAllKeys() require.Len(t, allKeys, 3) } diff --git a/cmd/notary/repo_factory.go b/cmd/notary/repo_factory.go new file mode 100644 index 000000000..6547b06af --- /dev/null +++ b/cmd/notary/repo_factory.go @@ -0,0 +1,45 @@ +package main + +import ( + "github.com/spf13/viper" + + "net/http" + + "github.com/docker/notary" + "github.com/docker/notary/client" + "github.com/docker/notary/tuf/data" +) + +const remoteConfigField = "api" + +// RepoFactory takes a GUN and returns an initialized client.Repository, or an error. +type RepoFactory func(gun data.GUN) (client.Repository, error) + +// ConfigureRepo takes in the configuration parameters and returns a repoFactory that can +// initialize new client.Repository objects with the correct upstreams and password +// retrieval mechanisms. +func ConfigureRepo(v *viper.Viper, retriever notary.PassRetriever, onlineOperation bool) RepoFactory { + localRepo := func(gun data.GUN) (client.Repository, error) { + var rt http.RoundTripper + trustPin, err := getTrustPinning(v) + if err != nil { + return nil, err + } + if onlineOperation { + rt, err = getTransport(v, gun, admin) + if err != nil { + return nil, err + } + } + return client.NewFileCachedNotaryRepository( + v.GetString("trust_dir"), + gun, + getRemoteTrustServer(v), + rt, + retriever, + trustPin, + ) + } + + return localRepo +} diff --git a/cmd/notary/tuf.go b/cmd/notary/tuf.go index 6f96d176a..b58cf6df5 100644 --- a/cmd/notary/tuf.go +++ b/cmd/notary/tuf.go @@ -200,17 +200,12 @@ func (t *tufCommander) tufWitness(cmd *cobra.Command, args []string) error { if err != nil { return err } - trustPin, err := getTrustPinning(config) - if err != nil { - return err - } + gun := data.GUN(args[0]) roles := data.NewRoleList(args[1:]) - // no online operations are performed by add so the transport argument - // should be nil - nRepo, err := notaryclient.NewFileCachedNotaryRepository( - config.GetString("trust_dir"), gun, getRemoteTrustServer(config), nil, t.retriever, trustPin) + fact := ConfigureRepo(config, t.retriever, false) + nRepo, err := fact(gun) if err != nil { return err } @@ -296,15 +291,10 @@ func (t *tufCommander) tufAddByHash(cmd *cobra.Command, args []string) error { return err } - trustPin, err := getTrustPinning(config) - if err != nil { - return err - } - // no online operations are performed by add so the transport argument // should be nil - nRepo, err := notaryclient.NewFileCachedNotaryRepository( - config.GetString("trust_dir"), gun, getRemoteTrustServer(config), nil, t.retriever, trustPin) + fact := ConfigureRepo(config, t.retriever, false) + nRepo, err := fact(gun) if err != nil { return err } @@ -357,15 +347,10 @@ func (t *tufCommander) tufAdd(cmd *cobra.Command, args []string) error { } } - trustPin, err := getTrustPinning(config) - if err != nil { - return err - } - // no online operations are performed by add so the transport argument // should be nil - nRepo, err := notaryclient.NewFileCachedNotaryRepository( - config.GetString("trust_dir"), gun, getRemoteTrustServer(config), nil, t.retriever, trustPin) + fact := ConfigureRepo(config, t.retriever, false) + nRepo, err := fact(gun) if err != nil { return err } @@ -424,7 +409,7 @@ func (t *tufCommander) tufDeleteGUN(cmd *cobra.Command, args []string) error { // importRootKey imports the root key from path then adds the key to repo // returns key ids -func importRootKey(cmd *cobra.Command, rootKey string, nRepo *notaryclient.NotaryRepository, retriever notary.PassRetriever) ([]string, error) { +func importRootKey(cmd *cobra.Command, rootKey string, nRepo notaryclient.Repository, retriever notary.PassRetriever) ([]string, error) { var rootKeyList []string if rootKey != "" { @@ -433,13 +418,13 @@ func importRootKey(cmd *cobra.Command, rootKey string, nRepo *notaryclient.Notar return nil, err } // add root key to repo - err = nRepo.CryptoService.AddKey(data.CanonicalRootRole, "", privKey) + err = nRepo.CryptoService().AddKey(data.CanonicalRootRole, "", privKey) if err != nil { return nil, fmt.Errorf("Error importing key: %v", err) } rootKeyList = []string{privKey.ID()} } else { - rootKeyList = nRepo.CryptoService.ListKeys(data.CanonicalRootRole) + rootKeyList = nRepo.CryptoService().ListKeys(data.CanonicalRootRole) } if len(rootKeyList) > 0 { @@ -495,18 +480,8 @@ func (t *tufCommander) tufInit(cmd *cobra.Command, args []string) error { } gun := data.GUN(args[0]) - rt, err := getTransport(config, gun, readWrite) - if err != nil { - return err - } - - trustPin, err := getTrustPinning(config) - if err != nil { - return err - } - - nRepo, err := notaryclient.NewFileCachedNotaryRepository( - config.GetString("trust_dir"), gun, getRemoteTrustServer(config), rt, t.retriever, trustPin) + fact := ConfigureRepo(config, t.retriever, true) + nRepo, err := fact(gun) if err != nil { return err } @@ -571,18 +546,8 @@ func (t *tufCommander) tufList(cmd *cobra.Command, args []string) error { } gun := data.GUN(args[0]) - rt, err := getTransport(config, gun, readOnly) - if err != nil { - return err - } - - trustPin, err := getTrustPinning(config) - if err != nil { - return err - } - - nRepo, err := notaryclient.NewFileCachedNotaryRepository( - config.GetString("trust_dir"), gun, getRemoteTrustServer(config), rt, t.retriever, trustPin) + fact := ConfigureRepo(config, t.retriever, true) + nRepo, err := fact(gun) if err != nil { return err } @@ -610,18 +575,8 @@ func (t *tufCommander) tufLookup(cmd *cobra.Command, args []string) error { gun := data.GUN(args[0]) targetName := args[1] - rt, err := getTransport(config, gun, readOnly) - if err != nil { - return err - } - - trustPin, err := getTrustPinning(config) - if err != nil { - return err - } - - nRepo, err := notaryclient.NewFileCachedNotaryRepository( - config.GetString("trust_dir"), gun, getRemoteTrustServer(config), rt, t.retriever, trustPin) + fact := ConfigureRepo(config, t.retriever, true) + nRepo, err := fact(gun) if err != nil { return err } @@ -647,13 +602,8 @@ func (t *tufCommander) tufStatus(cmd *cobra.Command, args []string) error { } gun := data.GUN(args[0]) - trustPin, err := getTrustPinning(config) - if err != nil { - return err - } - - nRepo, err := notaryclient.NewFileCachedNotaryRepository( - config.GetString("trust_dir"), gun, getRemoteTrustServer(config), nil, t.retriever, trustPin) + fact := ConfigureRepo(config, t.retriever, false) + nRepo, err := fact(gun) if err != nil { return err } @@ -704,13 +654,8 @@ func (t *tufCommander) tufReset(cmd *cobra.Command, args []string) error { } gun := data.GUN(args[0]) - trustPin, err := getTrustPinning(config) - if err != nil { - return err - } - - nRepo, err := notaryclient.NewFileCachedNotaryRepository( - config.GetString("trust_dir"), gun, getRemoteTrustServer(config), nil, t.retriever, trustPin) + fact := ConfigureRepo(config, t.retriever, false) + nRepo, err := fact(gun) if err != nil { return err } @@ -746,18 +691,8 @@ func (t *tufCommander) tufPublish(cmd *cobra.Command, args []string) error { cmd.Println("Pushing changes to", gun) - rt, err := getTransport(config, gun, readWrite) - if err != nil { - return err - } - - trustPin, err := getTrustPinning(config) - if err != nil { - return err - } - - nRepo, err := notaryclient.NewFileCachedNotaryRepository( - config.GetString("trust_dir"), gun, getRemoteTrustServer(config), rt, t.retriever, trustPin) + fact := ConfigureRepo(config, t.retriever, true) + nRepo, err := fact(gun) if err != nil { return err } @@ -777,21 +712,14 @@ func (t *tufCommander) tufRemove(cmd *cobra.Command, args []string) error { gun := data.GUN(args[0]) targetName := args[1] - trustPin, err := getTrustPinning(config) - if err != nil { - return err - } - - // no online operation are performed by remove so the transport argument - // should be nil. - repo, err := notaryclient.NewFileCachedNotaryRepository( - config.GetString("trust_dir"), gun, getRemoteTrustServer(config), nil, t.retriever, trustPin) + fact := ConfigureRepo(config, t.retriever, false) + nRepo, err := fact(gun) if err != nil { return err } // If roles is empty, we default to removing from targets - if err = repo.RemoveTarget(targetName, data.NewRoleList(t.roles)...); err != nil { + if err = nRepo.RemoveTarget(targetName, data.NewRoleList(t.roles)...); err != nil { return err } @@ -819,18 +747,8 @@ func (t *tufCommander) tufVerify(cmd *cobra.Command, args []string) error { gun := data.GUN(args[0]) targetName := args[1] - rt, err := getTransport(config, gun, readOnly) - if err != nil { - return err - } - - trustPin, err := getTrustPinning(config) - if err != nil { - return err - } - - nRepo, err := notaryclient.NewFileCachedNotaryRepository( - config.GetString("trust_dir"), gun, getRemoteTrustServer(config), rt, t.retriever, trustPin) + fact := ConfigureRepo(config, t.retriever, true) + nRepo, err := fact(gun) if err != nil { return err } @@ -1126,7 +1044,7 @@ func maybeAutoPublish(cmd *cobra.Command, doPublish bool, gun data.GUN, config * return publishAndPrintToCLI(cmd, nRepo) } -func publishAndPrintToCLI(cmd *cobra.Command, nRepo *notaryclient.NotaryRepository) error { +func publishAndPrintToCLI(cmd *cobra.Command, nRepo notaryclient.Repository) error { if err := nRepo.Publish(); err != nil { return err } diff --git a/storage/filestore.go b/storage/filestore.go index 1b82740b8..14c89e7f2 100644 --- a/storage/filestore.go +++ b/storage/filestore.go @@ -63,7 +63,7 @@ func (f *FilesystemStore) moveKeyTo0Dot4Location(file string) { fileDir = strings.TrimPrefix(fileDir, notary.RootKeysSubdir) fileDir = strings.TrimPrefix(fileDir, notary.NonRootKeysSubdir) if fileDir != "" { - block.Headers["gun"] = fileDir[1:] + block.Headers["gun"] = filepath.ToSlash(fileDir[1:]) } if strings.Contains(keyID, "_") { role := strings.Split(keyID, "_")[1] diff --git a/utils/configuration_linux_test.go b/utils/configuration_linux_test.go new file mode 100644 index 000000000..d9b4748b7 --- /dev/null +++ b/utils/configuration_linux_test.go @@ -0,0 +1,44 @@ +// +build !windows + +package utils + +import ( + "os" + "os/signal" + "syscall" + "testing" + + "github.com/docker/notary" + "github.com/stretchr/testify/require" +) + +func testSetSignalTrap(t *testing.T) { + var signalsPassedOn map[string]struct{} + + signalHandler := func(s os.Signal) { + signalsPassedOn := make(map[string]struct{}) + signalsPassedOn[s.String()] = struct{}{} + } + c := SetupSignalTrap(signalHandler) + + if len(notary.NotarySupportedSignals) == 0 { // currently, windows only + require.Nil(t, c) + } else { + require.NotNil(t, c) + defer signal.Stop(c) + } + + for _, s := range notary.NotarySupportedSignals { + syscallSignal, ok := s.(syscall.Signal) + require.True(t, ok) + require.NoError(t, syscall.Kill(syscall.Getpid(), syscallSignal)) + require.Len(t, signalsPassedOn, 0) + require.NotNil(t, signalsPassedOn[s.String()]) + } +} + +// TODO: undo this extra indirection, needed for mocking notary.NotarySupportedSignals being empty, when we have +// a windows CI system running +func TestSetSignalTrap(t *testing.T) { + testSetSignalTrap(t) +} diff --git a/utils/configuration_test.go b/utils/configuration_test.go index 2a6401b86..50046e6ea 100644 --- a/utils/configuration_test.go +++ b/utils/configuration_test.go @@ -6,10 +6,8 @@ import ( "fmt" "io/ioutil" "os" - "os/signal" "path/filepath" "reflect" - "syscall" "testing" "github.com/Sirupsen/logrus" @@ -549,41 +547,3 @@ func TestAdjustLogLevel(t *testing.T) { require.Equal(t, expt.endLevel, logrus.GetLevel()) } } - -func testSetSignalTrap(t *testing.T) { - var signalsPassedOn map[string]struct{} - - signalHandler := func(s os.Signal) { - signalsPassedOn := make(map[string]struct{}) - signalsPassedOn[s.String()] = struct{}{} - } - c := SetupSignalTrap(signalHandler) - - if len(notary.NotarySupportedSignals) == 0 { // currently, windows only - require.Nil(t, c) - } else { - require.NotNil(t, c) - defer signal.Stop(c) - } - - for _, s := range notary.NotarySupportedSignals { - syscallSignal, ok := s.(syscall.Signal) - require.True(t, ok) - require.NoError(t, syscall.Kill(syscall.Getpid(), syscallSignal)) - require.Len(t, signalsPassedOn, 0) - require.NotNil(t, signalsPassedOn[s.String()]) - } -} - -// TODO: undo this extra indirection, needed for mocking notary.NotarySupportedSignals being empty, when we have -// a windows CI system running -func TestSetSignalTrap(t *testing.T) { - testSetSignalTrap(t) -} - -func TestSetSignalTrapMockWindows(t *testing.T) { - old := notary.NotarySupportedSignals - notary.NotarySupportedSignals = nil - testSetSignalTrap(t) - notary.NotarySupportedSignals = old -} From 0c55e81cb6a75f97eb44d1d7fe8d9bfa79e48ef9 Mon Sep 17 00:00:00 2001 From: Riyaz Faizullabhoy Date: Thu, 31 Aug 2017 16:57:30 -0700 Subject: [PATCH 2/3] client: Add InitializeWithCertificate to interface, remove extraneous arg Signed-off-by: Riyaz Faizullabhoy --- client/client.go | 4 ++-- client/interface.go | 1 + cmd/notary/tuf.go | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/client/client.go b/client/client.go index d1f668cb2..3e0ab8b75 100644 --- a/client/client.go +++ b/client/client.go @@ -347,13 +347,13 @@ func keyExistsInList(cert data.PublicKey, ids map[string]bool) error { // InitializeWithCertificate initializes the repository with root keys and their corresponding certificates func (r *NotaryRepository) InitializeWithCertificate(rootKeyIDs []string, rootCerts []data.PublicKey, - nRepo *NotaryRepository, serverManagedRoles ...data.RoleName) error { + serverManagedRoles ...data.RoleName) error { // If we explicitly pass in certificate(s) but not key, then look keys up using certificate if len(rootKeyIDs) == 0 && len(rootCerts) != 0 { rootKeyIDs = []string{} availableRootKeyIDs := make(map[string]bool) - for _, k := range nRepo.CryptoService().ListKeys(data.CanonicalRootRole) { + for _, k := range r.CryptoService().ListKeys(data.CanonicalRootRole) { availableRootKeyIDs[k] = true } diff --git a/client/interface.go b/client/interface.go index f0058b40a..22b9c0a56 100644 --- a/client/interface.go +++ b/client/interface.go @@ -10,6 +10,7 @@ import ( type Repository interface { // General management operations Initialize(rootKeyIDs []string, serverManagedRoles ...data.RoleName) error + InitializeWithCertificate(rootKeyIDs []string, rootCerts []data.PublicKey, serverManagedRoles ...data.RoleName) error Publish() error // Target Operations diff --git a/cmd/notary/tuf.go b/cmd/notary/tuf.go index b58cf6df5..f57ab85b8 100644 --- a/cmd/notary/tuf.go +++ b/cmd/notary/tuf.go @@ -501,7 +501,7 @@ func (t *tufCommander) tufInit(cmd *cobra.Command, args []string) error { rootKeyIDs = []string{} } - if err = nRepo.InitializeWithCertificate(rootKeyIDs, rootCerts, nRepo); err != nil { + if err = nRepo.InitializeWithCertificate(rootKeyIDs, rootCerts); err != nil { return err } From 62788b436e4487c1c8492137c965d37789d15f08 Mon Sep 17 00:00:00 2001 From: Riyaz Faizullabhoy Date: Thu, 7 Sep 2017 11:37:50 -0700 Subject: [PATCH 3/3] interface: GetCryptoService Signed-off-by: Riyaz Faizullabhoy --- client/backwards_compatibility_test.go | 8 +- client/client.go | 28 +++---- client/client_test.go | 102 ++++++++++++------------- client/interface.go | 2 +- cmd/notary/keys.go | 2 +- cmd/notary/keys_test.go | 10 +-- cmd/notary/tuf.go | 4 +- 7 files changed, 78 insertions(+), 78 deletions(-) diff --git a/client/backwards_compatibility_test.go b/client/backwards_compatibility_test.go index 141a6037d..3098bda0e 100644 --- a/client/backwards_compatibility_test.go +++ b/client/backwards_compatibility_test.go @@ -225,10 +225,10 @@ func Test0Dot1RepoFormat(t *testing.T) { require.Len(t, targets, 2) // Also check that we can add/remove keys by rotating keys - oldTargetsKeys := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) + oldTargetsKeys := repo.GetCryptoService().ListKeys(data.CanonicalTargetsRole) require.NoError(t, repo.RotateKey(data.CanonicalTargetsRole, false, nil)) require.NoError(t, repo.Publish()) - newTargetsKeys := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) + newTargetsKeys := repo.GetCryptoService().ListKeys(data.CanonicalTargetsRole) require.Len(t, oldTargetsKeys, 1) require.Len(t, newTargetsKeys, 1) @@ -292,10 +292,10 @@ func Test0Dot3RepoFormat(t *testing.T) { require.Equal(t, data.RoleName("targets/releases"), delegations[0].Name) // Also check that we can add/remove keys by rotating keys - oldTargetsKeys := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) + oldTargetsKeys := repo.GetCryptoService().ListKeys(data.CanonicalTargetsRole) require.NoError(t, repo.RotateKey(data.CanonicalTargetsRole, false, nil)) require.NoError(t, repo.Publish()) - newTargetsKeys := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) + newTargetsKeys := repo.GetCryptoService().ListKeys(data.CanonicalTargetsRole) require.Len(t, oldTargetsKeys, 1) require.Len(t, newTargetsKeys, 1) diff --git a/client/client.go b/client/client.go index 3e0ab8b75..ca193364a 100644 --- a/client/client.go +++ b/client/client.go @@ -182,8 +182,8 @@ func rootCertKey(gun data.GUN, privKey data.PrivateKey) (data.PublicKey, error) return x509PublicKey, nil } -// CryptoService is the getter for the repository's CryptoService -func (r *NotaryRepository) CryptoService() signed.CryptoService { +// GetCryptoService is the getter for the repository's CryptoService +func (r *NotaryRepository) GetCryptoService() signed.CryptoService { return r.cryptoService } @@ -239,7 +239,7 @@ func (r *NotaryRepository) initialize(rootKeyIDs []string, rootCerts []data.Publ return err } - r.tufRepo = tuf.NewRepo(r.CryptoService()) + r.tufRepo = tuf.NewRepo(r.GetCryptoService()) if err := r.tufRepo.InitRoot( rootRole, @@ -269,7 +269,7 @@ func (r *NotaryRepository) initialize(rootKeyIDs []string, rootCerts []data.Publ func (r *NotaryRepository) createNewPublicKeyFromKeyIDs(keyIDs []string) ([]data.PublicKey, error) { publicKeys := []data.PublicKey{} - privKeys, err := getAllPrivKeys(keyIDs, r.CryptoService()) + privKeys, err := getAllPrivKeys(keyIDs, r.GetCryptoService()) if err != nil { return nil, err } @@ -303,7 +303,7 @@ func (r *NotaryRepository) publicKeysOfKeyIDs(keyIDs []string, pubKeys []data.Pu // forms matching key pairs func matchKeyIdsWithPubKeys(r *NotaryRepository, ids []string, pubKeys []data.PublicKey) error { for i := 0; i < len(ids); i++ { - privKey, _, err := r.CryptoService().GetPrivateKey(ids[i]) + privKey, _, err := r.GetCryptoService().GetPrivateKey(ids[i]) if err != nil { return fmt.Errorf("could not get the private key matching id %v: %v", ids[i], err) } @@ -353,7 +353,7 @@ func (r *NotaryRepository) InitializeWithCertificate(rootKeyIDs []string, rootCe if len(rootKeyIDs) == 0 && len(rootCerts) != 0 { rootKeyIDs = []string{} availableRootKeyIDs := make(map[string]bool) - for _, k := range r.CryptoService().ListKeys(data.CanonicalRootRole) { + for _, k := range r.GetCryptoService().ListKeys(data.CanonicalRootRole) { availableRootKeyIDs[k] = true } @@ -381,7 +381,7 @@ func (r *NotaryRepository) initializeRoles(rootKeys []data.PublicKey, localRoles for _, role := range localRoles { // This is currently hardcoding the keys to ECDSA. var key data.PublicKey - key, err = r.CryptoService().Create(role, r.gun, data.ECDSAKey) + key, err = r.GetCryptoService().Create(role, r.gun, data.ECDSAKey) if err != nil { return } @@ -933,7 +933,7 @@ func signTargets(updates map[data.RoleName][]byte, repo *tuf.Repo, initialPublis // snapshots are supported, if the snapshot metadata fails to load, that's ok. // This assumes that bootstrapRepo is only used by Publish() or RotateKey() func (r *NotaryRepository) bootstrapRepo() error { - b := tuf.NewRepoBuilder(r.gun, r.CryptoService(), r.trustPinning) + b := tuf.NewRepoBuilder(r.gun, r.GetCryptoService(), r.trustPinning) logrus.Debugf("Loading trusted collection.") @@ -1068,10 +1068,10 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufClient, e minVersion := 1 // the old root on disk should not be validated against any trust pinning configuration // because if we have an old root, it itself is the thing that pins trust - oldBuilder := tuf.NewRepoBuilder(r.gun, r.CryptoService(), trustpinning.TrustPinConfig{}) + oldBuilder := tuf.NewRepoBuilder(r.gun, r.GetCryptoService(), trustpinning.TrustPinConfig{}) // by default, we want to use the trust pinning configuration on any new root that we download - newBuilder := tuf.NewRepoBuilder(r.gun, r.CryptoService(), r.trustPinning) + newBuilder := tuf.NewRepoBuilder(r.gun, r.GetCryptoService(), r.trustPinning) // Try to read root from cache first. We will trust this root until we detect a problem // during update which will cause us to download a new root and perform a rotation. @@ -1085,7 +1085,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufClient, e // again, the root on disk is the source of trust pinning, so use an empty trust // pinning configuration - newBuilder = tuf.NewRepoBuilder(r.gun, r.CryptoService(), trustpinning.TrustPinConfig{}) + newBuilder = tuf.NewRepoBuilder(r.gun, r.GetCryptoService(), trustpinning.TrustPinConfig{}) if err := newBuilder.Load(data.CanonicalRootRole, rootJSON, minVersion, false); err != nil { // Ok, the old root is expired - we want to download a new one. But we want to use the @@ -1175,7 +1175,7 @@ func (r *NotaryRepository) pubKeyListForRotation(role data.RoleName, serverManag // If no new keys are passed in, we generate one if len(newKeys) == 0 { pubKeyList = make(data.KeyList, 0, 1) - pubKey, err = r.CryptoService().Create(role, r.gun, data.ECDSAKey) + pubKey, err = r.GetCryptoService().Create(role, r.gun, data.ECDSAKey) pubKeyList = append(pubKeyList, pubKey) } if err != nil { @@ -1186,7 +1186,7 @@ func (r *NotaryRepository) pubKeyListForRotation(role data.RoleName, serverManag if len(newKeys) > 0 { pubKeyList = make(data.KeyList, 0, len(newKeys)) for _, keyID := range newKeys { - pubKey = r.CryptoService().GetKey(keyID) + pubKey = r.GetCryptoService().GetKey(keyID) if pubKey == nil { return nil, fmt.Errorf("unable to find key: %s", keyID) } @@ -1209,7 +1209,7 @@ func (r *NotaryRepository) pubKeysToCerts(role data.RoleName, pubKeyList data.Ke } for i, pubKey := range pubKeyList { - privKey, loadedRole, err := r.CryptoService().GetPrivateKey(pubKey.ID()) + privKey, loadedRole, err := r.GetCryptoService().GetPrivateKey(pubKey.ID()) if err != nil { return nil, err } diff --git a/client/client_test.go b/client/client_test.go index 2853dc137..e18c7daf6 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -195,7 +195,7 @@ func createRepoAndKey(t *testing.T, rootType, tempBaseDir, gun, url string) (*No tempBaseDir, data.GUN(gun), url, http.DefaultTransport, rec.retriever, trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) - rootPubKey, err := testutils.CreateOrAddKey(repo.CryptoService(), data.CanonicalRootRole, repo.gun, rootType) + rootPubKey, err := testutils.CreateOrAddKey(repo.GetCryptoService(), data.CanonicalRootRole, repo.gun, rootType) require.NoError(t, err, "error generating root key: %s", err) rec.requireCreated(t, []string{data.CanonicalRootRole.String()}, @@ -365,7 +365,7 @@ func TestInitRepositoryWithCerts(t *testing.T) { //create extra key pairs if necessary for i := 0; i < tc.extraKeys; i++ { - key, err := repo.CryptoService().Create(data.CanonicalRootRole, repo.gun, data.ECDSAKey) + key, err := repo.GetCryptoService().Create(data.CanonicalRootRole, repo.gun, data.ECDSAKey) require.NoError(t, err, "error creating %v-th key: %v", i, err) pubKeyIDs = append(pubKeyIDs, key.ID()) } @@ -373,7 +373,7 @@ func TestInitRepositoryWithCerts(t *testing.T) { // assign pubKeys if necessary var pubKeys []data.PublicKey for i := 0; i < tc.numberOfCerts; i++ { - pubKeys = append(pubKeys, repo.CryptoService().GetKey(pubKeyIDs[i])) + pubKeys = append(pubKeys, repo.GetCryptoService().GetKey(pubKeyIDs[i])) } if !strings.Contains(tc.name, "unmatched key pairs") { @@ -413,8 +413,8 @@ func TestMatchKeyIDsWithPublicKeys(t *testing.T) { // set up repo and keys repo, _, keyID := createRepoAndKey(t, data.ECDSAKey, tempBaseDir, "docker.com/notary", ts.URL) - publicKey := repo.CryptoService().GetKey(keyID) - privateKey, _, err := repo.CryptoService().GetPrivateKey(keyID) + publicKey := repo.GetCryptoService().GetKey(keyID) + privateKey, _, err := repo.GetCryptoService().GetPrivateKey(keyID) require.NoError(t, err, "private key should exist in keystore") // 1. create a repository and obtain its root key id, use the key id to get the corresponding @@ -443,7 +443,7 @@ func TestMatchKeyIDsWithPublicKeys(t *testing.T) { require.NoError(t, err, "public key should be matched with its corresponding private key") // 4. match a non matching key pair, expect error - pub2, err := repo.CryptoService().Create(data.CanonicalRootRole, "docker.com/notary", data.ECDSAKey) + pub2, err := repo.GetCryptoService().Create(data.CanonicalRootRole, "docker.com/notary", data.ECDSAKey) require.NoError(t, err, "error generating root key: %s", err) err = matchKeyIdsWithPubKeys(repo, []string{pub2.ID()}, []data.PublicKey{publicKey}) require.Error(t, err, "validating a non-matching key pair should fail but didn't") @@ -701,11 +701,11 @@ func testInitRepoAttemptsExceeded(t *testing.T, rootType string) { repo, err := NewFileCachedNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, retriever, trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) - rootPubKey, err := testutils.CreateOrAddKey(repo.CryptoService(), data.CanonicalRootRole, repo.gun, rootType) + rootPubKey, err := testutils.CreateOrAddKey(repo.GetCryptoService(), data.CanonicalRootRole, repo.gun, rootType) require.NoError(t, err, "error generating root key: %s", err) retriever = passphrase.ConstantRetriever("incorrect password") - // repo.CryptoService’s FileKeyStore caches the unlocked private key, so to test + // repo.GetCryptoService’s FileKeyStore caches the unlocked private key, so to test // private key unlocking we need a new repo instance. repo, err = NewFileCachedNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, retriever, trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) @@ -740,10 +740,10 @@ func testInitRepoPasswordInvalid(t *testing.T, rootType string) { repo, err := NewFileCachedNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, retriever, trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) - rootPubKey, err := testutils.CreateOrAddKey(repo.CryptoService(), data.CanonicalRootRole, repo.gun, rootType) + rootPubKey, err := testutils.CreateOrAddKey(repo.GetCryptoService(), data.CanonicalRootRole, repo.gun, rootType) require.NoError(t, err, "error generating root key: %s", err) - // repo.CryptoService’s FileKeyStore caches the unlocked private key, so to test + // repo.GetCryptoService’s FileKeyStore caches the unlocked private key, so to test // private key unlocking we need a new repo instance. repo, err = NewFileCachedNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, giveUpPassphraseRetriever, trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) @@ -1177,7 +1177,7 @@ func fakeServerData(t *testing.T, repo *NotaryRepository, mux *http.ServeMux, timestampKey, ok := keys[data.CanonicalTimestampRole.String()] require.True(t, ok) // Add timestamp key via the server's cryptoservice so it can sign - repo.CryptoService().AddKey(data.CanonicalTimestampRole, repo.gun, timestampKey) + repo.GetCryptoService().AddKey(data.CanonicalTimestampRole, repo.gun, timestampKey) savedTUFRepo := repo.tufRepo // in case this is overwritten @@ -1390,7 +1390,7 @@ func testListTargetWithDelegates(t *testing.T, rootType string) { currentTarget := addTarget(t, repo, "current", "../fixtures/intermediate-ca.crt") // setup delegated targets/level1 role - k, err := testutils.CreateOrAddKey(repo.CryptoService(), "targets/level1", repo.gun, rootType) + k, err := testutils.CreateOrAddKey(repo.GetCryptoService(), "targets/level1", repo.gun, rootType) require.NoError(t, err) err = repo.tufRepo.UpdateDelegationKeys("targets/level1", []data.PublicKey{k}, []string{}, 1) require.NoError(t, err) @@ -1400,7 +1400,7 @@ func testListTargetWithDelegates(t *testing.T, rootType string) { otherTarget := addTarget(t, repo, "other", "../fixtures/root-ca.crt", "targets/level1") // setup delegated targets/level2 role - k, err = testutils.CreateOrAddKey(repo.CryptoService(), "targets/level2", repo.gun, rootType) + k, err = testutils.CreateOrAddKey(repo.GetCryptoService(), "targets/level2", repo.gun, rootType) require.NoError(t, err) err = repo.tufRepo.UpdateDelegationKeys("targets/level2", []data.PublicKey{k}, []string{}, 1) require.NoError(t, err) @@ -1432,7 +1432,7 @@ func testListTargetWithDelegates(t *testing.T, rootType string) { // setup delegated targets/level1/level2 role separately, which can only modify paths prefixed with "level2" // This is done separately due to target shadowing - k, err = testutils.CreateOrAddKey(repo.CryptoService(), "targets/level1/level2", repo.gun, rootType) + k, err = testutils.CreateOrAddKey(repo.GetCryptoService(), "targets/level1/level2", repo.gun, rootType) require.NoError(t, err) err = repo.tufRepo.UpdateDelegationKeys("targets/level1/level2", []data.PublicKey{k}, []string{}, 1) require.NoError(t, err) @@ -1544,7 +1544,7 @@ func TestListTargetRestrictsDelegationPaths(t *testing.T) { require.NoError(t, err, "error creating repository: %s", err) // setup delegated targets/level1 role - k, err := repo.CryptoService().Create("targets/level1", repo.gun, data.ECDSAKey) + k, err := repo.GetCryptoService().Create("targets/level1", repo.gun, data.ECDSAKey) require.NoError(t, err) err = repo.tufRepo.UpdateDelegationKeys("targets/level1", []data.PublicKey{k}, []string{}, 1) require.NoError(t, err) @@ -1987,11 +1987,11 @@ func testPublishNoOneHasSnapshotKey(t *testing.T, rootType string) { snapshotRole, ok := repo.tufRepo.Root.Signed.Roles[data.CanonicalSnapshotRole] require.True(t, ok) for _, keyID := range snapshotRole.KeyIDs { - repo.CryptoService().RemoveKey(keyID) + repo.GetCryptoService().RemoveKey(keyID) } // ensure that the cryptoservice no longer has any snapshot keys - require.Len(t, repo.CryptoService().ListKeys(data.CanonicalSnapshotRole), 0) + require.Len(t, repo.GetCryptoService().ListKeys(data.CanonicalSnapshotRole), 0) // Publish something addTarget(t, repo, "v1", "../fixtures/intermediate-ca.crt") @@ -2148,12 +2148,12 @@ func TestPublishSnapshotLocalKeysCreatedFirst(t *testing.T) { } func createKey(t *testing.T, repo *NotaryRepository, role data.RoleName, x509 bool) data.PublicKey { - key, err := repo.CryptoService().Create(role, repo.gun, data.ECDSAKey) + key, err := repo.GetCryptoService().Create(role, repo.gun, data.ECDSAKey) require.NoError(t, err, "error creating key") if x509 { start := time.Now().AddDate(0, 0, -1) - privKey, _, err := repo.CryptoService().GetPrivateKey(key.ID()) + privKey, _, err := repo.GetCryptoService().GetPrivateKey(key.ID()) require.NoError(t, err) cert, err := cryptoservice.GenerateCertificate( privKey, data.GUN(role), start, start.AddDate(1, 0, 0), @@ -2370,9 +2370,9 @@ func TestPublishTargetsDelegationNoTargetsKeyNeeded(t *testing.T) { rec.clear() // remove targets key - it is not even needed - targetsKeys := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) + targetsKeys := repo.GetCryptoService().ListKeys(data.CanonicalTargetsRole) require.Len(t, targetsKeys, 1) - require.NoError(t, repo.CryptoService().RemoveKey(targetsKeys[0])) + require.NoError(t, repo.GetCryptoService().RemoveKey(targetsKeys[0])) requirePublishToRolesSucceeds(t, repo, []data.RoleName{"targets/a/b"}, []data.RoleName{"targets/a/b"}) @@ -2405,11 +2405,11 @@ func TestPublishTargetsDelegationSuccessNeedsToDownloadRoles(t *testing.T) { defer os.RemoveAll(delgRepo.baseDir) // create a key on the owner repo - aKey, err := ownerRepo.CryptoService().Create("targets/a", gun, data.ECDSAKey) + aKey, err := ownerRepo.GetCryptoService().Create("targets/a", gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") // create a key on the delegated repo - bKey, err := delgRepo.CryptoService().Create("targets/a/b", gun, data.ECDSAKey) + bKey, err := delgRepo.GetCryptoService().Create("targets/a/b", gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") // clear metadata and unencrypted private key cache @@ -2470,11 +2470,11 @@ func TestPublishTargetsDelegationFromTwoRepos(t *testing.T) { defer os.RemoveAll(repo2.baseDir) // create keys for each repo - key1, err := repo1.CryptoService().Create("targets/a", repo1.gun, data.ECDSAKey) + key1, err := repo1.GetCryptoService().Create("targets/a", repo1.gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") // create a key on the delegated repo - key2, err := repo2.CryptoService().Create("targets/a", repo2.gun, data.ECDSAKey) + key2, err := repo2.GetCryptoService().Create("targets/a", repo2.gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") // delegation includes both keys @@ -2544,7 +2544,7 @@ func TestPublishRemoveDelegationKeyFromDelegationRole(t *testing.T) { defer os.RemoveAll(delgRepo.baseDir) // create a key on the delegated repo - aKey, err := delgRepo.CryptoService().Create("targets/a", delgRepo.gun, data.ECDSAKey) + aKey, err := delgRepo.GetCryptoService().Create("targets/a", delgRepo.gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") // owner creates delegation, adds the delegated key to it, and publishes it @@ -2559,7 +2559,7 @@ func TestPublishRemoveDelegationKeyFromDelegationRole(t *testing.T) { // owner revokes delegation // note there is no removekeyfromdelegation yet, so here's a hack to do so - newKey, err := ownerRepo.CryptoService().Create("targets/a", ownerRepo.gun, data.ECDSAKey) + newKey, err := ownerRepo.GetCryptoService().Create("targets/a", ownerRepo.gun, data.ECDSAKey) require.NoError(t, err) tdJSON, err := json.Marshal(&changelist.TUFDelegation{ NewThreshold: 1, @@ -2608,7 +2608,7 @@ func TestPublishRemoveDelegation(t *testing.T) { defer os.RemoveAll(delgRepo.baseDir) // create a key on the delegated repo - aKey, err := delgRepo.CryptoService().Create("targets/a", delgRepo.gun, data.ECDSAKey) + aKey, err := delgRepo.GetCryptoService().Create("targets/a", delgRepo.gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") // owner creates delegation, adds the delegated key to it, and publishes it @@ -2643,7 +2643,7 @@ func TestPublishSucceedsDespiteDelegationCorrupt(t *testing.T) { repo, _ := initializeRepo(t, data.ECDSAKey, "docker.com/notary", ts.URL, false) defer os.RemoveAll(repo.baseDir) - delgKey, err := repo.CryptoService().Create("targets/a", repo.gun, data.ECDSAKey) + delgKey, err := repo.GetCryptoService().Create("targets/a", repo.gun, data.ECDSAKey) require.NoError(t, err, "error creating delegation key") require.NoError(t, @@ -2666,7 +2666,7 @@ func TestRotateKeyInvalidRole(t *testing.T) { defer os.RemoveAll(repo.baseDir) // create a delegation - pubKey, err := repo.CryptoService().Create("targets/releases", data.GUN("docker.com/notary"), data.ECDSAKey) + pubKey, err := repo.GetCryptoService().Create("targets/releases", data.GUN("docker.com/notary"), data.ECDSAKey) require.NoError(t, err) require.NoError(t, repo.AddDelegation("targets/releases", []data.PublicKey{pubKey}, []string{""})) require.NoError(t, repo.Publish()) @@ -2817,7 +2817,7 @@ func requireRotationSuccessful(t *testing.T, repo1 *NotaryRepository, keysToRota canonicalID, err := utils.CanonicalKeyID(oldPubKey) require.NoError(t, err) - _, _, err = repo.CryptoService().GetPrivateKey(canonicalID) + _, _, err = repo.GetCryptoService().GetPrivateKey(canonicalID) switch roleName { case data.CanonicalRootRole: require.NoError(t, err) @@ -2834,7 +2834,7 @@ func requireRotationSuccessful(t *testing.T, repo1 *NotaryRepository, keysToRota canonicalID, err := utils.CanonicalKeyID(pubKey) require.NoError(t, err) - key, _, err := repo.CryptoService().GetPrivateKey(canonicalID) + key, _, err := repo.GetCryptoService().GetPrivateKey(canonicalID) if isRemoteKey { require.Error(t, err) require.Nil(t, key) @@ -3130,9 +3130,9 @@ func TestRotateRootKeyProvided(t *testing.T) { require.NoError(t, err) // Key loaded from file (just generating it here) - rootPublicKey, err := authorRepo.CryptoService().Create(data.CanonicalRootRole, "", data.ECDSAKey) + rootPublicKey, err := authorRepo.GetCryptoService().Create(data.CanonicalRootRole, "", data.ECDSAKey) require.NoError(t, err) - rootPrivateKey, _, err := authorRepo.CryptoService().GetPrivateKey(rootPublicKey.ID()) + rootPrivateKey, _, err := authorRepo.GetCryptoService().GetPrivateKey(rootPublicKey.ID()) require.NoError(t, err) // Fail to rotate to bad key @@ -3312,9 +3312,9 @@ func TestAddDelegationChangefileValid(t *testing.T) { repo, _ := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - targetKeyIds := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) + targetKeyIds := repo.GetCryptoService().ListKeys(data.CanonicalTargetsRole) require.NotEmpty(t, targetKeyIds) - targetPubKey := repo.CryptoService().GetKey(targetKeyIds[0]) + targetPubKey := repo.GetCryptoService().GetKey(targetKeyIds[0]) require.NotNil(t, targetPubKey) err := repo.AddDelegation(data.CanonicalRootRole, []data.PublicKey{targetPubKey}, []string{""}) @@ -3350,9 +3350,9 @@ func TestAddDelegationChangefileApplicable(t *testing.T) { repo, _ := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - targetKeyIds := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) + targetKeyIds := repo.GetCryptoService().ListKeys(data.CanonicalTargetsRole) require.NotEmpty(t, targetKeyIds) - targetPubKey := repo.CryptoService().GetKey(targetKeyIds[0]) + targetPubKey := repo.GetCryptoService().GetKey(targetKeyIds[0]) require.NotNil(t, targetPubKey) // this hierarchy has to be right to be applied @@ -3382,9 +3382,9 @@ func TestAddDelegationChangefileApplicable(t *testing.T) { // to be propagated. func TestAddDelegationErrorWritingChanges(t *testing.T) { testErrorWritingChangefiles(t, func(repo *NotaryRepository) error { - targetKeyIds := repo.CryptoService().ListKeys(data.CanonicalTargetsRole) + targetKeyIds := repo.GetCryptoService().ListKeys(data.CanonicalTargetsRole) require.NotEmpty(t, targetKeyIds) - targetPubKey := repo.CryptoService().GetKey(targetKeyIds[0]) + targetPubKey := repo.GetCryptoService().GetKey(targetKeyIds[0]) require.NotNil(t, targetPubKey) return repo.AddDelegation("targets/a", []data.PublicKey{targetPubKey}, []string{""}) @@ -3401,7 +3401,7 @@ func TestRemoveDelegationChangefileValid(t *testing.T) { repo, rootKeyID := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - rootPubKey := repo.CryptoService().GetKey(rootKeyID) + rootPubKey := repo.GetCryptoService().GetKey(rootKeyID) require.NotNil(t, rootPubKey) err := repo.RemoveDelegationKeys(data.CanonicalRootRole, []string{rootKeyID}) @@ -3432,7 +3432,7 @@ func TestRemoveDelegationChangefileApplicable(t *testing.T) { repo, rootKeyID := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - rootPubKey := repo.CryptoService().GetKey(rootKeyID) + rootPubKey := repo.GetCryptoService().GetKey(rootKeyID) require.NotNil(t, rootPubKey) // add a delegation first so it can be removed @@ -3468,7 +3468,7 @@ func TestClearAllPathsDelegationChangefileApplicable(t *testing.T) { repo, rootKeyID := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - rootPubKey := repo.CryptoService().GetKey(rootKeyID) + rootPubKey := repo.GetCryptoService().GetKey(rootKeyID) require.NotNil(t, rootPubKey) // add a delegation first so it can be removed @@ -3498,10 +3498,10 @@ func TestFullAddDelegationChangefileApplicable(t *testing.T) { repo, rootKeyID := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - rootPubKey := repo.CryptoService().GetKey(rootKeyID) + rootPubKey := repo.GetCryptoService().GetKey(rootKeyID) require.NotNil(t, rootPubKey) - key2, err := repo.CryptoService().Create("user", repo.gun, data.ECDSAKey) + key2, err := repo.GetCryptoService().Create("user", repo.gun, data.ECDSAKey) require.NoError(t, err) var delegationName data.RoleName = "targets/a" @@ -3540,10 +3540,10 @@ func TestFullRemoveDelegationChangefileApplicable(t *testing.T) { repo, rootKeyID := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false) defer os.RemoveAll(repo.baseDir) - rootPubKey := repo.CryptoService().GetKey(rootKeyID) + rootPubKey := repo.GetCryptoService().GetKey(rootKeyID) require.NotNil(t, rootPubKey) - key2, err := repo.CryptoService().Create("user", repo.gun, data.ECDSAKey) + key2, err := repo.GetCryptoService().Create("user", repo.gun, data.ECDSAKey) require.NoError(t, err) key2CanonicalID, err := utils.CanonicalKeyID(key2) require.NoError(t, err) @@ -3966,7 +3966,7 @@ func TestGetAllTargetInfo(t *testing.T) { targetsCurrentTarget := addTarget(t, repo, "current", "../fixtures/intermediate-ca.crt") // setup delegated targets/level1 role with targets current and other - k, err := repo.CryptoService().Create("targets/level1", repo.gun, rootType) + k, err := repo.GetCryptoService().Create("targets/level1", repo.gun, rootType) require.NoError(t, err) key1 := k err = repo.tufRepo.UpdateDelegationKeys("targets/level1", []data.PublicKey{k}, []string{}, 1) @@ -3977,7 +3977,7 @@ func TestGetAllTargetInfo(t *testing.T) { level1OtherTarget := addTarget(t, repo, "other", "../fixtures/root-ca.crt", "targets/level1") // setup delegated targets/level2 role with targets current and level2 - k, err = repo.CryptoService().Create("targets/level2", repo.gun, rootType) + k, err = repo.GetCryptoService().Create("targets/level2", repo.gun, rootType) require.NoError(t, err) key2 := k err = repo.tufRepo.UpdateDelegationKeys("targets/level2", []data.PublicKey{k}, []string{}, 1) @@ -4008,7 +4008,7 @@ func TestGetAllTargetInfo(t *testing.T) { // setup delegated targets/level1/level2 role separately, which can only modify paths prefixed with "level2" // add level2 to targets/level1/level2 - k, err = repo.CryptoService().Create("targets/level1/level2", repo.gun, rootType) + k, err = repo.GetCryptoService().Create("targets/level1/level2", repo.gun, rootType) require.NoError(t, err) key3 := k err = repo.tufRepo.UpdateDelegationKeys("targets/level1/level2", []data.PublicKey{k}, []string{}, 1) @@ -4038,7 +4038,7 @@ func TestGetAllTargetInfo(t *testing.T) { level2Level2 = expectation{role: "targets/level2", target: "level2"} level1Level2Level2 = expectation{role: "targets/level1/level2", target: "level2"} ) - targetsKey := repo.CryptoService().ListKeys(data.CanonicalTargetsRole)[0] + targetsKey := repo.GetCryptoService().ListKeys(data.CanonicalTargetsRole)[0] allExpected := map[expectation]TargetSignedStruct{ targetCurrent: { Target: *targetsCurrentTarget, diff --git a/client/interface.go b/client/interface.go index 22b9c0a56..ca09fb4eb 100644 --- a/client/interface.go +++ b/client/interface.go @@ -41,7 +41,7 @@ type Repository interface { // Key Operations RotateKey(role data.RoleName, serverManagesKey bool, keyList []string) error - CryptoService() signed.CryptoService + GetCryptoService() signed.CryptoService SetLegacyVersions(int) GetGUN() data.GUN } diff --git a/cmd/notary/keys.go b/cmd/notary/keys.go index 24f8b80f4..bf61b29cc 100644 --- a/cmd/notary/keys.go +++ b/cmd/notary/keys.go @@ -324,7 +324,7 @@ func (k *keyCommander) keysRotate(cmd *cobra.Command, args []string) error { if err != nil { return err } - err = nRepo.CryptoService().AddKey(rotateKeyRole, gun, privKey) + err = nRepo.GetCryptoService().AddKey(rotateKeyRole, gun, privKey) if err != nil { return fmt.Errorf("Error importing key: %v", err) } diff --git a/cmd/notary/keys_test.go b/cmd/notary/keys_test.go index 91a12a85e..5d85aa7a0 100644 --- a/cmd/notary/keys_test.go +++ b/cmd/notary/keys_test.go @@ -337,13 +337,13 @@ func setUpRepo(t *testing.T, tempBaseDir string, gun data.GUN, ret notary.PassRe tempBaseDir, gun, ts.URL, http.DefaultTransport, ret, trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) - rootPubKey, err := repo.CryptoService().Create(data.CanonicalRootRole, "", data.ECDSAKey) + rootPubKey, err := repo.GetCryptoService().Create(data.CanonicalRootRole, "", data.ECDSAKey) require.NoError(t, err, "error generating root key: %s", err) err = repo.Initialize([]string{rootPubKey.ID()}) require.NoError(t, err) - return ts, repo.CryptoService().ListAllKeys() + return ts, repo.GetCryptoService().ListAllKeys() } // The command line uses NotaryRepository's RotateKey - this is just testing @@ -383,7 +383,7 @@ func TestRotateKeyRemoteServerManagesKey(t *testing.T) { require.NoError(t, err, "unable to get changelist: %v", err) require.Len(t, cl.List(), 0, "expected the changes to have been published") - finalKeys := repo.CryptoService().ListAllKeys() + finalKeys := repo.GetCryptoService().ListAllKeys() // no keys have been created, since a remote key was specified if role == data.CanonicalSnapshotRole.String() { require.Len(t, finalKeys, 2) @@ -438,7 +438,7 @@ func TestRotateKeyBothKeys(t *testing.T) { require.Len(t, cl.List(), 0) // two new keys have been created, and the old keys should still be gone - newKeys := repo.CryptoService().ListAllKeys() + newKeys := repo.GetCryptoService().ListAllKeys() // there should be 3 keys - snapshot, targets, and root require.Len(t, newKeys, 3) @@ -499,7 +499,7 @@ func TestRotateKeyRootIsInteractive(t *testing.T) { require.NoError(t, err, "error creating repo: %s", err) // There should still just be one root key (and one targets and one snapshot) - allKeys := repo.CryptoService().ListAllKeys() + allKeys := repo.GetCryptoService().ListAllKeys() require.Len(t, allKeys, 3) } diff --git a/cmd/notary/tuf.go b/cmd/notary/tuf.go index f57ab85b8..fbb8b707b 100644 --- a/cmd/notary/tuf.go +++ b/cmd/notary/tuf.go @@ -418,13 +418,13 @@ func importRootKey(cmd *cobra.Command, rootKey string, nRepo notaryclient.Reposi return nil, err } // add root key to repo - err = nRepo.CryptoService().AddKey(data.CanonicalRootRole, "", privKey) + err = nRepo.GetCryptoService().AddKey(data.CanonicalRootRole, "", privKey) if err != nil { return nil, fmt.Errorf("Error importing key: %v", err) } rootKeyList = []string{privKey.ID()} } else { - rootKeyList = nRepo.CryptoService().ListKeys(data.CanonicalRootRole) + rootKeyList = nRepo.GetCryptoService().ListKeys(data.CanonicalRootRole) } if len(rootKeyList) > 0 {