diff --git a/Dockerfile b/Dockerfile
index 76c2de26cf052..dc62f07609eb6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -169,7 +169,7 @@ RUN set -x \
 	&& rm -rf "$GOPATH"
 
 # Install notary server
-ENV NOTARY_VERSION docker-v1.10-5
+ENV NOTARY_VERSION v0.2.0
 RUN set -x \
 	&& export GOPATH="$(mktemp -d)" \
 	&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64
index 3274289a4dc8f..947b393f46950 100644
--- a/Dockerfile.aarch64
+++ b/Dockerfile.aarch64
@@ -119,7 +119,7 @@ RUN set -x \
 	&& rm -rf "$GOPATH"
 
 # Install notary server
-ENV NOTARY_VERSION docker-v1.10-5
+ENV NOTARY_VERSION v0.2.0
 RUN set -x \
 	&& export GOPATH="$(mktemp -d)" \
 	&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
diff --git a/Dockerfile.armhf b/Dockerfile.armhf
index d95134bfadf6c..fd6f8721fa807 100644
--- a/Dockerfile.armhf
+++ b/Dockerfile.armhf
@@ -135,7 +135,7 @@ RUN set -x \
 	&& rm -rf "$GOPATH"
 
 # Install notary server
-ENV NOTARY_VERSION docker-v1.10-5
+ENV NOTARY_VERSION v0.2.0
 RUN set -x \
 	&& export GOPATH="$(mktemp -d)" \
 	&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
diff --git a/Dockerfile.ppc64le b/Dockerfile.ppc64le
index b48b1ae6955b2..fc1d929f48b12 100644
--- a/Dockerfile.ppc64le
+++ b/Dockerfile.ppc64le
@@ -127,16 +127,16 @@ RUN set -x \
 		go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
 	&& rm -rf "$GOPATH"
 
-# TODO update this when we upgrade to Go 1.5.1+
+
 # Install notary server
-#ENV NOTARY_VERSION docker-v1.10-5
-#RUN set -x \
-#	&& export GOPATH="$(mktemp -d)" \
-#	&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
-#	&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
-#	&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
-#		go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
-#	&& rm -rf "$GOPATH"
+ENV NOTARY_VERSION v0.2.0
+RUN set -x \
+	&& export GOPATH="$(mktemp -d)" \
+	&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
+	&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
+	&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
+		go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
+	&& rm -rf "$GOPATH"
 
 # Get the "docker-py" source so we can run their integration tests
 ENV DOCKER_PY_COMMIT e2878cbcc3a7eef99917adc1be252800b0e41ece
diff --git a/Dockerfile.s390x b/Dockerfile.s390x
index f80ffb31b19c1..f46e1e0c9b9d9 100644
--- a/Dockerfile.s390x
+++ b/Dockerfile.s390x
@@ -108,7 +108,7 @@ RUN set -x \
 	&& rm -rf "$GOPATH"
 
 # Install notary server
-ENV NOTARY_VERSION docker-v1.10-5
+ENV NOTARY_VERSION v0.2.0
 RUN set -x \
 	&& export GOPATH="$(mktemp -d)" \
 	&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
diff --git a/hack/vendor.sh b/hack/vendor.sh
index 53deb94279750..ee3dde1a8964f 100755
--- a/hack/vendor.sh
+++ b/hack/vendor.sh
@@ -52,7 +52,7 @@ clone git github.com/docker/distribution 7b66c50bb7e0e4b3b83f8fd134a9f6ea4be08b5
 clone git github.com/vbatts/tar-split v0.9.11
 
 # get desired notary commit, might also need to be updated in Dockerfile
-clone git github.com/docker/notary docker-v1.10-5
+clone git github.com/docker/notary v0.2.0
 
 clone git google.golang.org/grpc 174192fc93efcb188fc8f46ca447f0da606b6885 https://github.com/grpc/grpc-go.git
 clone git github.com/miekg/pkcs11 80f102b5cac759de406949c47f0928b99bd64cdf
diff --git a/integration-cli/docker_cli_create_test.go b/integration-cli/docker_cli_create_test.go
index 657c3fd6a29f4..81f3284368d4e 100644
--- a/integration-cli/docker_cli_create_test.go
+++ b/integration-cli/docker_cli_create_test.go
@@ -365,7 +365,7 @@ func (s *DockerTrustSuite) TestCreateWhenCertExpired(c *check.C) {
 
 func (s *DockerTrustSuite) TestTrustedCreateFromBadTrustServer(c *check.C) {
 	repoName := fmt.Sprintf("%v/dockerclievilcreate/trusted:latest", privateRegistryURL)
-	evilLocalConfigDir, err := ioutil.TempDir("", "evil-local-config-dir")
+	evilLocalConfigDir, err := ioutil.TempDir("", "evilcreate-local-config-dir")
 	c.Assert(err, check.IsNil)
 
 	// tag the image and upload it to the private registry
@@ -404,12 +404,16 @@ func (s *DockerTrustSuite) TestTrustedCreateFromBadTrustServer(c *check.C) {
 	c.Assert(err, check.IsNil)
 	c.Assert(string(out), checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push:\n%s", out))
 
-	// Now, try creating with the original client from this new trust server. This should fail.
+	// Now, try creating with the original client from this new trust server. This should fallback to our cached timestamp and metadata.
 	createCmd = exec.Command(dockerBinary, "create", repoName)
 	s.trustedCmd(createCmd)
 	out, _, err = runCommandWithOutput(createCmd)
-	c.Assert(err, check.Not(check.IsNil))
-	c.Assert(string(out), checker.Contains, "valid signatures did not meet threshold", check.Commentf("Missing expected output on trusted push:\n%s", out))
+	if err != nil {
+		c.Fatalf("Error falling back to cached trust data: %s\n%s", err, out)
+	}
+	if !strings.Contains(string(out), "Error while downloading remote metadata, using cached timestamp") {
+		c.Fatalf("Missing expected output on trusted create:\n%s", out)
+	}
 
 }
 
diff --git a/integration-cli/docker_cli_pull_trusted_test.go b/integration-cli/docker_cli_pull_trusted_test.go
index 2f194d08a4d45..fdaaaa1a82ff0 100644
--- a/integration-cli/docker_cli_pull_trusted_test.go
+++ b/integration-cli/docker_cli_pull_trusted_test.go
@@ -135,13 +135,16 @@ func (s *DockerTrustSuite) TestTrustedPullFromBadTrustServer(c *check.C) {
 	c.Assert(err, check.IsNil, check.Commentf(out))
 	c.Assert(string(out), checker.Contains, "Signing and pushing trust metadata", check.Commentf(out))
 
-	// Now, try pulling with the original client from this new trust server. This should fail.
+	// Now, try pulling with the original client from this new trust server. This should fall back to cached metadata.
 	pullCmd = exec.Command(dockerBinary, "pull", repoName)
 	s.trustedCmd(pullCmd)
 	out, _, err = runCommandWithOutput(pullCmd)
-
-	c.Assert(err, check.NotNil, check.Commentf(out))
-	c.Assert(string(out), checker.Contains, "valid signatures did not meet threshold", check.Commentf(out))
+	if err != nil {
+		c.Fatalf("Error falling back to cached trust data: %s\n%s", err, out)
+	}
+	if !strings.Contains(string(out), "Error while downloading remote metadata, using cached timestamp") {
+		c.Fatalf("Missing expected output on trusted pull:\n%s", out)
+	}
 }
 
 func (s *DockerTrustSuite) TestTrustedPullWithExpiredSnapshot(c *check.C) {
diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go
index 1cd40408bf899..c2e0644796e87 100644
--- a/integration-cli/docker_cli_run_test.go
+++ b/integration-cli/docker_cli_run_test.go
@@ -3260,7 +3260,7 @@ func (s *DockerTrustSuite) TestTrustedRunFromBadTrustServer(c *check.C) {
 	// Windows does not support this functionality
 	testRequires(c, DaemonIsLinux)
 	repoName := fmt.Sprintf("%v/dockerclievilrun/trusted:latest", privateRegistryURL)
-	evilLocalConfigDir, err := ioutil.TempDir("", "evil-local-config-dir")
+	evilLocalConfigDir, err := ioutil.TempDir("", "evilrun-local-config-dir")
 	if err != nil {
 		c.Fatalf("Failed to create local temp dir")
 	}
@@ -3316,15 +3316,15 @@ func (s *DockerTrustSuite) TestTrustedRunFromBadTrustServer(c *check.C) {
 		c.Fatalf("Missing expected output on trusted push:\n%s", out)
 	}
 
-	// Now, try running with the original client from this new trust server. This should fail.
+	// Now, try running with the original client from this new trust server. This should fallback to our cached timestamp and metadata.
 	runCmd = exec.Command(dockerBinary, "run", repoName)
 	s.trustedCmd(runCmd)
 	out, _, err = runCommandWithOutput(runCmd)
-	if err == nil {
-		c.Fatalf("Expected to fail on this run due to different remote data: %s\n%s", err, out)
-	}
 
-	if !strings.Contains(string(out), "valid signatures did not meet threshold") {
+	if err != nil {
+		c.Fatalf("Error falling back to cached trust data: %s\n%s", err, out)
+	}
+	if !strings.Contains(string(out), "Error while downloading remote metadata, using cached timestamp") {
 		c.Fatalf("Missing expected output on trusted push:\n%s", out)
 	}
 }
diff --git a/integration-cli/trust_server.go b/integration-cli/trust_server.go
index 9629e8457522f..a8ec3181b1d44 100644
--- a/integration-cli/trust_server.go
+++ b/integration-cli/trust_server.go
@@ -237,7 +237,7 @@ func (s *DockerTrustSuite) setupDelegations(c *check.C, repoName, pwd string) {
 	if err != nil {
 		c.Fatalf("Error creating delegation key: %s\n", err)
 	}
-	err = nRepo.AddDelegation("targets/releases", 1, []data.PublicKey{delgKey}, []string{""})
+	err = nRepo.AddDelegation("targets/releases", []data.PublicKey{delgKey}, []string{""})
 	if err != nil {
 		c.Fatalf("Error creating delegation: %s\n", err)
 	}
diff --git a/vendor/src/github.com/docker/notary/Makefile b/vendor/src/github.com/docker/notary/Makefile
index 949d79864ae15..447514af09a3b 100644
--- a/vendor/src/github.com/docker/notary/Makefile
+++ b/vendor/src/github.com/docker/notary/Makefile
@@ -42,14 +42,6 @@ GO_VERSION = $(shell go version | awk '{print $$3}')
 .DELETE_ON_ERROR: cover
 .DEFAULT: default
 
-go_version:
-ifeq (,$(findstring go1.5.,$(GO_VERSION)))
-	$(error Requires go version 1.5.x - found $(GO_VERSION))
-else
-	@echo
-endif
-
-
 all: AUTHORS clean fmt vet fmt lint build test binaries
 
 AUTHORS: .git/HEAD
@@ -71,7 +63,23 @@ ${PREFIX}/bin/notary-signer: NOTARY_VERSION $(shell find . -type f -name '*.go')
 	@echo "+ $@"
 	@godep go build -tags ${NOTARY_BUILDTAGS} -o $@ ${GO_LDFLAGS} ./cmd/notary-signer
 
-vet: go_version
+ifeq ($(shell uname -s),Darwin)
+${PREFIX}/bin/static/notary-server:
+	@echo "notary-server: static builds not supported on OS X"
+
+${PREFIX}/bin/static/notary-signer:
+	@echo "notary-signer: static builds not supported on OS X"
+else
+${PREFIX}/bin/static/notary-server: NOTARY_VERSION $(shell find . -type f -name '*.go')
+	@echo "+ $@"
+	@godep go build -tags ${NOTARY_BUILDTAGS} -o $@ ${GO_LDFLAGS_STATIC} ./cmd/notary-server
+
+${PREFIX}/bin/static/notary-signer: NOTARY_VERSION $(shell find . -type f -name '*.go')
+	@echo "+ $@"
+	@godep go build -tags ${NOTARY_BUILDTAGS} -o $@ ${GO_LDFLAGS_STATIC} ./cmd/notary-signer
+endif
+
+vet: 
 	@echo "+ $@"
 ifeq ($(shell uname -s), Darwin)
 	@test -z "$(shell find . -iname *test*.go | grep -v _test.go | grep -v Godeps | xargs echo "This file should end with '_test':"  | tee /dev/stderr)"
@@ -88,14 +96,24 @@ lint:
 	@echo "+ $@"
 	@test -z "$$(golint ./... | grep -v .pb. | grep -v Godeps/_workspace/src/ | tee /dev/stderr)"
 
-build: go_version
+# Requires that the following:
+# go get -u github.com/client9/misspell/cmd/misspell
+#
+# be run first
+
+# misspell target, don't include Godeps, binaries, python tests, or git files
+misspell:
+	@echo "+ $@"
+	@test -z "$$(find . -name '*' | grep -v Godeps/_workspace/src/ | grep -v bin/ | grep -v misc/ | grep -v .git/ | xargs misspell | tee /dev/stderr)"
+
+build:
 	@echo "+ $@"
 	@go build -tags "${NOTARY_BUILDTAGS}" -v ${GO_LDFLAGS} ./...
 
 # When running `go test ./...`, it runs all the suites in parallel, which causes
 # problems when running with a yubikey
 test: TESTOPTS =
-test: go_version
+test: 
 	@echo Note: when testing with a yubikey plugged in, make sure to include 'TESTOPTS="-p 1"'
 	@echo "+ $@ $(TESTOPTS)"
 	@echo
@@ -121,7 +139,7 @@ define gocover
 $(GO_EXC) test $(OPTS) $(TESTOPTS) -covermode="$(COVERMODE)" -coverprofile="$(COVERDIR)/$(subst /,-,$(1)).$(subst $(_space),.,$(NOTARY_BUILDTAGS)).coverage.txt" "$(1)" || exit 1;
 endef
 
-gen-cover: go_version
+gen-cover: 
 	@mkdir -p "$(COVERDIR)"
 	$(foreach PKG,$(PKGS),$(call gocover,$(PKG)))
 	rm -f "$(COVERDIR)"/*testutils*.coverage.txt
@@ -150,7 +168,10 @@ covmerge:
 clean-protos:
 	@rm proto/*.pb.go
 
-binaries: go_version ${PREFIX}/bin/notary-server ${PREFIX}/bin/notary ${PREFIX}/bin/notary-signer
+binaries: ${PREFIX}/bin/notary-server ${PREFIX}/bin/notary ${PREFIX}/bin/notary-signer
+	@echo "+ $@"
+
+static: ${PREFIX}/bin/static/notary-server ${PREFIX}/bin/static/notary-signer
 	@echo "+ $@"
 
 define template
@@ -158,7 +179,7 @@ mkdir -p ${PREFIX}/cross/$(1)/$(2);
 GOOS=$(1) GOARCH=$(2) CGO_ENABLED=0 go build -o ${PREFIX}/cross/$(1)/$(2)/notary -a -tags "static_build netgo" -installsuffix netgo ${GO_LDFLAGS_STATIC} ./cmd/notary;
 endef
 
-cross: go_version
+cross: 
 	$(foreach GOARCH,$(GOARCHS),$(foreach GOOS,$(GOOSES),$(call template,$(GOOS),$(GOARCH))))
 
 
diff --git a/vendor/src/github.com/docker/notary/README.md b/vendor/src/github.com/docker/notary/README.md
index ed3ca49351d3a..96cd5be5c6bfe 100644
--- a/vendor/src/github.com/docker/notary/README.md
+++ b/vendor/src/github.com/docker/notary/README.md
@@ -1,4 +1,5 @@
-# Notary [![Circle CI](https://circleci.com/gh/docker/notary/tree/master.svg?style=shield)](https://circleci.com/gh/docker/notary/tree/master)
+# Notary 
+[![Circle CI](https://circleci.com/gh/docker/notary/tree/master.svg?style=shield)](https://circleci.com/gh/docker/notary/tree/master) [![CodeCov](https://codecov.io/github/docker/notary/coverage.svg?branch=master)](https://codecov.io/github/docker/notary)
 
 The Notary project comprises a [server](cmd/notary-server) and a [client](cmd/notary) for running and interacting
 with trusted collections.
diff --git a/vendor/src/github.com/docker/notary/circle.yml b/vendor/src/github.com/docker/notary/circle.yml
index 163d610f24c1e..6b98a161f1601 100644
--- a/vendor/src/github.com/docker/notary/circle.yml
+++ b/vendor/src/github.com/docker/notary/circle.yml
@@ -6,7 +6,7 @@ machine:
 
   post:
   # Install many go versions
-    - gvm install go1.5.1 -B --name=stable
+    - gvm install go1.6 -B --name=stable
 
   environment:
   # Convenient shortcuts to "common" locations
@@ -37,10 +37,11 @@ dependencies:
         pwd: $BASE_STABLE
 
   post:
-  # For the stable go version, additionally install linting tools
+  # For the stable go version, additionally install linting and misspell tools
     - >
       gvm use stable &&
-      go get github.com/golang/lint/golint
+      go get github.com/golang/lint/golint &&
+      go get -u github.com/client9/misspell/cmd/misspell
 test:
   pre:
   # Output the go versions we are going to test
@@ -62,6 +63,10 @@ test:
     - gvm use stable && make lint:
         pwd: $BASE_STABLE
 
+  # MISSPELL
+    - gvm use stable && make misspell:
+        pwd: $BASE_STABLE
+
   override:
   # Test stable, and report
   # hacking this to be parallel
diff --git a/vendor/src/github.com/docker/notary/client/changelist/change.go b/vendor/src/github.com/docker/notary/client/changelist/change.go
index 311857aa61cfb..3307189c8108b 100644
--- a/vendor/src/github.com/docker/notary/client/changelist/change.go
+++ b/vendor/src/github.com/docker/notary/client/changelist/change.go
@@ -17,7 +17,7 @@ const (
 // Types for TufChanges are namespaced by the Role they
 // are relevant for. The Root and Targets roles are the
 // only ones for which user action can cause a change, as
-// all changes in Snapshot and Timestamp are programatically
+// all changes in Snapshot and Timestamp are programmatically
 // generated base on Root and Targets changes.
 const (
 	TypeRootRole          = "role"
@@ -82,14 +82,13 @@ func (c TufChange) Content() []byte {
 // this includes creating a delegations. This format is used to avoid
 // unexpected race conditions between humans modifying the same delegation
 type TufDelegation struct {
-	NewName                string       `json:"new_name,omitempty"`
-	NewThreshold           int          `json:"threshold, omitempty"`
-	AddKeys                data.KeyList `json:"add_keys, omitempty"`
-	RemoveKeys             []string     `json:"remove_keys,omitempty"`
-	AddPaths               []string     `json:"add_paths,omitempty"`
-	RemovePaths            []string     `json:"remove_paths,omitempty"`
-	AddPathHashPrefixes    []string     `json:"add_prefixes,omitempty"`
-	RemovePathHashPrefixes []string     `json:"remove_prefixes,omitempty"`
+	NewName       string       `json:"new_name,omitempty"`
+	NewThreshold  int          `json:"threshold, omitempty"`
+	AddKeys       data.KeyList `json:"add_keys, omitempty"`
+	RemoveKeys    []string     `json:"remove_keys,omitempty"`
+	AddPaths      []string     `json:"add_paths,omitempty"`
+	RemovePaths   []string     `json:"remove_paths,omitempty"`
+	ClearAllPaths bool         `json:"clear_paths,omitempty"`
 }
 
 // ToNewRole creates a fresh role object from the TufDelegation data
@@ -98,5 +97,5 @@ func (td TufDelegation) ToNewRole(scope string) (*data.Role, error) {
 	if td.NewName != "" {
 		name = td.NewName
 	}
-	return data.NewRole(name, td.NewThreshold, td.AddKeys.IDs(), td.AddPaths, td.AddPathHashPrefixes)
+	return data.NewRole(name, td.NewThreshold, td.AddKeys.IDs(), td.AddPaths)
 }
diff --git a/vendor/src/github.com/docker/notary/client/client.go b/vendor/src/github.com/docker/notary/client/client.go
index b383c94dcafdb..cbb49771324fd 100644
--- a/vendor/src/github.com/docker/notary/client/client.go
+++ b/vendor/src/github.com/docker/notary/client/client.go
@@ -9,6 +9,7 @@ import (
 	"net/url"
 	"os"
 	"path/filepath"
+	"strings"
 	"time"
 
 	"github.com/Sirupsen/logrus"
@@ -20,23 +21,13 @@ import (
 	"github.com/docker/notary/tuf"
 	tufclient "github.com/docker/notary/tuf/client"
 	"github.com/docker/notary/tuf/data"
-	"github.com/docker/notary/tuf/keys"
 	"github.com/docker/notary/tuf/signed"
 	"github.com/docker/notary/tuf/store"
-)
-
-const (
-	maxSize = 5 << 20
+	"github.com/docker/notary/tuf/utils"
 )
 
 func init() {
-	data.SetDefaultExpiryTimes(
-		map[string]int{
-			"root":     3650,
-			"targets":  1095,
-			"snapshot": 1095,
-		},
-	)
+	data.SetDefaultExpiryTimes(notary.NotaryDefaultExpiries)
 }
 
 // ErrRepoNotInitialized is returned when trying to publish an uninitialized
@@ -118,7 +109,6 @@ func repositoryFromKeystores(baseDir, gun, baseURL string, rt http.RoundTripper,
 		nRepo.tufRepoPath,
 		"metadata",
 		"json",
-		"",
 	)
 	if err != nil {
 		return nil, err
@@ -218,11 +208,16 @@ func (r *NotaryRepository) Initialize(rootKeyID string, serverManagedRoles ...st
 		return fmt.Errorf("invalid format for root key: %s", privKey.Algorithm())
 	}
 
-	kdb := keys.NewDB()
-	err = addKeyForRole(kdb, data.CanonicalRootRole, rootKey)
-	if err != nil {
-		return err
-	}
+	var (
+		rootRole = data.NewBaseRole(
+			data.CanonicalRootRole,
+			notary.MinThreshold,
+			rootKey,
+		)
+		timestampRole data.BaseRole
+		snapshotRole  data.BaseRole
+		targetsRole   data.BaseRole
+	)
 
 	// we want to create all the local keys first so we don't have to
 	// make unnecessary network calls
@@ -232,8 +227,19 @@ func (r *NotaryRepository) Initialize(rootKeyID string, serverManagedRoles ...st
 		if err != nil {
 			return err
 		}
-		if err := addKeyForRole(kdb, role, key); err != nil {
-			return err
+		switch role {
+		case data.CanonicalSnapshotRole:
+			snapshotRole = data.NewBaseRole(
+				role,
+				notary.MinThreshold,
+				key,
+			)
+		case data.CanonicalTargetsRole:
+			targetsRole = data.NewBaseRole(
+				role,
+				notary.MinThreshold,
+				key,
+			)
 		}
 	}
 	for _, role := range remotelyManagedKeys {
@@ -244,14 +250,31 @@ func (r *NotaryRepository) Initialize(rootKeyID string, serverManagedRoles ...st
 		}
 		logrus.Debugf("got remote %s %s key with keyID: %s",
 			role, key.Algorithm(), key.ID())
-		if err := addKeyForRole(kdb, role, key); err != nil {
-			return err
+		switch role {
+		case data.CanonicalSnapshotRole:
+			snapshotRole = data.NewBaseRole(
+				role,
+				notary.MinThreshold,
+				key,
+			)
+		case data.CanonicalTimestampRole:
+			timestampRole = data.NewBaseRole(
+				role,
+				notary.MinThreshold,
+				key,
+			)
 		}
 	}
 
-	r.tufRepo = tuf.NewRepo(kdb, r.CryptoService)
+	r.tufRepo = tuf.NewRepo(r.CryptoService)
 
-	err = r.tufRepo.InitRoot(false)
+	err = r.tufRepo.InitRoot(
+		rootRole,
+		timestampRole,
+		snapshotRole,
+		targetsRole,
+		false,
+	)
 	if err != nil {
 		logrus.Debug("Error on InitRoot: ", err.Error())
 		return err
@@ -305,96 +328,6 @@ func addChange(cl *changelist.FileChangelist, c changelist.Change, roles ...stri
 	return nil
 }
 
-// AddDelegation creates a new changelist entry to add a delegation to the repository
-// when the changelist gets applied at publish time.  This does not do any validation
-// other than checking the name of the delegation to add - all that will happen
-// at publish time.
-func (r *NotaryRepository) AddDelegation(name string, threshold int,
-	delegationKeys []data.PublicKey, paths []string) error {
-
-	if !data.IsDelegation(name) {
-		return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
-	}
-
-	cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist"))
-	if err != nil {
-		return err
-	}
-	defer cl.Close()
-
-	logrus.Debugf(`Adding delegation "%s" with threshold %d, and %d keys\n`,
-		name, threshold, len(delegationKeys))
-
-	tdJSON, err := json.Marshal(&changelist.TufDelegation{
-		NewThreshold: threshold,
-		AddKeys:      data.KeyList(delegationKeys),
-		AddPaths:     paths,
-	})
-	if err != nil {
-		return err
-	}
-
-	template := changelist.NewTufChange(
-		changelist.ActionCreate,
-		name,
-		changelist.TypeTargetsDelegation,
-		"", // no path
-		tdJSON,
-	)
-
-	return addChange(cl, template, name)
-}
-
-// RemoveDelegation creates a new changelist entry to remove a delegation from
-// the repository when the changelist gets applied at publish time.
-// This does not validate that the delegation exists, since one might exist
-// after applying all changes.
-func (r *NotaryRepository) RemoveDelegation(name string, keyIDs, paths []string, removeAll bool) error {
-
-	if !data.IsDelegation(name) {
-		return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
-	}
-
-	cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist"))
-	if err != nil {
-		return err
-	}
-	defer cl.Close()
-
-	logrus.Debugf(`Removing delegation "%s"\n`, name)
-	var template *changelist.TufChange
-
-	// We use the Delete action only for force removal, Update is used for removing individual keys and paths
-	if removeAll {
-		template = changelist.NewTufChange(
-			changelist.ActionDelete,
-			name,
-			changelist.TypeTargetsDelegation,
-			"",  // no path
-			nil, // deleting role, no data needed
-		)
-
-	} else {
-		tdJSON, err := json.Marshal(&changelist.TufDelegation{
-			RemoveKeys:  keyIDs,
-			RemovePaths: paths,
-		})
-		if err != nil {
-			return err
-		}
-
-		template = changelist.NewTufChange(
-			changelist.ActionUpdate,
-			name,
-			changelist.TypeTargetsDelegation,
-			"", // no path
-			tdJSON,
-		)
-	}
-
-	return addChange(cl, template, name)
-}
-
 // AddTarget creates new changelist entries to add a target to the given roles
 // in the repository when the changelist gets applied at publish time.
 // If roles are unspecified, the default role is "targets".
@@ -452,10 +385,24 @@ func (r *NotaryRepository) ListTargets(roles ...string) ([]*TargetWithRole, erro
 	}
 	targets := make(map[string]*TargetWithRole)
 	for _, role := range roles {
-		// we don't need to do anything special with removing role from
-		// roles because listSubtree always processes role and only excludes
-		// descendant delegations that appear in roles.
-		r.listSubtree(targets, role, roles...)
+		// Define an array of roles to skip for this walk (see IMPORTANT comment above)
+		skipRoles := utils.StrSliceRemove(roles, role)
+
+		// Define a visitor function to populate the targets map in priority order
+		listVisitorFunc := func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} {
+			// We found targets so we should try to add them to our targets map
+			for targetName, targetMeta := range tgt.Signed.Targets {
+				// Follow the priority by not overriding previously set targets
+				// and check that this path is valid with this role
+				if _, ok := targets[targetName]; ok || !validRole.CheckPaths(targetName) {
+					continue
+				}
+				targets[targetName] =
+					&TargetWithRole{Target: Target{Name: targetName, Hashes: targetMeta.Hashes, Length: targetMeta.Length}, Role: validRole.Name}
+			}
+			return nil
+		}
+		r.tufRepo.WalkTargets("", role, listVisitorFunc, skipRoles...)
 	}
 
 	var targetList []*TargetWithRole
@@ -466,34 +413,6 @@ func (r *NotaryRepository) ListTargets(roles ...string) ([]*TargetWithRole, erro
 	return targetList, nil
 }
 
-func (r *NotaryRepository) listSubtree(targets map[string]*TargetWithRole, role string, exclude ...string) {
-	excl := make(map[string]bool)
-	for _, r := range exclude {
-		excl[r] = true
-	}
-	roles := []string{role}
-	for len(roles) > 0 {
-		role = roles[0]
-		roles = roles[1:]
-		tgts, ok := r.tufRepo.Targets[role]
-		if !ok {
-			// not every role has to exist
-			continue
-		}
-		for name, meta := range tgts.Signed.Targets {
-			if _, ok := targets[name]; !ok {
-				targets[name] = &TargetWithRole{
-					Target: Target{Name: name, Hashes: meta.Hashes, Length: meta.Length}, Role: role}
-			}
-		}
-		for _, d := range tgts.Signed.Delegations.Roles {
-			if !excl[d.Name] {
-				roles = append(roles, d.Name)
-			}
-		}
-	}
-}
-
 // GetTargetByName returns a target given a name. If no roles are passed
 // it uses the targets role and does a search of the entire delegation
 // graph, finding the first entry in a breadth first search of the delegations.
@@ -502,7 +421,7 @@ func (r *NotaryRepository) listSubtree(targets map[string]*TargetWithRole, role
 // will be returned
 // See the IMPORTANT section on ListTargets above. Those roles also apply here.
 func (r *NotaryRepository) GetTargetByName(name string, roles ...string) (*TargetWithRole, error) {
-	c, err := r.Update(false)
+	_, err := r.Update(false)
 	if err != nil {
 		return nil, err
 	}
@@ -510,11 +429,30 @@ func (r *NotaryRepository) GetTargetByName(name string, roles ...string) (*Targe
 	if len(roles) == 0 {
 		roles = append(roles, data.CanonicalTargetsRole)
 	}
+	var resultMeta data.FileMeta
+	var resultRoleName string
+	var foundTarget bool
 	for _, role := range roles {
-		meta, foundRole := c.TargetMeta(role, name, roles...)
-		if meta != nil {
-			return &TargetWithRole{
-				Target: Target{Name: name, Hashes: meta.Hashes, Length: meta.Length}, Role: foundRole}, nil
+		// Define an array of roles to skip for this walk (see IMPORTANT comment above)
+		skipRoles := utils.StrSliceRemove(roles, role)
+
+		// Define a visitor function to find the specified target
+		getTargetVisitorFunc := func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} {
+			if tgt == nil {
+				return nil
+			}
+			// We found the target and validated path compatibility in our walk,
+			// so we should stop our walk and set the resultMeta and resultRoleName variables
+			if resultMeta, foundTarget = tgt.Signed.Targets[name]; foundTarget {
+				resultRoleName = validRole.Name
+				return tuf.StopWalk{}
+			}
+			return nil
+		}
+		err = r.tufRepo.WalkTargets(name, role, getTargetVisitorFunc, skipRoles...)
+		// Check that we didn't error, and that we assigned to our target
+		if err == nil && foundTarget {
+			return &TargetWithRole{Target: Target{Name: name, Hashes: resultMeta.Hashes, Length: resultMeta.Length}, Role: resultRoleName}, nil
 		}
 	}
 	return nil, fmt.Errorf("No trust data for %s", name)
@@ -532,45 +470,6 @@ func (r *NotaryRepository) GetChangelist() (changelist.Changelist, error) {
 	return cl, nil
 }
 
-// GetDelegationRoles returns the keys and roles of the repository's delegations
-func (r *NotaryRepository) GetDelegationRoles() ([]*data.Role, error) {
-	// Update state of the repo to latest
-	if _, err := r.Update(false); err != nil {
-		return nil, err
-	}
-
-	// All top level delegations (ex: targets/level1) are stored exclusively in targets.json
-	targets, ok := r.tufRepo.Targets[data.CanonicalTargetsRole]
-	if !ok {
-		return nil, store.ErrMetaNotFound{Resource: data.CanonicalTargetsRole}
-	}
-
-	allDelegations := targets.Signed.Delegations.Roles
-
-	// make a copy for traversing nested delegations
-	delegationsList := make([]*data.Role, len(allDelegations))
-	copy(delegationsList, allDelegations)
-
-	// Now traverse to lower level delegations (ex: targets/level1/level2)
-	for len(delegationsList) > 0 {
-		// Pop off first delegation to traverse
-		delegation := delegationsList[0]
-		delegationsList = delegationsList[1:]
-
-		// Get metadata
-		delegationMeta, ok := r.tufRepo.Targets[delegation.Name]
-		// If we get an error, don't try to traverse further into this subtree because it doesn't exist or is malformed
-		if !ok {
-			continue
-		}
-
-		// Add nested delegations to return list and exploration list
-		allDelegations = append(allDelegations, delegationMeta.Signed.Delegations.Roles...)
-		delegationsList = append(delegationsList, delegationMeta.Signed.Delegations.Roles...)
-	}
-	return allDelegations, nil
-}
-
 // RoleWithSignatures is a Role with its associated signatures
 type RoleWithSignatures struct {
 	Signatures []data.Signature
@@ -604,7 +503,7 @@ func (r *NotaryRepository) ListRoles() ([]RoleWithSignatures, error) {
 		case data.CanonicalTimestampRole:
 			roleWithSig.Signatures = r.tufRepo.Timestamp.Signatures
 		default:
-			// If the role isn't a delegation, we should error -- this is only possible if we have invalid keyDB state
+			// If the role isn't a delegation, we should error -- this is only possible if we have invalid state
 			if !data.IsDelegation(role.Name) {
 				return nil, data.ErrInvalidRole{Role: role.Name, Reason: "invalid role name"}
 			}
@@ -705,7 +604,7 @@ func (r *NotaryRepository) Publish() error {
 		r.tufRepo, data.CanonicalSnapshotRole)
 
 	if err == nil {
-		// Only update the snapshot if we've sucessfully signed it.
+		// Only update the snapshot if we've successfully signed it.
 		updatedFiles[data.CanonicalSnapshotRole] = snapshotJSON
 	} else if _, ok := err.(signed.ErrNoKeys); ok {
 		// If signing fails due to us not having the snapshot key, then
@@ -743,11 +642,10 @@ func (r *NotaryRepository) Publish() error {
 // This can also be unified with some cache reading tools from tuf/client.
 // This assumes that bootstrapRepo is only used by Publish()
 func (r *NotaryRepository) bootstrapRepo() error {
-	kdb := keys.NewDB()
-	tufRepo := tuf.NewRepo(kdb, r.CryptoService)
+	tufRepo := tuf.NewRepo(r.CryptoService)
 
 	logrus.Debugf("Loading trusted collection.")
-	rootJSON, err := r.fileStore.GetMeta("root", 0)
+	rootJSON, err := r.fileStore.GetMeta("root", -1)
 	if err != nil {
 		return err
 	}
@@ -760,7 +658,7 @@ func (r *NotaryRepository) bootstrapRepo() error {
 	if err != nil {
 		return err
 	}
-	targetsJSON, err := r.fileStore.GetMeta("targets", 0)
+	targetsJSON, err := r.fileStore.GetMeta("targets", -1)
 	if err != nil {
 		return err
 	}
@@ -771,7 +669,7 @@ func (r *NotaryRepository) bootstrapRepo() error {
 	}
 	tufRepo.SetTargets("targets", targets)
 
-	snapshotJSON, err := r.fileStore.GetMeta("snapshot", 0)
+	snapshotJSON, err := r.fileStore.GetMeta("snapshot", -1)
 	if err == nil {
 		snapshot := &data.SignedSnapshot{}
 		err = json.Unmarshal(snapshotJSON, snapshot)
@@ -854,7 +752,10 @@ func (r *NotaryRepository) Update(forWrite bool) (*tufclient.Client, error) {
 	}
 	err = c.Update()
 	if err != nil {
-		if notFound, ok := err.(store.ErrMetaNotFound); ok && notFound.Resource == data.CanonicalRootRole {
+		// notFound.Resource may include a checksum so when the role is root,
+		// it will be root.json or root.<checksum>.json. Therefore best we can
+		// do it match a "root." prefix
+		if notFound, ok := err.(store.ErrMetaNotFound); ok && strings.HasPrefix(notFound.Resource, data.CanonicalRootRole+".") {
 			return nil, r.errRepositoryNotExist()
 		}
 		return nil, err
@@ -876,7 +777,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufclient.Cl
 	// 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.
-	rootJSON, cachedRootErr := r.fileStore.GetMeta("root", maxSize)
+	rootJSON, cachedRootErr := r.fileStore.GetMeta("root", -1)
 
 	if cachedRootErr == nil {
 		signedRoot, cachedRootErr = r.validateRoot(rootJSON)
@@ -890,7 +791,8 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufclient.Cl
 		// checking for initialization of the repo).
 
 		// if remote store successfully set up, try and get root from remote
-		tmpJSON, err := remote.GetMeta("root", maxSize)
+		// We don't have any local data to determine the size of root, so try the maximum (though it is restricted at 100MB)
+		tmpJSON, err := remote.GetMeta("root", -1)
 		if err != nil {
 			// we didn't have a root in cache and were unable to load one from
 			// the server. Nothing we can do but error.
@@ -912,8 +814,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufclient.Cl
 		}
 	}
 
-	kdb := keys.NewDB()
-	r.tufRepo = tuf.NewRepo(kdb, r.CryptoService)
+	r.tufRepo = tuf.NewRepo(r.CryptoService)
 
 	if signedRoot == nil {
 		return nil, ErrRepoNotInitialized{}
@@ -927,7 +828,6 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufclient.Cl
 	return tufclient.NewClient(
 		r.tufRepo,
 		remote,
-		kdb,
 		r.fileStore,
 	), nil
 }
@@ -1020,7 +920,7 @@ func (r *NotaryRepository) DeleteTrustData() error {
 	if err := r.fileStore.RemoveAll(); err != nil {
 		return fmt.Errorf("error clearing TUF repo data: %v", err)
 	}
-	r.tufRepo = tuf.NewRepo(nil, nil)
+	r.tufRepo = tuf.NewRepo(nil)
 	// Clear certificates
 	certificates, err := r.CertStore.GetCertificatesByCN(r.gun)
 	if err != nil {
diff --git a/vendor/src/github.com/docker/notary/client/delegations.go b/vendor/src/github.com/docker/notary/client/delegations.go
new file mode 100644
index 0000000000000..c28e3d84693b8
--- /dev/null
+++ b/vendor/src/github.com/docker/notary/client/delegations.go
@@ -0,0 +1,294 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"path/filepath"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/notary"
+	"github.com/docker/notary/client/changelist"
+	"github.com/docker/notary/tuf/data"
+	"github.com/docker/notary/tuf/store"
+	"github.com/docker/notary/tuf/utils"
+)
+
+// AddDelegation creates changelist entries to add provided delegation public keys and paths.
+// This method composes AddDelegationRoleAndKeys and AddDelegationPaths (each creates one changelist if called).
+func (r *NotaryRepository) AddDelegation(name string, delegationKeys []data.PublicKey, paths []string) error {
+	if len(delegationKeys) > 0 {
+		err := r.AddDelegationRoleAndKeys(name, delegationKeys)
+		if err != nil {
+			return err
+		}
+	}
+	if len(paths) > 0 {
+		err := r.AddDelegationPaths(name, paths)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// AddDelegationRoleAndKeys creates a changelist entry to add provided delegation public keys.
+// This method is the simplest way to create a new delegation, because the delegation must have at least
+// one key upon creation to be valid since we will reject the changelist while validating the threshold.
+func (r *NotaryRepository) AddDelegationRoleAndKeys(name string, delegationKeys []data.PublicKey) error {
+
+	if !data.IsDelegation(name) {
+		return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
+	}
+
+	cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist"))
+	if err != nil {
+		return err
+	}
+	defer cl.Close()
+
+	logrus.Debugf(`Adding delegation "%s" with threshold %d, and %d keys\n`,
+		name, notary.MinThreshold, len(delegationKeys))
+
+	// Defaulting to threshold of 1, since we don't allow for larger thresholds at the moment.
+	tdJSON, err := json.Marshal(&changelist.TufDelegation{
+		NewThreshold: notary.MinThreshold,
+		AddKeys:      data.KeyList(delegationKeys),
+	})
+	if err != nil {
+		return err
+	}
+
+	template := newCreateDelegationChange(name, tdJSON)
+	return addChange(cl, template, name)
+}
+
+// AddDelegationPaths creates a changelist entry to add provided paths to an existing delegation.
+// This method cannot create a new delegation itself because the role must meet the key threshold upon creation.
+func (r *NotaryRepository) AddDelegationPaths(name string, paths []string) error {
+
+	if !data.IsDelegation(name) {
+		return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
+	}
+
+	cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist"))
+	if err != nil {
+		return err
+	}
+	defer cl.Close()
+
+	logrus.Debugf(`Adding %s paths to delegation %s\n`, paths, name)
+
+	tdJSON, err := json.Marshal(&changelist.TufDelegation{
+		AddPaths: paths,
+	})
+	if err != nil {
+		return err
+	}
+
+	template := newCreateDelegationChange(name, tdJSON)
+	return addChange(cl, template, name)
+}
+
+// RemoveDelegationKeysAndPaths creates changelist entries to remove provided delegation key IDs and paths.
+// This method composes RemoveDelegationPaths and RemoveDelegationKeys (each creates one changelist if called).
+func (r *NotaryRepository) RemoveDelegationKeysAndPaths(name string, keyIDs, paths []string) error {
+	if len(paths) > 0 {
+		err := r.RemoveDelegationPaths(name, paths)
+		if err != nil {
+			return err
+		}
+	}
+	if len(keyIDs) > 0 {
+		err := r.RemoveDelegationKeys(name, keyIDs)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// RemoveDelegationRole creates a changelist to remove all paths and keys from a role, and delete the role in its entirety.
+func (r *NotaryRepository) RemoveDelegationRole(name string) error {
+
+	if !data.IsDelegation(name) {
+		return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
+	}
+
+	cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist"))
+	if err != nil {
+		return err
+	}
+	defer cl.Close()
+
+	logrus.Debugf(`Removing delegation "%s"\n`, name)
+
+	template := newDeleteDelegationChange(name, nil)
+	return addChange(cl, template, name)
+}
+
+// RemoveDelegationPaths creates a changelist entry to remove provided paths from an existing delegation.
+func (r *NotaryRepository) RemoveDelegationPaths(name string, paths []string) error {
+
+	if !data.IsDelegation(name) {
+		return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
+	}
+
+	cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist"))
+	if err != nil {
+		return err
+	}
+	defer cl.Close()
+
+	logrus.Debugf(`Removing %s paths from delegation "%s"\n`, paths, name)
+
+	tdJSON, err := json.Marshal(&changelist.TufDelegation{
+		RemovePaths: paths,
+	})
+	if err != nil {
+		return err
+	}
+
+	template := newUpdateDelegationChange(name, tdJSON)
+	return addChange(cl, template, name)
+}
+
+// RemoveDelegationKeys creates a changelist entry to remove provided keys from an existing delegation.
+// When this changelist is applied, if the specified keys are the only keys left in the role,
+// the role itself will be deleted in its entirety.
+func (r *NotaryRepository) RemoveDelegationKeys(name string, keyIDs []string) error {
+
+	if !data.IsDelegation(name) {
+		return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
+	}
+
+	cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist"))
+	if err != nil {
+		return err
+	}
+	defer cl.Close()
+
+	logrus.Debugf(`Removing %s keys from delegation "%s"\n`, keyIDs, name)
+
+	tdJSON, err := json.Marshal(&changelist.TufDelegation{
+		RemoveKeys: keyIDs,
+	})
+	if err != nil {
+		return err
+	}
+
+	template := newUpdateDelegationChange(name, tdJSON)
+	return addChange(cl, template, name)
+}
+
+// ClearDelegationPaths creates a changelist entry to remove all paths from an existing delegation.
+func (r *NotaryRepository) ClearDelegationPaths(name string) error {
+
+	if !data.IsDelegation(name) {
+		return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
+	}
+
+	cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist"))
+	if err != nil {
+		return err
+	}
+	defer cl.Close()
+
+	logrus.Debugf(`Removing all paths from delegation "%s"\n`, name)
+
+	tdJSON, err := json.Marshal(&changelist.TufDelegation{
+		ClearAllPaths: true,
+	})
+	if err != nil {
+		return err
+	}
+
+	template := newUpdateDelegationChange(name, tdJSON)
+	return addChange(cl, template, name)
+}
+
+func newUpdateDelegationChange(name string, content []byte) *changelist.TufChange {
+	return changelist.NewTufChange(
+		changelist.ActionUpdate,
+		name,
+		changelist.TypeTargetsDelegation,
+		"", // no path for delegations
+		content,
+	)
+}
+
+func newCreateDelegationChange(name string, content []byte) *changelist.TufChange {
+	return changelist.NewTufChange(
+		changelist.ActionCreate,
+		name,
+		changelist.TypeTargetsDelegation,
+		"", // no path for delegations
+		content,
+	)
+}
+
+func newDeleteDelegationChange(name string, content []byte) *changelist.TufChange {
+	return changelist.NewTufChange(
+		changelist.ActionDelete,
+		name,
+		changelist.TypeTargetsDelegation,
+		"", // no path for delegations
+		content,
+	)
+}
+
+// GetDelegationRoles returns the keys and roles of the repository's delegations
+// Also converts key IDs to canonical key IDs to keep consistent with signing prompts
+func (r *NotaryRepository) GetDelegationRoles() ([]*data.Role, error) {
+	// Update state of the repo to latest
+	if _, err := r.Update(false); err != nil {
+		return nil, err
+	}
+
+	// All top level delegations (ex: targets/level1) are stored exclusively in targets.json
+	_, ok := r.tufRepo.Targets[data.CanonicalTargetsRole]
+	if !ok {
+		return nil, store.ErrMetaNotFound{Resource: data.CanonicalTargetsRole}
+	}
+
+	// make a copy for traversing nested delegations
+	allDelegations := []*data.Role{}
+
+	// Define a visitor function to populate the delegations list and translate their key IDs to canonical IDs
+	delegationCanonicalListVisitor := func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} {
+		// For the return list, update with a copy that includes canonicalKeyIDs
+		// These aren't validated by the validRole
+		canonicalDelegations, err := translateDelegationsToCanonicalIDs(tgt.Signed.Delegations)
+		if err != nil {
+			return err
+		}
+		allDelegations = append(allDelegations, canonicalDelegations...)
+		return nil
+	}
+	err := r.tufRepo.WalkTargets("", "", delegationCanonicalListVisitor)
+	if err != nil {
+		return nil, err
+	}
+	return allDelegations, nil
+}
+
+func translateDelegationsToCanonicalIDs(delegationInfo data.Delegations) ([]*data.Role, error) {
+	canonicalDelegations := make([]*data.Role, len(delegationInfo.Roles))
+	copy(canonicalDelegations, delegationInfo.Roles)
+	delegationKeys := delegationInfo.Keys
+	for i, delegation := range canonicalDelegations {
+		canonicalKeyIDs := []string{}
+		for _, keyID := range delegation.KeyIDs {
+			pubKey, ok := delegationKeys[keyID]
+			if !ok {
+				return nil, fmt.Errorf("Could not translate canonical key IDs for %s", delegation.Name)
+			}
+			canonicalKeyID, err := utils.CanonicalKeyID(pubKey)
+			if err != nil {
+				return nil, fmt.Errorf("Could not translate canonical key IDs for %s: %v", delegation.Name, err)
+			}
+			canonicalKeyIDs = append(canonicalKeyIDs, canonicalKeyID)
+		}
+		canonicalDelegations[i].KeyIDs = canonicalKeyIDs
+	}
+	return canonicalDelegations, nil
+}
diff --git a/vendor/src/github.com/docker/notary/client/helpers.go b/vendor/src/github.com/docker/notary/client/helpers.go
index a9fd590a9fc41..46648a11b5784 100644
--- a/vendor/src/github.com/docker/notary/client/helpers.go
+++ b/vendor/src/github.com/docker/notary/client/helpers.go
@@ -12,8 +12,8 @@ import (
 	"github.com/docker/notary/client/changelist"
 	tuf "github.com/docker/notary/tuf"
 	"github.com/docker/notary/tuf/data"
-	"github.com/docker/notary/tuf/keys"
 	"github.com/docker/notary/tuf/store"
+	"github.com/docker/notary/tuf/utils"
 )
 
 // Use this to initialize remote HTTPStores from the config settings
@@ -22,7 +22,6 @@ func getRemoteStore(baseURL, gun string, rt http.RoundTripper) (store.RemoteStor
 		baseURL+"/v2/"+gun+"/_trust/tuf/",
 		"",
 		"json",
-		"",
 		"key",
 		rt,
 	)
@@ -80,53 +79,51 @@ func changeTargetsDelegation(repo *tuf.Repo, c changelist.Change) error {
 		if err != nil {
 			return err
 		}
-		r, err := repo.GetDelegation(c.Scope())
-		if _, ok := err.(data.ErrNoSuchRole); err != nil && !ok {
-			// error that wasn't ErrNoSuchRole
-			return err
-		}
-		if err == nil {
-			// role existed, attempt to merge paths and keys
-			if err := r.AddPaths(td.AddPaths); err != nil {
-				return err
-			}
-			return repo.UpdateDelegations(r, td.AddKeys)
-		}
-		// create brand new role
-		r, err = td.ToNewRole(c.Scope())
+
+		// Try to create brand new role or update one
+		// First add the keys, then the paths.  We can only add keys and paths in this scenario
+		err = repo.UpdateDelegationKeys(c.Scope(), td.AddKeys, []string{}, td.NewThreshold)
 		if err != nil {
 			return err
 		}
-		return repo.UpdateDelegations(r, td.AddKeys)
+		return repo.UpdateDelegationPaths(c.Scope(), td.AddPaths, []string{}, false)
 	case changelist.ActionUpdate:
 		td := changelist.TufDelegation{}
 		err := json.Unmarshal(c.Content(), &td)
 		if err != nil {
 			return err
 		}
-		r, err := repo.GetDelegation(c.Scope())
+		delgRole, err := repo.GetDelegationRole(c.Scope())
 		if err != nil {
 			return err
 		}
-		// If we specify the only keys left delete the role, else just delete specified keys
-		if strings.Join(r.KeyIDs, ";") == strings.Join(td.RemoveKeys, ";") && len(td.AddKeys) == 0 {
-			r := data.Role{Name: c.Scope()}
-			return repo.DeleteDelegation(r)
+
+		// We need to translate the keys from canonical ID to TUF ID for compatibility
+		canonicalToTUFID := make(map[string]string)
+		for tufID, pubKey := range delgRole.Keys {
+			canonicalID, err := utils.CanonicalKeyID(pubKey)
+			if err != nil {
+				return err
+			}
+			canonicalToTUFID[canonicalID] = tufID
 		}
-		// if we aren't deleting and the role exists, merge
-		if err := r.AddPaths(td.AddPaths); err != nil {
-			return err
+
+		removeTUFKeyIDs := []string{}
+		for _, canonID := range td.RemoveKeys {
+			removeTUFKeyIDs = append(removeTUFKeyIDs, canonicalToTUFID[canonID])
+		}
+
+		// If we specify the only keys left delete the role, else just delete specified keys
+		if strings.Join(delgRole.ListKeyIDs(), ";") == strings.Join(removeTUFKeyIDs, ";") && len(td.AddKeys) == 0 {
+			return repo.DeleteDelegation(c.Scope())
 		}
-		if err := r.AddPathHashPrefixes(td.AddPathHashPrefixes); err != nil {
+		err = repo.UpdateDelegationKeys(c.Scope(), td.AddKeys, removeTUFKeyIDs, td.NewThreshold)
+		if err != nil {
 			return err
 		}
-		r.RemoveKeys(td.RemoveKeys)
-		r.RemovePaths(td.RemovePaths)
-		r.RemovePathHashPrefixes(td.RemovePathHashPrefixes)
-		return repo.UpdateDelegations(r, td.AddKeys)
+		return repo.UpdateDelegationPaths(c.Scope(), td.AddPaths, td.RemovePaths, td.ClearAllPaths)
 	case changelist.ActionDelete:
-		r := data.Role{Name: c.Scope()}
-		return repo.DeleteDelegation(r)
+		return repo.DeleteDelegation(c.Scope())
 	default:
 		return fmt.Errorf("unsupported action against delegations: %s", c.Action())
 	}
@@ -239,19 +236,6 @@ func getRemoteKey(url, gun, role string, rt http.RoundTripper) (data.PublicKey,
 	return pubKey, nil
 }
 
-// add a key to a KeyDB, and create a role for the key and add it.
-func addKeyForRole(kdb *keys.KeyDB, role string, key data.PublicKey) error {
-	theRole, err := data.NewRole(role, 1, []string{key.ID()}, nil, nil)
-	if err != nil {
-		return err
-	}
-	kdb.AddKey(key)
-	if err := kdb.AddRole(theRole); err != nil {
-		return err
-	}
-	return nil
-}
-
 // signs and serializes the metadata for a canonical role in a tuf repo to JSON
 func serializeCanonicalRole(tufRepo *tuf.Repo, role string) (out []byte, err error) {
 	var s *data.Signed
diff --git a/vendor/src/github.com/docker/notary/const.go b/vendor/src/github.com/docker/notary/const.go
index a1140c0dc0c13..566c7f0fbdc0b 100644
--- a/vendor/src/github.com/docker/notary/const.go
+++ b/vendor/src/github.com/docker/notary/const.go
@@ -1,7 +1,15 @@
 package notary
 
+import (
+	"time"
+)
+
 // application wide constants
 const (
+	// MaxDownloadSize is the maximum size we'll download for metadata if no limit is given
+	MaxDownloadSize int64 = 100 << 20
+	// MaxTimestampSize is the maximum size of timestamp metadata - 1MiB.
+	MaxTimestampSize int64 = 1 << 20
 	// MinRSABitSize is the minimum bit size for RSA keys allowed in notary
 	MinRSABitSize = 2048
 	// MinThreshold requires a minimum of one threshold for roles; currently we do not support a higher threshold
@@ -14,4 +22,29 @@ const (
 	Sha256HexSize = 64
 	// TrustedCertsDir is the directory, under the notary repo base directory, where trusted certs are stored
 	TrustedCertsDir = "trusted_certificates"
+	// PrivDir is the directory, under the notary repo base directory, where private keys are stored
+	PrivDir = "private"
+	// RootKeysSubdir is the subdirectory under PrivDir where root private keys are stored
+	RootKeysSubdir = "root_keys"
+	// NonRootKeysSubdir is the subdirectory under PrivDir where non-root private keys are stored
+	NonRootKeysSubdir = "tuf_keys"
+
+	// Day is a duration of one day
+	Day  = 24 * time.Hour
+	Year = 365 * Day
+
+	// NotaryRootExpiry is the duration representing the expiry time of the Root role
+	NotaryRootExpiry      = 10 * Year
+	NotaryTargetsExpiry   = 3 * Year
+	NotarySnapshotExpiry  = 3 * Year
+	NotaryTimestampExpiry = 14 * Day
 )
+
+// NotaryDefaultExpiries is the construct used to configure the default expiry times of
+// the various role files.
+var NotaryDefaultExpiries = map[string]time.Duration{
+	"root":      NotaryRootExpiry,
+	"targets":   NotaryTargetsExpiry,
+	"snapshot":  NotarySnapshotExpiry,
+	"timestamp": NotaryTimestampExpiry,
+}
diff --git a/vendor/src/github.com/docker/notary/cryptoservice/import_export.go b/vendor/src/github.com/docker/notary/cryptoservice/import_export.go
index f1d454e151f5b..c4b19944a4de1 100644
--- a/vendor/src/github.com/docker/notary/cryptoservice/import_export.go
+++ b/vendor/src/github.com/docker/notary/cryptoservice/import_export.go
@@ -11,8 +11,10 @@ import (
 	"path/filepath"
 	"strings"
 
+	"github.com/docker/notary"
 	"github.com/docker/notary/passphrase"
 	"github.com/docker/notary/trustmanager"
+	"github.com/docker/notary/tuf/data"
 )
 
 const zipMadeByUNIX = 3 << 8
@@ -31,14 +33,17 @@ var (
 	ErrNoKeysFoundForGUN = errors.New("no keys found for specified GUN")
 )
 
-// ExportRootKey exports the specified root key to an io.Writer in PEM format.
+// ExportKey exports the specified private key to an io.Writer in PEM format.
 // The key's existing encryption is preserved.
-func (cs *CryptoService) ExportRootKey(dest io.Writer, keyID string) error {
+func (cs *CryptoService) ExportKey(dest io.Writer, keyID, role string) error {
 	var (
 		pemBytes []byte
 		err      error
 	)
 
+	if role != data.CanonicalRootRole {
+		keyID = filepath.Join(cs.gun, keyID)
+	}
 	for _, ks := range cs.keyStores {
 		pemBytes, err = ks.ExportKey(keyID)
 		if err != nil {
@@ -59,9 +64,9 @@ func (cs *CryptoService) ExportRootKey(dest io.Writer, keyID string) error {
 	return nil
 }
 
-// ExportRootKeyReencrypt exports the specified root key to an io.Writer in
+// ExportKeyReencrypt exports the specified private key to an io.Writer in
 // PEM format. The key is reencrypted with a new passphrase.
-func (cs *CryptoService) ExportRootKeyReencrypt(dest io.Writer, keyID string, newPassphraseRetriever passphrase.Retriever) error {
+func (cs *CryptoService) ExportKeyReencrypt(dest io.Writer, keyID string, newPassphraseRetriever passphrase.Retriever) error {
 	privateKey, role, err := cs.GetPrivateKey(keyID)
 	if err != nil {
 		return err
@@ -103,14 +108,41 @@ func (cs *CryptoService) ImportRootKey(source io.Reader) error {
 	if err != nil {
 		return err
 	}
+	return cs.ImportRoleKey(pemBytes, data.CanonicalRootRole, nil)
+}
 
-	if err = checkRootKeyIsEncrypted(pemBytes); err != nil {
-		return err
+// ImportRoleKey imports a private key in PEM format key from a byte array
+// It prompts for the key's passphrase to verify the data and to determine
+// the key ID.
+func (cs *CryptoService) ImportRoleKey(pemBytes []byte, role string, newPassphraseRetriever passphrase.Retriever) error {
+	var alias string
+	var err error
+	if role == data.CanonicalRootRole {
+		alias = role
+		if err = checkRootKeyIsEncrypted(pemBytes); err != nil {
+			return err
+		}
+	} else {
+		// Parse the private key to get the key ID so that we can import it to the correct location
+		privKey, err := trustmanager.ParsePEMPrivateKey(pemBytes, "")
+		if err != nil {
+			privKey, _, err = trustmanager.GetPasswdDecryptBytes(newPassphraseRetriever, pemBytes, role, string(role))
+			if err != nil {
+				return err
+			}
+		}
+		// Since we're importing a non-root role, we need to pass the path as an alias
+		alias = filepath.Join(notary.NonRootKeysSubdir, cs.gun, privKey.ID())
+		// We also need to ensure that the role is properly set in the PEM headers
+		pemBytes, err = trustmanager.KeyToPEM(privKey, role)
+		if err != nil {
+			return err
+		}
 	}
 
 	for _, ks := range cs.keyStores {
 		// don't redeclare err, we want the value carried out of the loop
-		if err = ks.ImportKey(pemBytes, "root"); err == nil {
+		if err = ks.ImportKey(pemBytes, alias); err == nil {
 			return nil //bail on the first keystore we import to
 		}
 	}
diff --git a/vendor/src/github.com/docker/notary/docker-compose.yml b/vendor/src/github.com/docker/notary/docker-compose.yml
index 17b5798fa2072..4f8705f384b4b 100644
--- a/vendor/src/github.com/docker/notary/docker-compose.yml
+++ b/vendor/src/github.com/docker/notary/docker-compose.yml
@@ -1,27 +1,34 @@
-notaryserver:
+server:
   build: .
   dockerfile: server.Dockerfile
   links:
-   - notarymysql
-   - notarysigner
-  ports:
-   - "8080"
-   - "4443:4443"
+    - mysql
+    - signer
+    - signer:notarysigner
   environment:
-   - SERVICE_NAME=notary
-  command: -config=fixtures/server-config.json
-notarysigner:
-  volumes:
-   - /dev/bus/usb/003/010:/dev/bus/usb/002/010
-   - /var/run/pcscd/pcscd.comm:/var/run/pcscd/pcscd.comm
+    - SERVICE_NAME=notary_server
+  ports:
+    - "8080"
+    - "4443:4443"
+  entrypoint: /bin/bash
+  command: -c "./migrations/migrate.sh && notary-server -config=fixtures/server-config.json"
+signer:
   build: .
   dockerfile: signer.Dockerfile
   links:
-   - notarymysql
-  command: -config=fixtures/signer-config.json
-notarymysql:
+    - mysql
+  environment:
+    - SERVICE_NAME=notary_signer
+  entrypoint: /bin/bash
+  command: -c "./migrations/migrate.sh && notary-signer -config=fixtures/signer-config.json"
+mysql:
   volumes:
-    - notarymysql:/var/lib/mysql
-  build: ./notarymysql/
+    - ./notarymysql/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
+    - notary_data:/var/lib/mysql
+  image: mariadb:10.1.10
   ports:
     - "3306:3306"
+  environment:
+    - TERM=dumb
+    - MYSQL_ALLOW_EMPTY_PASSWORD="true"
+  command: mysqld --innodb_file_per_table
diff --git a/vendor/src/github.com/docker/notary/notarymysql/LICENSE b/vendor/src/github.com/docker/notary/notarymysql/LICENSE
deleted file mode 100644
index c8476ac066e01..0000000000000
--- a/vendor/src/github.com/docker/notary/notarymysql/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2014 Sameer Naik
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/vendor/src/github.com/docker/notary/server.Dockerfile b/vendor/src/github.com/docker/notary/server.Dockerfile
index a2273bc52322d..693064d7b5d33 100644
--- a/vendor/src/github.com/docker/notary/server.Dockerfile
+++ b/vendor/src/github.com/docker/notary/server.Dockerfile
@@ -1,4 +1,5 @@
-FROM golang:1.5.1
+FROM golang:1.5.3
+MAINTAINER David Lawrence "david.lawrence@docker.com"
 
 RUN apt-get update && apt-get install -y \
     libltdl-dev \
@@ -7,13 +8,20 @@ RUN apt-get update && apt-get install -y \
 
 EXPOSE 4443
 
+# Install DB migration tool
+RUN go get github.com/mattes/migrate
+
 ENV NOTARYPKG github.com/docker/notary
 ENV GOPATH /go/src/${NOTARYPKG}/Godeps/_workspace:$GOPATH
 
+
+
+# Copy the local repo to the expected go path
 COPY . /go/src/github.com/docker/notary
 
 WORKDIR /go/src/${NOTARYPKG}
 
+# Install notary-server
 RUN go install \
     -tags pkcs11 \
     -ldflags "-w -X ${NOTARYPKG}/version.GitCommit=`git rev-parse --short HEAD` -X ${NOTARYPKG}/version.NotaryVersion=`cat NOTARY_VERSION`" \
diff --git a/vendor/src/github.com/docker/notary/signer.Dockerfile b/vendor/src/github.com/docker/notary/signer.Dockerfile
index 3ff8523448eef..837273bac568b 100644
--- a/vendor/src/github.com/docker/notary/signer.Dockerfile
+++ b/vendor/src/github.com/docker/notary/signer.Dockerfile
@@ -1,29 +1,20 @@
-FROM dockersecurity/golang-softhsm2
-MAINTAINER Diogo Monica "diogo@docker.com"
+FROM golang:1.5.3
+MAINTAINER David Lawrence "david.lawrence@docker.com"
 
-# CHANGE-ME: Default values for SoftHSM2 PIN and SOPIN, used to initialize the first token
-ENV NOTARY_SIGNER_PIN="1234"
-ENV SOPIN="1234"
-ENV LIBDIR="/usr/local/lib/softhsm/"
-ENV NOTARY_SIGNER_DEFAULT_ALIAS="timestamp_1"
-ENV NOTARY_SIGNER_TIMESTAMP_1="testpassword"
-
-# Install openSC and dependencies
 RUN apt-get update && apt-get install -y \
     libltdl-dev \
-    libpcsclite-dev \
-    opensc \
-    usbutils \
     --no-install-recommends \
     && rm -rf /var/lib/apt/lists/*
 
-# Initialize the SoftHSM2 token on slod 0, using PIN and SOPIN varaibles
-RUN softhsm2-util --init-token --slot 0 --label "test_token" --pin $NOTARY_SIGNER_PIN --so-pin $SOPIN
+EXPOSE 4444
+
+# Install DB migration tool
+RUN go get github.com/mattes/migrate
 
 ENV NOTARYPKG github.com/docker/notary
 ENV GOPATH /go/src/${NOTARYPKG}/Godeps/_workspace:$GOPATH
-
-EXPOSE 4444
+ENV NOTARY_SIGNER_DEFAULT_ALIAS="timestamp_1"
+ENV NOTARY_SIGNER_TIMESTAMP_1="testpassword"
 
 # Copy the local repo to the expected go path
 COPY . /go/src/github.com/docker/notary
@@ -36,6 +27,5 @@ RUN go install \
     -ldflags "-w -X ${NOTARYPKG}/version.GitCommit=`git rev-parse --short HEAD` -X ${NOTARYPKG}/version.NotaryVersion=`cat NOTARY_VERSION`" \
     ${NOTARYPKG}/cmd/notary-signer
 
-
 ENTRYPOINT [ "notary-signer" ]
 CMD [ "-config=fixtures/signer-config-local.json" ]
diff --git a/vendor/src/github.com/docker/notary/trustmanager/keyfilestore.go b/vendor/src/github.com/docker/notary/trustmanager/keyfilestore.go
index 0f9d821327522..0a6b8ff4f8986 100644
--- a/vendor/src/github.com/docker/notary/trustmanager/keyfilestore.go
+++ b/vendor/src/github.com/docker/notary/trustmanager/keyfilestore.go
@@ -8,16 +8,11 @@ import (
 	"sync"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/notary"
 	"github.com/docker/notary/passphrase"
 	"github.com/docker/notary/tuf/data"
 )
 
-const (
-	rootKeysSubdir    = "root_keys"
-	nonRootKeysSubdir = "tuf_keys"
-	privDir           = "private"
-)
-
 // KeyFileStore persists and manages private keys on disk
 type KeyFileStore struct {
 	sync.Mutex
@@ -37,7 +32,7 @@ type KeyMemoryStore struct {
 // NewKeyFileStore returns a new KeyFileStore creating a private directory to
 // hold the keys.
 func NewKeyFileStore(baseDir string, passphraseRetriever passphrase.Retriever) (*KeyFileStore, error) {
-	baseDir = filepath.Join(baseDir, privDir)
+	baseDir = filepath.Join(baseDir, notary.PrivDir)
 	fileStore, err := NewPrivateSimpleFileStore(baseDir, keyExtension)
 	if err != nil {
 		return nil, err
@@ -242,10 +237,10 @@ func listKeys(s LimitedFileStore) map[string]string {
 	for _, f := range s.ListFiles() {
 		// Remove the prefix of the directory from the filename
 		var keyIDFull string
-		if strings.HasPrefix(f, rootKeysSubdir+"/") {
-			keyIDFull = strings.TrimPrefix(f, rootKeysSubdir+"/")
+		if strings.HasPrefix(f, notary.RootKeysSubdir+"/") {
+			keyIDFull = strings.TrimPrefix(f, notary.RootKeysSubdir+"/")
 		} else {
-			keyIDFull = strings.TrimPrefix(f, nonRootKeysSubdir+"/")
+			keyIDFull = strings.TrimPrefix(f, notary.NonRootKeysSubdir+"/")
 		}
 
 		keyIDFull = strings.TrimSpace(keyIDFull)
@@ -302,9 +297,9 @@ func removeKey(s LimitedFileStore, cachedKeys map[string]*cachedKey, name string
 // Assumes 2 subdirectories, 1 containing root keys and 1 containing tuf keys
 func getSubdir(alias string) string {
 	if alias == "root" {
-		return rootKeysSubdir
+		return notary.RootKeysSubdir
 	}
-	return nonRootKeysSubdir
+	return notary.NonRootKeysSubdir
 }
 
 // Given a key ID, gets the bytes and alias belonging to that key if the key
@@ -327,7 +322,7 @@ func getRawKey(s LimitedFileStore, name string) ([]byte, string, error) {
 	return keyBytes, role, nil
 }
 
-// GetPasswdDecryptBytes gets the password to decript the given pem bytes.
+// GetPasswdDecryptBytes gets the password to decrypt the given pem bytes.
 // Returns the password and private key
 func GetPasswdDecryptBytes(passphraseRetriever passphrase.Retriever, pemBytes []byte, name, alias string) (data.PrivateKey, string, error) {
 	var (
diff --git a/vendor/src/github.com/docker/notary/trustmanager/x509utils.go b/vendor/src/github.com/docker/notary/trustmanager/x509utils.go
index f39ca8eb22bc4..601b15b8a9b28 100644
--- a/vendor/src/github.com/docker/notary/trustmanager/x509utils.go
+++ b/vendor/src/github.com/docker/notary/trustmanager/x509utils.go
@@ -470,12 +470,17 @@ func KeyToPEM(privKey data.PrivateKey, role string) ([]byte, error) {
 		return nil, err
 	}
 
-	block := &pem.Block{
-		Type: bt,
-		Headers: map[string]string{
+	headers := map[string]string{}
+	if role != "" {
+		headers = map[string]string{
 			"role": role,
-		},
-		Bytes: privKey.Private(),
+		}
+	}
+
+	block := &pem.Block{
+		Type:    bt,
+		Headers: headers,
+		Bytes:   privKey.Private(),
 	}
 
 	return pem.EncodeToMemory(block), nil
@@ -509,6 +514,19 @@ func EncryptPrivateKey(key data.PrivateKey, role, passphrase string) ([]byte, er
 	return pem.EncodeToMemory(encryptedPEMBlock), nil
 }
 
+// ReadRoleFromPEM returns the value from the role PEM header, if it exists
+func ReadRoleFromPEM(pemBytes []byte) string {
+	pemBlock, _ := pem.Decode(pemBytes)
+	if pemBlock.Headers == nil {
+		return ""
+	}
+	role, ok := pemBlock.Headers["role"]
+	if !ok {
+		return ""
+	}
+	return role
+}
+
 // CertToKey transforms a single input certificate into its corresponding
 // PublicKey
 func CertToKey(cert *x509.Certificate) data.PublicKey {
diff --git a/vendor/src/github.com/docker/notary/trustmanager/yubikey/yubikeystore.go b/vendor/src/github.com/docker/notary/trustmanager/yubikey/yubikeystore.go
index a10048367ace8..3e292a2e9d1eb 100644
--- a/vendor/src/github.com/docker/notary/trustmanager/yubikey/yubikeystore.go
+++ b/vendor/src/github.com/docker/notary/trustmanager/yubikey/yubikeystore.go
@@ -765,15 +765,15 @@ func (s *YubiKeyStore) ExportKey(keyID string) ([]byte, error) {
 // ImportKey imports a root key into a Yubikey
 func (s *YubiKeyStore) ImportKey(pemBytes []byte, keyPath string) error {
 	logrus.Debugf("Attempting to import: %s key inside of YubiKeyStore", keyPath)
+	if keyPath != data.CanonicalRootRole {
+		return fmt.Errorf("yubikey only supports storing root keys")
+	}
 	privKey, _, err := trustmanager.GetPasswdDecryptBytes(
 		s.passRetriever, pemBytes, "", "imported root")
 	if err != nil {
 		logrus.Debugf("Failed to get and retrieve a key from: %s", keyPath)
 		return err
 	}
-	if keyPath != data.CanonicalRootRole {
-		return fmt.Errorf("yubikey only supports storing root keys")
-	}
 	_, err = s.addKey(privKey.ID(), "root", privKey)
 	return err
 }
diff --git a/vendor/src/github.com/docker/notary/tuf/README.md b/vendor/src/github.com/docker/notary/tuf/README.md
index ac8d6d11328b6..00a342e81eaf4 100644
--- a/vendor/src/github.com/docker/notary/tuf/README.md
+++ b/vendor/src/github.com/docker/notary/tuf/README.md
@@ -29,7 +29,7 @@ however in attempting to add delegations I found I was making such
 significant changes that I could not maintain backwards compatibility
 without the code becoming overly convoluted.
 
-Some features such as pluggable verifiers have alreayd been merged upstream to flynn/go-tuf
+Some features such as pluggable verifiers have already been merged upstream to flynn/go-tuf
 and we are in discussion with [titanous](https://github.com/titanous) about working to merge the 2 implementations.
 
 This implementation retains the same 3 Clause BSD license present on 
diff --git a/vendor/src/github.com/docker/notary/tuf/client/client.go b/vendor/src/github.com/docker/notary/tuf/client/client.go
index 0eaa8c87e7b39..51aededc1080e 100644
--- a/vendor/src/github.com/docker/notary/tuf/client/client.go
+++ b/vendor/src/github.com/docker/notary/tuf/client/client.go
@@ -3,38 +3,31 @@ package client
 import (
 	"bytes"
 	"crypto/sha256"
-	"encoding/hex"
 	"encoding/json"
 	"fmt"
-	"io"
 	"path"
-	"strings"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/notary"
 	tuf "github.com/docker/notary/tuf"
 	"github.com/docker/notary/tuf/data"
-	"github.com/docker/notary/tuf/keys"
 	"github.com/docker/notary/tuf/signed"
 	"github.com/docker/notary/tuf/store"
 	"github.com/docker/notary/tuf/utils"
 )
 
-const maxSize int64 = 5 << 20
-
 // Client is a usability wrapper around a raw TUF repo
 type Client struct {
 	local  *tuf.Repo
 	remote store.RemoteStore
-	keysDB *keys.KeyDB
 	cache  store.MetadataStore
 }
 
-// NewClient initialized a Client with the given repo, remote source of content, key database, and cache
-func NewClient(local *tuf.Repo, remote store.RemoteStore, keysDB *keys.KeyDB, cache store.MetadataStore) *Client {
+// NewClient initialized a Client with the given repo, remote source of content, and cache
+func NewClient(local *tuf.Repo, remote store.RemoteStore, cache store.MetadataStore) *Client {
 	return &Client{
 		local:  local,
 		remote: remote,
-		keysDB: keysDB,
 		cache:  cache,
 	}
 }
@@ -131,11 +124,15 @@ func (c Client) checkRoot() error {
 func (c *Client) downloadRoot() error {
 	logrus.Debug("Downloading Root...")
 	role := data.CanonicalRootRole
-	size := maxSize
+	// We can't read an exact size for the root metadata without risking getting stuck in the TUF update cycle
+	// since it's possible that downloading timestamp/snapshot metadata may fail due to a signature mismatch
+	var size int64 = -1
 	var expectedSha256 []byte
 	if c.local.Snapshot != nil {
-		size = c.local.Snapshot.Signed.Meta[role].Length
-		expectedSha256 = c.local.Snapshot.Signed.Meta[role].Hashes["sha256"]
+		if prevRootMeta, ok := c.local.Snapshot.Signed.Meta[role]; ok {
+			size = prevRootMeta.Length
+			expectedSha256 = prevRootMeta.Hashes["sha256"]
+		}
 	}
 
 	// if we're bootstrapping we may not have a cached root, an
@@ -178,6 +175,7 @@ func (c *Client) downloadRoot() error {
 	var s *data.Signed
 	var raw []byte
 	if download {
+		// use consistent download if we have the checksum.
 		raw, s, err = c.downloadSigned(role, size, expectedSha256)
 		if err != nil {
 			return err
@@ -201,34 +199,45 @@ func (c *Client) downloadRoot() error {
 
 func (c Client) verifyRoot(role string, s *data.Signed, minVersion int) error {
 	// this will confirm that the root has been signed by the old root role
-	// as c.keysDB contains the root keys we bootstrapped with.
+	// with the root keys we bootstrapped with.
 	// Still need to determine if there has been a root key update and
 	// confirm signature with new root key
 	logrus.Debug("verifying root with existing keys")
-	err := signed.Verify(s, role, minVersion, c.keysDB)
+	rootRole, err := c.local.GetBaseRole(role)
 	if err != nil {
+		logrus.Debug("no previous root role loaded")
+		return err
+	}
+	// Verify using the rootRole loaded from the known root.json
+	if err = signed.Verify(s, rootRole, minVersion); err != nil {
 		logrus.Debug("root did not verify with existing keys")
 		return err
 	}
 
-	// This will cause keyDB to get updated, overwriting any keyIDs associated
-	// with the roles in root.json
 	logrus.Debug("updating known root roles and keys")
 	root, err := data.RootFromSigned(s)
 	if err != nil {
 		logrus.Error(err.Error())
 		return err
 	}
+	// replace the existing root.json with the new one (just in memory, we
+	// have another validation step before we fully accept the new root)
 	err = c.local.SetRoot(root)
 	if err != nil {
 		logrus.Error(err.Error())
 		return err
 	}
-	// verify again now that the old keys have been replaced with the new keys.
+	// Verify the new root again having loaded the rootRole out of this new
+	// file (verifies self-referential integrity)
 	// TODO(endophage): be more intelligent and only re-verify if we detect
 	//                  there has been a change in root keys
 	logrus.Debug("verifying root with updated keys")
-	err = signed.Verify(s, role, minVersion, c.keysDB)
+	rootRole, err = c.local.GetBaseRole(role)
+	if err != nil {
+		logrus.Debug("root role with new keys not loaded")
+		return err
+	}
+	err = signed.Verify(s, rootRole, minVersion)
 	if err != nil {
 		logrus.Debug("root did not verify with new keys")
 		return err
@@ -248,11 +257,11 @@ func (c *Client) downloadTimestamp() error {
 	// we're interacting with the repo. This will result in the
 	// version being 0
 	var (
-		saveToCache bool
-		old         *data.Signed
-		version     = 0
+		old     *data.Signed
+		ts      *data.SignedTimestamp
+		version = 0
 	)
-	cachedTS, err := c.cache.GetMeta(role, maxSize)
+	cachedTS, err := c.cache.GetMeta(role, notary.MaxTimestampSize)
 	if err == nil {
 		cached := &data.Signed{}
 		err := json.Unmarshal(cachedTS, cached)
@@ -266,49 +275,56 @@ func (c *Client) downloadTimestamp() error {
 	}
 	// unlike root, targets and snapshot, always try and download timestamps
 	// from remote, only using the cache one if we couldn't reach remote.
-	raw, s, err := c.downloadSigned(role, maxSize, nil)
-	if err != nil || len(raw) == 0 {
-		if old == nil {
-			if err == nil {
-				// couldn't retrieve data from server and don't have valid
-				// data in cache.
-				return store.ErrMetaNotFound{Resource: data.CanonicalTimestampRole}
-			}
-			return err
+	raw, s, err := c.downloadSigned(role, notary.MaxTimestampSize, nil)
+	if err == nil {
+		ts, err = c.verifyTimestamp(s, version)
+		if err == nil {
+			logrus.Debug("successfully verified downloaded timestamp")
+			c.cache.SetMeta(role, raw)
+			c.local.SetTimestamp(ts)
+			return nil
 		}
-		logrus.Debug(err.Error())
-		logrus.Warn("Error while downloading remote metadata, using cached timestamp - this might not be the latest version available remotely")
-		s = old
-	} else {
-		saveToCache = true
 	}
-	err = signed.Verify(s, role, version, c.keysDB)
-	if err != nil {
+	if old == nil {
+		// couldn't retrieve valid data from server and don't have unmarshallable data in cache.
+		logrus.Debug("no cached timestamp available")
 		return err
 	}
-	logrus.Debug("successfully verified timestamp")
-	if saveToCache {
-		c.cache.SetMeta(role, raw)
-	}
-	ts, err := data.TimestampFromSigned(s)
+	logrus.Debug(err.Error())
+	logrus.Warn("Error while downloading remote metadata, using cached timestamp - this might not be the latest version available remotely")
+	ts, err = c.verifyTimestamp(old, version)
 	if err != nil {
 		return err
 	}
+	logrus.Debug("successfully verified cached timestamp")
 	c.local.SetTimestamp(ts)
 	return nil
 }
 
+// verifies that a timestamp is valid, and returned the SignedTimestamp object to add to the tuf repo
+func (c *Client) verifyTimestamp(s *data.Signed, minVersion int) (*data.SignedTimestamp, error) {
+	timestampRole, err := c.local.GetBaseRole(data.CanonicalTimestampRole)
+	if err != nil {
+		logrus.Debug("no timestamp role loaded")
+		return nil, err
+	}
+	if err := signed.Verify(s, timestampRole, minVersion); err != nil {
+		return nil, err
+	}
+	return data.TimestampFromSigned(s)
+}
+
 // downloadSnapshot is responsible for downloading the snapshot.json
 func (c *Client) downloadSnapshot() error {
 	logrus.Debug("Downloading Snapshot...")
 	role := data.CanonicalSnapshotRole
 	if c.local.Timestamp == nil {
-		return ErrMissingMeta{role: "snapshot"}
+		return tuf.ErrNotLoaded{Role: data.CanonicalTimestampRole}
 	}
 	size := c.local.Timestamp.Signed.Meta[role].Length
 	expectedSha256, ok := c.local.Timestamp.Signed.Meta[role].Hashes["sha256"]
 	if !ok {
-		return ErrMissingMeta{role: "snapshot"}
+		return data.ErrMissingMeta{Role: "snapshot"}
 	}
 
 	var download bool
@@ -350,7 +366,12 @@ func (c *Client) downloadSnapshot() error {
 		s = old
 	}
 
-	err = signed.Verify(s, role, version, c.keysDB)
+	snapshotRole, err := c.local.GetBaseRole(role)
+	if err != nil {
+		logrus.Debug("no snapshot role loaded")
+		return err
+	}
+	err = signed.Verify(s, snapshotRole, version)
 	if err != nil {
 		return err
 	}
@@ -382,18 +403,14 @@ func (c *Client) downloadTargets(role string) error {
 			return err
 		}
 		if c.local.Snapshot == nil {
-			return ErrMissingMeta{role: role}
+			return tuf.ErrNotLoaded{Role: data.CanonicalSnapshotRole}
 		}
 		snap := c.local.Snapshot.Signed
 		root := c.local.Root.Signed
-		r := c.keysDB.GetRole(role)
-		if r == nil {
-			return fmt.Errorf("Invalid role: %s", role)
-		}
-		keyIDs := r.KeyIDs
-		s, err := c.getTargetsFile(role, keyIDs, snap.Meta, root.ConsistentSnapshot, r.Threshold)
+
+		s, err := c.getTargetsFile(role, snap.Meta, root.ConsistentSnapshot)
 		if err != nil {
-			if _, ok := err.(ErrMissingMeta); ok && role != data.CanonicalTargetsRole {
+			if _, ok := err.(data.ErrMissingMeta); ok && role != data.CanonicalTargetsRole {
 				// if the role meta hasn't been published,
 				// that's ok, continue
 				continue
@@ -401,7 +418,7 @@ func (c *Client) downloadTargets(role string) error {
 			logrus.Error("Error getting targets file:", err)
 			return err
 		}
-		t, err := data.TargetsFromSigned(s)
+		t, err := data.TargetsFromSigned(s, role)
 		if err != nil {
 			return err
 		}
@@ -412,14 +429,19 @@ func (c *Client) downloadTargets(role string) error {
 
 		// push delegated roles contained in the targets file onto the stack
 		for _, r := range t.Signed.Delegations.Roles {
-			stack.Push(r.Name)
+			if path.Dir(r.Name) == role {
+				// only load children that are direct 1st generation descendants
+				// of the role we've just downloaded
+				stack.Push(r.Name)
+			}
 		}
 	}
 	return nil
 }
 
 func (c *Client) downloadSigned(role string, size int64, expectedSha256 []byte) ([]byte, *data.Signed, error) {
-	raw, err := c.remote.GetMeta(role, size)
+	rolePath := utils.ConsistentName(role, expectedSha256)
+	raw, err := c.remote.GetMeta(rolePath, size)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -437,15 +459,15 @@ func (c *Client) downloadSigned(role string, size int64, expectedSha256 []byte)
 	return raw, s, nil
 }
 
-func (c Client) getTargetsFile(role string, keyIDs []string, snapshotMeta data.Files, consistent bool, threshold int) (*data.Signed, error) {
+func (c Client) getTargetsFile(role string, snapshotMeta data.Files, consistent bool) (*data.Signed, error) {
 	// require role exists in snapshots
 	roleMeta, ok := snapshotMeta[role]
 	if !ok {
-		return nil, ErrMissingMeta{role: role}
+		return nil, data.ErrMissingMeta{Role: role}
 	}
 	expectedSha256, ok := snapshotMeta[role].Hashes["sha256"]
 	if !ok {
-		return nil, ErrMissingMeta{role: role}
+		return nil, data.ErrMissingMeta{Role: role}
 	}
 
 	// try to get meta file from content addressed cache
@@ -464,7 +486,7 @@ func (c Client) getTargetsFile(role string, keyIDs []string, snapshotMeta data.F
 		}
 		err := json.Unmarshal(raw, old)
 		if err == nil {
-			targ, err := data.TargetsFromSigned(old)
+			targ, err := data.TargetsFromSigned(old, role)
 			if err == nil {
 				version = targ.Signed.Version
 			} else {
@@ -478,21 +500,30 @@ func (c Client) getTargetsFile(role string, keyIDs []string, snapshotMeta data.F
 	size := snapshotMeta[role].Length
 	var s *data.Signed
 	if download {
-		rolePath, err := c.RoleTargetsPath(role, hex.EncodeToString(expectedSha256), consistent)
+		raw, s, err = c.downloadSigned(role, size, expectedSha256)
 		if err != nil {
 			return nil, err
 		}
-		raw, s, err = c.downloadSigned(rolePath, size, expectedSha256)
+	} else {
+		logrus.Debug("using cached ", role)
+		s = old
+	}
+	var targetOrDelgRole data.BaseRole
+	if data.IsDelegation(role) {
+		delgRole, err := c.local.GetDelegationRole(role)
 		if err != nil {
+			logrus.Debugf("no %s delegation role loaded", role)
 			return nil, err
 		}
+		targetOrDelgRole = delgRole.BaseRole
 	} else {
-		logrus.Debug("using cached ", role)
-		s = old
+		targetOrDelgRole, err = c.local.GetBaseRole(role)
+		if err != nil {
+			logrus.Debugf("no %s role loaded", role)
+			return nil, err
+		}
 	}
-
-	err = signed.Verify(s, role, version, c.keysDB)
-	if err != nil {
+	if err = signed.Verify(s, targetOrDelgRole, version); err != nil {
 		return nil, err
 	}
 	logrus.Debugf("successfully verified %s", role)
@@ -505,73 +536,3 @@ func (c Client) getTargetsFile(role string, keyIDs []string, snapshotMeta data.F
 	}
 	return s, nil
 }
-
-// RoleTargetsPath generates the appropriate HTTP URL for the targets file,
-// based on whether the repo is marked as consistent.
-func (c Client) RoleTargetsPath(role string, hashSha256 string, consistent bool) (string, error) {
-	if consistent {
-		// Use path instead of filepath since we refer to the TUF role directly instead of its target files
-		dir := path.Dir(role)
-		if strings.Contains(role, "/") {
-			lastSlashIdx := strings.LastIndex(role, "/")
-			role = role[lastSlashIdx+1:]
-		}
-		role = path.Join(
-			dir,
-			fmt.Sprintf("%s.%s.json", hashSha256, role),
-		)
-	}
-	return role, nil
-}
-
-// TargetMeta ensures the repo is up to date. It assumes downloadTargets
-// has already downloaded all delegated roles
-func (c Client) TargetMeta(role, path string, excludeRoles ...string) (*data.FileMeta, string) {
-	excl := make(map[string]bool)
-	for _, r := range excludeRoles {
-		excl[r] = true
-	}
-
-	pathDigest := sha256.Sum256([]byte(path))
-	pathHex := hex.EncodeToString(pathDigest[:])
-
-	// FIFO list of targets delegations to inspect for target
-	roles := []string{role}
-	var (
-		meta *data.FileMeta
-		curr string
-	)
-	for len(roles) > 0 {
-		// have to do these lines here because of order of execution in for statement
-		curr = roles[0]
-		roles = roles[1:]
-
-		meta = c.local.TargetMeta(curr, path)
-		if meta != nil {
-			// we found the target!
-			return meta, curr
-		}
-		delegations := c.local.TargetDelegations(curr, path, pathHex)
-		for _, d := range delegations {
-			if !excl[d.Name] {
-				roles = append(roles, d.Name)
-			}
-		}
-	}
-	return meta, ""
-}
-
-// DownloadTarget downloads the target to dst from the remote
-func (c Client) DownloadTarget(dst io.Writer, path string, meta *data.FileMeta) error {
-	reader, err := c.remote.GetTarget(path)
-	if err != nil {
-		return err
-	}
-	defer reader.Close()
-	r := io.TeeReader(
-		io.LimitReader(reader, meta.Length),
-		dst,
-	)
-	err = utils.ValidateTarget(r, meta)
-	return err
-}
diff --git a/vendor/src/github.com/docker/notary/tuf/client/errors.go b/vendor/src/github.com/docker/notary/tuf/client/errors.go
index 037b3df00bbc4..ad0555127e4ab 100644
--- a/vendor/src/github.com/docker/notary/tuf/client/errors.go
+++ b/vendor/src/github.com/docker/notary/tuf/client/errors.go
@@ -13,15 +13,6 @@ func (e ErrChecksumMismatch) Error() string {
 	return fmt.Sprintf("tuf: checksum for %s did not match", e.role)
 }
 
-// ErrMissingMeta - couldn't find the FileMeta object for a role or target
-type ErrMissingMeta struct {
-	role string
-}
-
-func (e ErrMissingMeta) Error() string {
-	return fmt.Sprintf("tuf: sha256 checksum required for %s", e.role)
-}
-
 // ErrCorruptedCache - local data is incorrect
 type ErrCorruptedCache struct {
 	file string
diff --git a/vendor/src/github.com/docker/notary/tuf/data/errors.go b/vendor/src/github.com/docker/notary/tuf/data/errors.go
new file mode 100644
index 0000000000000..7ff5814c8e07f
--- /dev/null
+++ b/vendor/src/github.com/docker/notary/tuf/data/errors.go
@@ -0,0 +1,22 @@
+package data
+
+import "fmt"
+
+// ErrInvalidMetadata is the error to be returned when metadata is invalid
+type ErrInvalidMetadata struct {
+	role string
+	msg  string
+}
+
+func (e ErrInvalidMetadata) Error() string {
+	return fmt.Sprintf("%s type metadata invalid: %s", e.role, e.msg)
+}
+
+// ErrMissingMeta - couldn't find the FileMeta object for a role or target
+type ErrMissingMeta struct {
+	Role string
+}
+
+func (e ErrMissingMeta) Error() string {
+	return fmt.Sprintf("tuf: sha256 checksum required for %s", e.Role)
+}
diff --git a/vendor/src/github.com/docker/notary/tuf/data/keys.go b/vendor/src/github.com/docker/notary/tuf/data/keys.go
index 9f94d5552fea3..25df598c16068 100644
--- a/vendor/src/github.com/docker/notary/tuf/data/keys.go
+++ b/vendor/src/github.com/docker/notary/tuf/data/keys.go
@@ -46,7 +46,7 @@ type Keys map[string]PublicKey
 
 // UnmarshalJSON implements the json.Unmarshaller interface
 func (ks *Keys) UnmarshalJSON(data []byte) error {
-	parsed := make(map[string]tufKey)
+	parsed := make(map[string]TUFKey)
 	err := json.Unmarshal(data, &parsed)
 	if err != nil {
 		return err
@@ -64,7 +64,7 @@ type KeyList []PublicKey
 
 // UnmarshalJSON implements the json.Unmarshaller interface
 func (ks *KeyList) UnmarshalJSON(data []byte) error {
-	parsed := make([]tufKey, 0, 1)
+	parsed := make([]TUFKey, 0, 1)
 	err := json.Unmarshal(data, &parsed)
 	if err != nil {
 		return err
@@ -86,64 +86,64 @@ func (ks KeyList) IDs() []string {
 	return keyIDs
 }
 
-func typedPublicKey(tk tufKey) PublicKey {
+func typedPublicKey(tk TUFKey) PublicKey {
 	switch tk.Algorithm() {
 	case ECDSAKey:
-		return &ECDSAPublicKey{tufKey: tk}
+		return &ECDSAPublicKey{TUFKey: tk}
 	case ECDSAx509Key:
-		return &ECDSAx509PublicKey{tufKey: tk}
+		return &ECDSAx509PublicKey{TUFKey: tk}
 	case RSAKey:
-		return &RSAPublicKey{tufKey: tk}
+		return &RSAPublicKey{TUFKey: tk}
 	case RSAx509Key:
-		return &RSAx509PublicKey{tufKey: tk}
+		return &RSAx509PublicKey{TUFKey: tk}
 	case ED25519Key:
-		return &ED25519PublicKey{tufKey: tk}
+		return &ED25519PublicKey{TUFKey: tk}
 	}
-	return &UnknownPublicKey{tufKey: tk}
+	return &UnknownPublicKey{TUFKey: tk}
 }
 
-func typedPrivateKey(tk tufKey) (PrivateKey, error) {
+func typedPrivateKey(tk TUFKey) (PrivateKey, error) {
 	private := tk.Value.Private
 	tk.Value.Private = nil
 	switch tk.Algorithm() {
 	case ECDSAKey:
 		return NewECDSAPrivateKey(
 			&ECDSAPublicKey{
-				tufKey: tk,
+				TUFKey: tk,
 			},
 			private,
 		)
 	case ECDSAx509Key:
 		return NewECDSAPrivateKey(
 			&ECDSAx509PublicKey{
-				tufKey: tk,
+				TUFKey: tk,
 			},
 			private,
 		)
 	case RSAKey:
 		return NewRSAPrivateKey(
 			&RSAPublicKey{
-				tufKey: tk,
+				TUFKey: tk,
 			},
 			private,
 		)
 	case RSAx509Key:
 		return NewRSAPrivateKey(
 			&RSAx509PublicKey{
-				tufKey: tk,
+				TUFKey: tk,
 			},
 			private,
 		)
 	case ED25519Key:
 		return NewED25519PrivateKey(
 			ED25519PublicKey{
-				tufKey: tk,
+				TUFKey: tk,
 			},
 			private,
 		)
 	}
 	return &UnknownPrivateKey{
-		tufKey:     tk,
+		TUFKey:     tk,
 		privateKey: privateKey{private: private},
 	}, nil
 }
@@ -151,7 +151,7 @@ func typedPrivateKey(tk tufKey) (PrivateKey, error) {
 // NewPublicKey creates a new, correctly typed PublicKey, using the
 // UnknownPublicKey catchall for unsupported ciphers
 func NewPublicKey(alg string, public []byte) PublicKey {
-	tk := tufKey{
+	tk := TUFKey{
 		Type: alg,
 		Value: KeyPair{
 			Public: public,
@@ -163,7 +163,7 @@ func NewPublicKey(alg string, public []byte) PublicKey {
 // NewPrivateKey creates a new, correctly typed PrivateKey, using the
 // UnknownPrivateKey catchall for unsupported ciphers
 func NewPrivateKey(pubKey PublicKey, private []byte) (PrivateKey, error) {
-	tk := tufKey{
+	tk := TUFKey{
 		Type: pubKey.Algorithm(),
 		Value: KeyPair{
 			Public:  pubKey.Public(),
@@ -175,7 +175,7 @@ func NewPrivateKey(pubKey PublicKey, private []byte) (PrivateKey, error) {
 
 // UnmarshalPublicKey is used to parse individual public keys in JSON
 func UnmarshalPublicKey(data []byte) (PublicKey, error) {
-	var parsed tufKey
+	var parsed TUFKey
 	err := json.Unmarshal(data, &parsed)
 	if err != nil {
 		return nil, err
@@ -185,7 +185,7 @@ func UnmarshalPublicKey(data []byte) (PublicKey, error) {
 
 // UnmarshalPrivateKey is used to parse individual private keys in JSON
 func UnmarshalPrivateKey(data []byte) (PrivateKey, error) {
-	var parsed tufKey
+	var parsed TUFKey
 	err := json.Unmarshal(data, &parsed)
 	if err != nil {
 		return nil, err
@@ -193,26 +193,26 @@ func UnmarshalPrivateKey(data []byte) (PrivateKey, error) {
 	return typedPrivateKey(parsed)
 }
 
-// tufKey is the structure used for both public and private keys in TUF.
+// TUFKey is the structure used for both public and private keys in TUF.
 // Normally it would make sense to use a different structures for public and
 // private keys, but that would change the key ID algorithm (since the canonical
 // JSON would be different). This structure should normally be accessed through
 // the PublicKey or PrivateKey interfaces.
-type tufKey struct {
+type TUFKey struct {
 	id    string
 	Type  string  `json:"keytype"`
 	Value KeyPair `json:"keyval"`
 }
 
 // Algorithm returns the algorithm of the key
-func (k tufKey) Algorithm() string {
+func (k TUFKey) Algorithm() string {
 	return k.Type
 }
 
 // ID efficiently generates if necessary, and caches the ID of the key
-func (k *tufKey) ID() string {
+func (k *TUFKey) ID() string {
 	if k.id == "" {
-		pubK := tufKey{
+		pubK := TUFKey{
 			Type: k.Algorithm(),
 			Value: KeyPair{
 				Public:  k.Public(),
@@ -230,7 +230,7 @@ func (k *tufKey) ID() string {
 }
 
 // Public returns the public bytes
-func (k tufKey) Public() []byte {
+func (k TUFKey) Public() []byte {
 	return k.Value.Public
 }
 
@@ -239,42 +239,42 @@ func (k tufKey) Public() []byte {
 // ECDSAPublicKey represents an ECDSA key using a raw serialization
 // of the public key
 type ECDSAPublicKey struct {
-	tufKey
+	TUFKey
 }
 
 // ECDSAx509PublicKey represents an ECDSA key using an x509 cert
 // as the serialized format of the public key
 type ECDSAx509PublicKey struct {
-	tufKey
+	TUFKey
 }
 
 // RSAPublicKey represents an RSA key using a raw serialization
 // of the public key
 type RSAPublicKey struct {
-	tufKey
+	TUFKey
 }
 
 // RSAx509PublicKey represents an RSA key using an x509 cert
 // as the serialized format of the public key
 type RSAx509PublicKey struct {
-	tufKey
+	TUFKey
 }
 
 // ED25519PublicKey represents an ED25519 key using a raw serialization
 // of the public key
 type ED25519PublicKey struct {
-	tufKey
+	TUFKey
 }
 
 // UnknownPublicKey is a catchall for key types that are not supported
 type UnknownPublicKey struct {
-	tufKey
+	TUFKey
 }
 
 // NewECDSAPublicKey initializes a new public key with the ECDSAKey type
 func NewECDSAPublicKey(public []byte) *ECDSAPublicKey {
 	return &ECDSAPublicKey{
-		tufKey: tufKey{
+		TUFKey: TUFKey{
 			Type: ECDSAKey,
 			Value: KeyPair{
 				Public:  public,
@@ -287,7 +287,7 @@ func NewECDSAPublicKey(public []byte) *ECDSAPublicKey {
 // NewECDSAx509PublicKey initializes a new public key with the ECDSAx509Key type
 func NewECDSAx509PublicKey(public []byte) *ECDSAx509PublicKey {
 	return &ECDSAx509PublicKey{
-		tufKey: tufKey{
+		TUFKey: TUFKey{
 			Type: ECDSAx509Key,
 			Value: KeyPair{
 				Public:  public,
@@ -300,7 +300,7 @@ func NewECDSAx509PublicKey(public []byte) *ECDSAx509PublicKey {
 // NewRSAPublicKey initializes a new public key with the RSA type
 func NewRSAPublicKey(public []byte) *RSAPublicKey {
 	return &RSAPublicKey{
-		tufKey: tufKey{
+		TUFKey: TUFKey{
 			Type: RSAKey,
 			Value: KeyPair{
 				Public:  public,
@@ -313,7 +313,7 @@ func NewRSAPublicKey(public []byte) *RSAPublicKey {
 // NewRSAx509PublicKey initializes a new public key with the RSAx509Key type
 func NewRSAx509PublicKey(public []byte) *RSAx509PublicKey {
 	return &RSAx509PublicKey{
-		tufKey: tufKey{
+		TUFKey: TUFKey{
 			Type: RSAx509Key,
 			Value: KeyPair{
 				Public:  public,
@@ -326,7 +326,7 @@ func NewRSAx509PublicKey(public []byte) *RSAx509PublicKey {
 // NewED25519PublicKey initializes a new public key with the ED25519Key type
 func NewED25519PublicKey(public []byte) *ED25519PublicKey {
 	return &ED25519PublicKey{
-		tufKey: tufKey{
+		TUFKey: TUFKey{
 			Type: ED25519Key,
 			Value: KeyPair{
 				Public:  public,
@@ -367,7 +367,7 @@ type ED25519PrivateKey struct {
 
 // UnknownPrivateKey is a catchall for unsupported key types
 type UnknownPrivateKey struct {
-	tufKey
+	TUFKey
 	privateKey
 }
 
@@ -515,10 +515,10 @@ func (k UnknownPrivateKey) SignatureAlgorithm() SigAlgorithm {
 	return ""
 }
 
-// PublicKeyFromPrivate returns a new tufKey based on a private key, with
+// PublicKeyFromPrivate returns a new TUFKey based on a private key, with
 // the private key bytes guaranteed to be nil.
 func PublicKeyFromPrivate(pk PrivateKey) PublicKey {
-	return typedPublicKey(tufKey{
+	return typedPublicKey(TUFKey{
 		Type: pk.Algorithm(),
 		Value: KeyPair{
 			Public:  pk.Public(),
diff --git a/vendor/src/github.com/docker/notary/tuf/data/roles.go b/vendor/src/github.com/docker/notary/tuf/data/roles.go
index a505c92304bbc..b1a2988bd0de7 100644
--- a/vendor/src/github.com/docker/notary/tuf/data/roles.go
+++ b/vendor/src/github.com/docker/notary/tuf/data/roles.go
@@ -2,10 +2,11 @@ package data
 
 import (
 	"fmt"
-	"github.com/Sirupsen/logrus"
 	"path"
 	"regexp"
 	"strings"
+
+	"github.com/Sirupsen/logrus"
 )
 
 // Canonical base role names
@@ -85,32 +86,139 @@ func IsDelegation(role string) bool {
 		isClean
 }
 
+// BaseRole is an internal representation of a root/targets/snapshot/timestamp role, with its public keys included
+type BaseRole struct {
+	Keys      map[string]PublicKey
+	Name      string
+	Threshold int
+}
+
+// NewBaseRole creates a new BaseRole object with the provided parameters
+func NewBaseRole(name string, threshold int, keys ...PublicKey) BaseRole {
+	r := BaseRole{
+		Name:      name,
+		Threshold: threshold,
+		Keys:      make(map[string]PublicKey),
+	}
+	for _, k := range keys {
+		r.Keys[k.ID()] = k
+	}
+	return r
+}
+
+// ListKeys retrieves the public keys valid for this role
+func (b BaseRole) ListKeys() KeyList {
+	return listKeys(b.Keys)
+}
+
+// ListKeyIDs retrieves the list of key IDs valid for this role
+func (b BaseRole) ListKeyIDs() []string {
+	return listKeyIDs(b.Keys)
+}
+
+// DelegationRole is an internal representation of a delegation role, with its public keys included
+type DelegationRole struct {
+	BaseRole
+	Paths []string
+}
+
+func listKeys(keyMap map[string]PublicKey) KeyList {
+	keys := KeyList{}
+	for _, key := range keyMap {
+		keys = append(keys, key)
+	}
+	return keys
+}
+
+func listKeyIDs(keyMap map[string]PublicKey) []string {
+	keyIDs := []string{}
+	for id := range keyMap {
+		keyIDs = append(keyIDs, id)
+	}
+	return keyIDs
+}
+
+// Restrict restricts the paths and path hash prefixes for the passed in delegation role,
+// returning a copy of the role with validated paths as if it was a direct child
+func (d DelegationRole) Restrict(child DelegationRole) (DelegationRole, error) {
+	if !d.IsParentOf(child) {
+		return DelegationRole{}, fmt.Errorf("%s is not a parent of %s", d.Name, child.Name)
+	}
+	return DelegationRole{
+		BaseRole: BaseRole{
+			Keys:      child.Keys,
+			Name:      child.Name,
+			Threshold: child.Threshold,
+		},
+		Paths: RestrictDelegationPathPrefixes(d.Paths, child.Paths),
+	}, nil
+}
+
+// IsParentOf returns whether the passed in delegation role is the direct child of this role,
+// determined by delegation name.
+// Ex: targets/a is a direct parent of targets/a/b, but targets/a is not a direct parent of targets/a/b/c
+func (d DelegationRole) IsParentOf(child DelegationRole) bool {
+	return path.Dir(child.Name) == d.Name
+}
+
+// CheckPaths checks if a given path is valid for the role
+func (d DelegationRole) CheckPaths(path string) bool {
+	return checkPaths(path, d.Paths)
+}
+
+func checkPaths(path string, permitted []string) bool {
+	for _, p := range permitted {
+		if strings.HasPrefix(path, p) {
+			return true
+		}
+	}
+	return false
+}
+
+// RestrictDelegationPathPrefixes returns the list of valid delegationPaths that are prefixed by parentPaths
+func RestrictDelegationPathPrefixes(parentPaths, delegationPaths []string) []string {
+	validPaths := []string{}
+	if len(delegationPaths) == 0 {
+		return validPaths
+	}
+
+	// Validate each individual delegation path
+	for _, delgPath := range delegationPaths {
+		isPrefixed := false
+		for _, parentPath := range parentPaths {
+			if strings.HasPrefix(delgPath, parentPath) {
+				isPrefixed = true
+				break
+			}
+		}
+		// If the delegation path did not match prefix against any parent path, it is not valid
+		if isPrefixed {
+			validPaths = append(validPaths, delgPath)
+		}
+	}
+	return validPaths
+}
+
 // RootRole is a cut down role as it appears in the root.json
+// Eventually should only be used for immediately before and after serialization/deserialization
 type RootRole struct {
 	KeyIDs    []string `json:"keyids"`
 	Threshold int      `json:"threshold"`
 }
 
 // Role is a more verbose role as they appear in targets delegations
+// Eventually should only be used for immediately before and after serialization/deserialization
 type Role struct {
 	RootRole
-	Name             string   `json:"name"`
-	Paths            []string `json:"paths,omitempty"`
-	PathHashPrefixes []string `json:"path_hash_prefixes,omitempty"`
-	Email            string   `json:"email,omitempty"`
+	Name  string   `json:"name"`
+	Paths []string `json:"paths,omitempty"`
 }
 
 // NewRole creates a new Role object from the given parameters
-func NewRole(name string, threshold int, keyIDs, paths, pathHashPrefixes []string) (*Role, error) {
-	if len(paths) > 0 && len(pathHashPrefixes) > 0 {
-		return nil, ErrInvalidRole{
-			Role:   name,
-			Reason: "roles may not have both Paths and PathHashPrefixes",
-		}
-	}
+func NewRole(name string, threshold int, keyIDs, paths []string) (*Role, error) {
 	if IsDelegation(name) {
-		if len(paths) == 0 && len(pathHashPrefixes) == 0 {
-			logrus.Debugf("role %s with no Paths and no PathHashPrefixes will never be able to publish content until one or more are added", name)
+		if len(paths) == 0 {
+			logrus.Debugf("role %s with no Paths will never be able to publish content until one or more are added", name)
 		}
 	}
 	if threshold < 1 {
@@ -124,52 +232,15 @@ func NewRole(name string, threshold int, keyIDs, paths, pathHashPrefixes []strin
 			KeyIDs:    keyIDs,
 			Threshold: threshold,
 		},
-		Name:             name,
-		Paths:            paths,
-		PathHashPrefixes: pathHashPrefixes,
+		Name:  name,
+		Paths: paths,
 	}, nil
 
 }
 
-// IsValid checks if the role has defined both paths and path hash prefixes,
-// having both is invalid
-func (r Role) IsValid() bool {
-	return !(len(r.Paths) > 0 && len(r.PathHashPrefixes) > 0)
-}
-
-// ValidKey checks if the given id is a recognized signing key for the role
-func (r Role) ValidKey(id string) bool {
-	for _, key := range r.KeyIDs {
-		if key == id {
-			return true
-		}
-	}
-	return false
-}
-
 // CheckPaths checks if a given path is valid for the role
 func (r Role) CheckPaths(path string) bool {
-	for _, p := range r.Paths {
-		if strings.HasPrefix(path, p) {
-			return true
-		}
-	}
-	return false
-}
-
-// CheckPrefixes checks if a given hash matches the prefixes for the role
-func (r Role) CheckPrefixes(hash string) bool {
-	for _, p := range r.PathHashPrefixes {
-		if strings.HasPrefix(hash, p) {
-			return true
-		}
-	}
-	return false
-}
-
-// IsDelegation checks if the role is a delegation or a root role
-func (r Role) IsDelegation() bool {
-	return IsDelegation(r.Name)
+	return checkPaths(path, r.Paths)
 }
 
 // AddKeys merges the ids into the current list of role key ids
@@ -182,25 +253,10 @@ func (r *Role) AddPaths(paths []string) error {
 	if len(paths) == 0 {
 		return nil
 	}
-	if len(r.PathHashPrefixes) > 0 {
-		return ErrInvalidRole{Role: r.Name, Reason: "attempted to add paths to role that already has hash prefixes"}
-	}
 	r.Paths = mergeStrSlices(r.Paths, paths)
 	return nil
 }
 
-// AddPathHashPrefixes merges the prefixes into the list of role path hash prefixes
-func (r *Role) AddPathHashPrefixes(prefixes []string) error {
-	if len(prefixes) == 0 {
-		return nil
-	}
-	if len(r.Paths) > 0 {
-		return ErrInvalidRole{Role: r.Name, Reason: "attempted to add hash prefixes to role that already has paths"}
-	}
-	r.PathHashPrefixes = mergeStrSlices(r.PathHashPrefixes, prefixes)
-	return nil
-}
-
 // RemoveKeys removes the ids from the current list of key ids
 func (r *Role) RemoveKeys(ids []string) {
 	r.KeyIDs = subtractStrSlices(r.KeyIDs, ids)
@@ -211,11 +267,6 @@ func (r *Role) RemovePaths(paths []string) {
 	r.Paths = subtractStrSlices(r.Paths, paths)
 }
 
-// RemovePathHashPrefixes removes the prefixes from the current list of path hash prefixes
-func (r *Role) RemovePathHashPrefixes(prefixes []string) {
-	r.PathHashPrefixes = subtractStrSlices(r.PathHashPrefixes, prefixes)
-}
-
 func mergeStrSlices(orig, new []string) []string {
 	have := make(map[string]bool)
 	for _, e := range orig {
diff --git a/vendor/src/github.com/docker/notary/tuf/data/root.go b/vendor/src/github.com/docker/notary/tuf/data/root.go
index bd479206fd643..3a9a1b1decd0c 100644
--- a/vendor/src/github.com/docker/notary/tuf/data/root.go
+++ b/vendor/src/github.com/docker/notary/tuf/data/root.go
@@ -1,6 +1,7 @@
 package data
 
 import (
+	"fmt"
 	"time"
 
 	"github.com/docker/go/canonical/json"
@@ -23,14 +24,57 @@ type Root struct {
 	ConsistentSnapshot bool                 `json:"consistent_snapshot"`
 }
 
+// isValidRootStructure returns an error, or nil, depending on whether the content of the struct
+// is valid for root metadata.  This does not check signatures or expiry, just that
+// the metadata content is valid.
+func isValidRootStructure(r Root) error {
+	expectedType := TUFTypes[CanonicalRootRole]
+	if r.Type != expectedType {
+		return ErrInvalidMetadata{
+			role: CanonicalRootRole, msg: fmt.Sprintf("expected type %s, not %s", expectedType, r.Type)}
+	}
+
+	// all the base roles MUST appear in the root.json - other roles are allowed,
+	// but other than the mirror role (not currently supported) are out of spec
+	for _, roleName := range BaseRoles {
+		roleObj, ok := r.Roles[roleName]
+		if !ok || roleObj == nil {
+			return ErrInvalidMetadata{
+				role: CanonicalRootRole, msg: fmt.Sprintf("missing %s role specification", roleName)}
+		}
+		if err := isValidRootRoleStructure(CanonicalRootRole, roleName, *roleObj, r.Keys); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func isValidRootRoleStructure(metaContainingRole, rootRoleName string, r RootRole, validKeys Keys) error {
+	if r.Threshold < 1 {
+		return ErrInvalidMetadata{
+			role: metaContainingRole,
+			msg:  fmt.Sprintf("invalid threshold specified for %s: %v ", rootRoleName, r.Threshold),
+		}
+	}
+	for _, keyID := range r.KeyIDs {
+		if _, ok := validKeys[keyID]; !ok {
+			return ErrInvalidMetadata{
+				role: metaContainingRole,
+				msg:  fmt.Sprintf("key ID %s specified in %s without corresponding key", keyID, rootRoleName),
+			}
+		}
+	}
+	return nil
+}
+
 // NewRoot initializes a new SignedRoot with a set of keys, roles, and the consistent flag
 func NewRoot(keys map[string]PublicKey, roles map[string]*RootRole, consistent bool) (*SignedRoot, error) {
 	signedRoot := &SignedRoot{
 		Signatures: make([]Signature, 0),
 		Signed: Root{
-			Type:               TUFTypes["root"],
+			Type:               TUFTypes[CanonicalRootRole],
 			Version:            0,
-			Expires:            DefaultExpires("root"),
+			Expires:            DefaultExpires(CanonicalRootRole),
 			Keys:               keys,
 			Roles:              roles,
 			ConsistentSnapshot: consistent,
@@ -41,6 +85,34 @@ func NewRoot(keys map[string]PublicKey, roles map[string]*RootRole, consistent b
 	return signedRoot, nil
 }
 
+// BuildBaseRole returns a copy of a BaseRole using the information in this SignedRoot for the specified role name.
+// Will error for invalid role name or key metadata within this SignedRoot
+func (r SignedRoot) BuildBaseRole(roleName string) (BaseRole, error) {
+	roleData, ok := r.Signed.Roles[roleName]
+	if !ok {
+		return BaseRole{}, ErrInvalidRole{Role: roleName, Reason: "role not found in root file"}
+	}
+	// Get all public keys for the base role from TUF metadata
+	keyIDs := roleData.KeyIDs
+	pubKeys := make(map[string]PublicKey)
+	for _, keyID := range keyIDs {
+		pubKey, ok := r.Signed.Keys[keyID]
+		if !ok {
+			return BaseRole{}, ErrInvalidRole{
+				Role:   roleName,
+				Reason: fmt.Sprintf("key with ID %s was not found in root metadata", keyID),
+			}
+		}
+		pubKeys[keyID] = pubKey
+	}
+
+	return BaseRole{
+		Name:      roleName,
+		Keys:      pubKeys,
+		Threshold: roleData.Threshold,
+	}, nil
+}
+
 // ToSigned partially serializes a SignedRoot for further signing
 func (r SignedRoot) ToSigned() (*Signed, error) {
 	s, err := defaultSerializer.MarshalCanonical(r.Signed)
@@ -70,11 +142,14 @@ func (r SignedRoot) MarshalJSON() ([]byte, error) {
 	return defaultSerializer.Marshal(signed)
 }
 
-// RootFromSigned fully unpacks a Signed object into a SignedRoot
+// RootFromSigned fully unpacks a Signed object into a SignedRoot and ensures
+// that it is a valid SignedRoot
 func RootFromSigned(s *Signed) (*SignedRoot, error) {
 	r := Root{}
-	err := json.Unmarshal(s.Signed, &r)
-	if err != nil {
+	if err := defaultSerializer.Unmarshal(s.Signed, &r); err != nil {
+		return nil, err
+	}
+	if err := isValidRootStructure(r); err != nil {
 		return nil, err
 	}
 	sigs := make([]Signature, len(s.Signatures))
diff --git a/vendor/src/github.com/docker/notary/tuf/data/snapshot.go b/vendor/src/github.com/docker/notary/tuf/data/snapshot.go
index f13951ca830cd..9637dfff86ba6 100644
--- a/vendor/src/github.com/docker/notary/tuf/data/snapshot.go
+++ b/vendor/src/github.com/docker/notary/tuf/data/snapshot.go
@@ -2,6 +2,8 @@ package data
 
 import (
 	"bytes"
+	"crypto/sha256"
+	"fmt"
 	"time"
 
 	"github.com/Sirupsen/logrus"
@@ -23,6 +25,30 @@ type Snapshot struct {
 	Meta    Files     `json:"meta"`
 }
 
+// isValidSnapshotStructure returns an error, or nil, depending on whether the content of the
+// struct is valid for snapshot metadata.  This does not check signatures or expiry, just that
+// the metadata content is valid.
+func isValidSnapshotStructure(s Snapshot) error {
+	expectedType := TUFTypes[CanonicalSnapshotRole]
+	if s.Type != expectedType {
+		return ErrInvalidMetadata{
+			role: CanonicalSnapshotRole, msg: fmt.Sprintf("expected type %s, not %s", expectedType, s.Type)}
+	}
+
+	for _, role := range []string{CanonicalRootRole, CanonicalTargetsRole} {
+		// Meta is a map of FileMeta, so if the role isn't in the map it returns
+		// an empty FileMeta, which has an empty map, and you can check on keys
+		// from an empty map.
+		if checksum, ok := s.Meta[role].Hashes["sha256"]; !ok || len(checksum) != sha256.Size {
+			return ErrInvalidMetadata{
+				role: CanonicalSnapshotRole,
+				msg:  fmt.Sprintf("missing or invalid %s sha256 checksum information", role),
+			}
+		}
+	}
+	return nil
+}
+
 // NewSnapshot initilizes a SignedSnapshot with a given top level root
 // and targets objects
 func NewSnapshot(root *Signed, targets *Signed) (*SignedSnapshot, error) {
@@ -64,8 +90,8 @@ func (sp *SignedSnapshot) hashForRole(role string) []byte {
 }
 
 // ToSigned partially serializes a SignedSnapshot for further signing
-func (sp SignedSnapshot) ToSigned() (*Signed, error) {
-	s, err := json.MarshalCanonical(sp.Signed)
+func (sp *SignedSnapshot) ToSigned() (*Signed, error) {
+	s, err := defaultSerializer.MarshalCanonical(sp.Signed)
 	if err != nil {
 		return nil, err
 	}
@@ -88,6 +114,15 @@ func (sp *SignedSnapshot) AddMeta(role string, meta FileMeta) {
 	sp.Dirty = true
 }
 
+// GetMeta gets the metadata for a particular role, returning an error if it's
+// not found
+func (sp *SignedSnapshot) GetMeta(role string) (*FileMeta, error) {
+	if meta, ok := sp.Signed.Meta[role]; ok {
+		return &meta, nil
+	}
+	return nil, ErrMissingMeta{Role: role}
+}
+
 // DeleteMeta removes a role from the snapshot. If the role doesn't
 // exist in the snapshot, it's a noop.
 func (sp *SignedSnapshot) DeleteMeta(role string) {
@@ -97,11 +132,22 @@ func (sp *SignedSnapshot) DeleteMeta(role string) {
 	}
 }
 
+// MarshalJSON returns the serialized form of SignedSnapshot as bytes
+func (sp *SignedSnapshot) MarshalJSON() ([]byte, error) {
+	signed, err := sp.ToSigned()
+	if err != nil {
+		return nil, err
+	}
+	return defaultSerializer.Marshal(signed)
+}
+
 // SnapshotFromSigned fully unpacks a Signed object into a SignedSnapshot
 func SnapshotFromSigned(s *Signed) (*SignedSnapshot, error) {
 	sp := Snapshot{}
-	err := json.Unmarshal(s.Signed, &sp)
-	if err != nil {
+	if err := defaultSerializer.Unmarshal(s.Signed, &sp); err != nil {
+		return nil, err
+	}
+	if err := isValidSnapshotStructure(sp); err != nil {
 		return nil, err
 	}
 	sigs := make([]Signature, len(s.Signatures))
diff --git a/vendor/src/github.com/docker/notary/tuf/data/targets.go b/vendor/src/github.com/docker/notary/tuf/data/targets.go
index a538d6afa52d6..fce4d177e0fda 100644
--- a/vendor/src/github.com/docker/notary/tuf/data/targets.go
+++ b/vendor/src/github.com/docker/notary/tuf/data/targets.go
@@ -1,9 +1,9 @@
 package data
 
 import (
-	"crypto/sha256"
-	"encoding/hex"
 	"errors"
+	"fmt"
+	"path"
 
 	"github.com/docker/go/canonical/json"
 )
@@ -23,6 +23,33 @@ type Targets struct {
 	Delegations Delegations `json:"delegations,omitempty"`
 }
 
+// isValidTargetsStructure returns an error, or nil, depending on whether the content of the struct
+// is valid for targets metadata.  This does not check signatures or expiry, just that
+// the metadata content is valid.
+func isValidTargetsStructure(t Targets, roleName string) error {
+	if roleName != CanonicalTargetsRole && !IsDelegation(roleName) {
+		return ErrInvalidRole{Role: roleName}
+	}
+
+	// even if it's a delegated role, the metadata type is "Targets"
+	expectedType := TUFTypes[CanonicalTargetsRole]
+	if t.Type != expectedType {
+		return ErrInvalidMetadata{
+			role: roleName, msg: fmt.Sprintf("expected type %s, not %s", expectedType, t.Type)}
+	}
+
+	for _, roleObj := range t.Delegations.Roles {
+		if !IsDelegation(roleObj.Name) || path.Dir(roleObj.Name) != roleName {
+			return ErrInvalidMetadata{
+				role: roleName, msg: fmt.Sprintf("delegation role %s invalid", roleObj.Name)}
+		}
+		if err := isValidRootRoleStructure(roleName, roleObj.Name, roleObj.RootRole, t.Delegations.Keys); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
 // NewTargets intiializes a new empty SignedTargets object
 func NewTargets() *SignedTargets {
 	return &SignedTargets{
@@ -51,30 +78,58 @@ func (t SignedTargets) GetMeta(path string) *FileMeta {
 	return nil
 }
 
-// GetDelegations filters the roles and associated keys that may be
-// the signers for the given target path. If no appropriate roles
-// can be found, it will simply return nil for the return values.
-// The returned slice of Role will have order maintained relative
-// to the role slice on Delegations per TUF spec proposal on using
-// order to determine priority.
-func (t SignedTargets) GetDelegations(path string) []*Role {
-	var roles []*Role
-	pathHashBytes := sha256.Sum256([]byte(path))
-	pathHash := hex.EncodeToString(pathHashBytes[:])
-	for _, r := range t.Signed.Delegations.Roles {
-		if !r.IsValid() {
-			// Role has both Paths and PathHashPrefixes.
+// GetValidDelegations filters the delegation roles specified in the signed targets, and
+// only returns roles that are direct children and restricts their paths
+func (t SignedTargets) GetValidDelegations(parent DelegationRole) []DelegationRole {
+	roles := t.buildDelegationRoles()
+	result := []DelegationRole{}
+	for _, r := range roles {
+		validRole, err := parent.Restrict(r)
+		if err != nil {
 			continue
 		}
-		if r.CheckPaths(path) {
-			roles = append(roles, r)
-			continue
+		result = append(result, validRole)
+	}
+	return result
+}
+
+// BuildDelegationRole returns a copy of a DelegationRole using the information in this SignedTargets for the specified role name.
+// Will error for invalid role name or key metadata within this SignedTargets.  Path data is not validated.
+func (t *SignedTargets) BuildDelegationRole(roleName string) (DelegationRole, error) {
+	for _, role := range t.Signed.Delegations.Roles {
+		if role.Name == roleName {
+			pubKeys := make(map[string]PublicKey)
+			for _, keyID := range role.KeyIDs {
+				pubKey, ok := t.Signed.Delegations.Keys[keyID]
+				if !ok {
+					// Couldn't retrieve all keys, so stop walking and return invalid role
+					return DelegationRole{}, ErrInvalidRole{Role: roleName, Reason: "delegation does not exist with all specified keys"}
+				}
+				pubKeys[keyID] = pubKey
+			}
+			return DelegationRole{
+				BaseRole: BaseRole{
+					Name:      role.Name,
+					Keys:      pubKeys,
+					Threshold: role.Threshold,
+				},
+				Paths: role.Paths,
+			}, nil
 		}
-		if r.CheckPrefixes(pathHash) {
-			roles = append(roles, r)
+	}
+	return DelegationRole{}, ErrNoSuchRole{Role: roleName}
+}
+
+// helper function to create DelegationRole structures from all delegations in a SignedTargets,
+// these delegations are read directly from the SignedTargets and not modified or validated
+func (t SignedTargets) buildDelegationRoles() []DelegationRole {
+	var roles []DelegationRole
+	for _, roleData := range t.Signed.Delegations.Roles {
+		delgRole, err := t.BuildDelegationRole(roleData.Name)
+		if err != nil {
 			continue
 		}
-		//keysDB.AddRole(r)
+		roles = append(roles, delgRole)
 	}
 	return roles
 }
@@ -93,8 +148,8 @@ func (t *SignedTargets) AddDelegation(role *Role, keys []*PublicKey) error {
 }
 
 // ToSigned partially serializes a SignedTargets for further signing
-func (t SignedTargets) ToSigned() (*Signed, error) {
-	s, err := json.MarshalCanonical(t.Signed)
+func (t *SignedTargets) ToSigned() (*Signed, error) {
+	s, err := defaultSerializer.MarshalCanonical(t.Signed)
 	if err != nil {
 		return nil, err
 	}
@@ -111,13 +166,25 @@ func (t SignedTargets) ToSigned() (*Signed, error) {
 	}, nil
 }
 
-// TargetsFromSigned fully unpacks a Signed object into a SignedTargets
-func TargetsFromSigned(s *Signed) (*SignedTargets, error) {
-	t := Targets{}
-	err := json.Unmarshal(s.Signed, &t)
+// MarshalJSON returns the serialized form of SignedTargets as bytes
+func (t *SignedTargets) MarshalJSON() ([]byte, error) {
+	signed, err := t.ToSigned()
 	if err != nil {
 		return nil, err
 	}
+	return defaultSerializer.Marshal(signed)
+}
+
+// TargetsFromSigned fully unpacks a Signed object into a SignedTargets, given
+// a role name (so it can validate the SignedTargets object)
+func TargetsFromSigned(s *Signed, roleName string) (*SignedTargets, error) {
+	t := Targets{}
+	if err := defaultSerializer.Unmarshal(s.Signed, &t); err != nil {
+		return nil, err
+	}
+	if err := isValidTargetsStructure(t, roleName); err != nil {
+		return nil, err
+	}
 	sigs := make([]Signature, len(s.Signatures))
 	copy(sigs, s.Signatures)
 	return &SignedTargets{
diff --git a/vendor/src/github.com/docker/notary/tuf/data/timestamp.go b/vendor/src/github.com/docker/notary/tuf/data/timestamp.go
index f68252ca5ba7f..bc961f7a6302e 100644
--- a/vendor/src/github.com/docker/notary/tuf/data/timestamp.go
+++ b/vendor/src/github.com/docker/notary/tuf/data/timestamp.go
@@ -2,6 +2,8 @@ package data
 
 import (
 	"bytes"
+	"crypto/sha256"
+	"fmt"
 	"time"
 
 	"github.com/docker/go/canonical/json"
@@ -22,6 +24,26 @@ type Timestamp struct {
 	Meta    Files     `json:"meta"`
 }
 
+// isValidTimestampStructure returns an error, or nil, depending on whether the content of the struct
+// is valid for timestamp metadata.  This does not check signatures or expiry, just that
+// the metadata content is valid.
+func isValidTimestampStructure(t Timestamp) error {
+	expectedType := TUFTypes[CanonicalTimestampRole]
+	if t.Type != expectedType {
+		return ErrInvalidMetadata{
+			role: CanonicalTimestampRole, msg: fmt.Sprintf("expected type %s, not %s", expectedType, t.Type)}
+	}
+
+	// Meta is a map of FileMeta, so if the role isn't in the map it returns
+	// an empty FileMeta, which has an empty map, and you can check on keys
+	// from an empty map.
+	if cs, ok := t.Meta[CanonicalSnapshotRole].Hashes["sha256"]; !ok || len(cs) != sha256.Size {
+		return ErrInvalidMetadata{
+			role: CanonicalTimestampRole, msg: "missing or invalid snapshot sha256 checksum information"}
+	}
+	return nil
+}
+
 // NewTimestamp initializes a timestamp with an existing snapshot
 func NewTimestamp(snapshot *Signed) (*SignedTimestamp, error) {
 	snapshotJSON, err := json.Marshal(snapshot)
@@ -47,8 +69,8 @@ func NewTimestamp(snapshot *Signed) (*SignedTimestamp, error) {
 
 // ToSigned partially serializes a SignedTimestamp such that it can
 // be signed
-func (ts SignedTimestamp) ToSigned() (*Signed, error) {
-	s, err := json.MarshalCanonical(ts.Signed)
+func (ts *SignedTimestamp) ToSigned() (*Signed, error) {
+	s, err := defaultSerializer.MarshalCanonical(ts.Signed)
 	if err != nil {
 		return nil, err
 	}
@@ -65,12 +87,33 @@ func (ts SignedTimestamp) ToSigned() (*Signed, error) {
 	}, nil
 }
 
+// GetSnapshot gets the expected snapshot metadata hashes in the timestamp metadata,
+// or nil if it doesn't exist
+func (ts *SignedTimestamp) GetSnapshot() (*FileMeta, error) {
+	snapshotExpected, ok := ts.Signed.Meta[CanonicalSnapshotRole]
+	if !ok {
+		return nil, ErrMissingMeta{Role: CanonicalSnapshotRole}
+	}
+	return &snapshotExpected, nil
+}
+
+// MarshalJSON returns the serialized form of SignedTimestamp as bytes
+func (ts *SignedTimestamp) MarshalJSON() ([]byte, error) {
+	signed, err := ts.ToSigned()
+	if err != nil {
+		return nil, err
+	}
+	return defaultSerializer.Marshal(signed)
+}
+
 // TimestampFromSigned parsed a Signed object into a fully unpacked
 // SignedTimestamp
 func TimestampFromSigned(s *Signed) (*SignedTimestamp, error) {
 	ts := Timestamp{}
-	err := json.Unmarshal(s.Signed, &ts)
-	if err != nil {
+	if err := defaultSerializer.Unmarshal(s.Signed, &ts); err != nil {
+		return nil, err
+	}
+	if err := isValidTimestampStructure(ts); err != nil {
 		return nil, err
 	}
 	sigs := make([]Signature, len(s.Signatures))
diff --git a/vendor/src/github.com/docker/notary/tuf/data/types.go b/vendor/src/github.com/docker/notary/tuf/data/types.go
index 6459b8e664a20..4de55c4e1cb0e 100644
--- a/vendor/src/github.com/docker/notary/tuf/data/types.go
+++ b/vendor/src/github.com/docker/notary/tuf/data/types.go
@@ -12,6 +12,7 @@ import (
 
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/go/canonical/json"
+	"github.com/docker/notary"
 )
 
 // SigAlgorithm for types of signatures
@@ -171,16 +172,16 @@ func NewDelegations() *Delegations {
 	}
 }
 
-// defines number of days in which something should expire
-var defaultExpiryTimes = map[string]int{
-	CanonicalRootRole:      365,
-	CanonicalTargetsRole:   90,
-	CanonicalSnapshotRole:  7,
-	CanonicalTimestampRole: 1,
+// These values are recommended TUF expiry times.
+var defaultExpiryTimes = map[string]time.Duration{
+	CanonicalRootRole:      notary.Year,
+	CanonicalTargetsRole:   90 * notary.Day,
+	CanonicalSnapshotRole:  7 * notary.Day,
+	CanonicalTimestampRole: notary.Day,
 }
 
 // SetDefaultExpiryTimes allows one to change the default expiries.
-func SetDefaultExpiryTimes(times map[string]int) {
+func SetDefaultExpiryTimes(times map[string]time.Duration) {
 	for key, value := range times {
 		if _, ok := defaultExpiryTimes[key]; !ok {
 			logrus.Errorf("Attempted to set default expiry for an unknown role: %s", key)
@@ -192,10 +193,10 @@ func SetDefaultExpiryTimes(times map[string]int) {
 
 // DefaultExpires gets the default expiry time for the given role
 func DefaultExpires(role string) time.Time {
-	var t time.Time
-	if t, ok := defaultExpiryTimes[role]; ok {
-		return time.Now().AddDate(0, 0, t)
+	if d, ok := defaultExpiryTimes[role]; ok {
+		return time.Now().Add(d)
 	}
+	var t time.Time
 	return t.UTC().Round(time.Second)
 }
 
diff --git a/vendor/src/github.com/docker/notary/tuf/keys/db.go b/vendor/src/github.com/docker/notary/tuf/keys/db.go
deleted file mode 100644
index 92d2ef863e5d3..0000000000000
--- a/vendor/src/github.com/docker/notary/tuf/keys/db.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package keys
-
-import (
-	"errors"
-
-	"github.com/docker/notary/tuf/data"
-)
-
-// Various basic key database errors
-var (
-	ErrWrongType        = errors.New("tuf: invalid key type")
-	ErrExists           = errors.New("tuf: key already in db")
-	ErrWrongID          = errors.New("tuf: key id mismatch")
-	ErrInvalidKey       = errors.New("tuf: invalid key")
-	ErrInvalidKeyID     = errors.New("tuf: invalid key id")
-	ErrInvalidThreshold = errors.New("tuf: invalid role threshold")
-)
-
-// KeyDB is an in memory database of public keys and role associations.
-// It is populated when parsing TUF files and used during signature
-// verification to look up the keys for a given role
-type KeyDB struct {
-	roles map[string]*data.Role
-	keys  map[string]data.PublicKey
-}
-
-// NewDB initializes an empty KeyDB
-func NewDB() *KeyDB {
-	return &KeyDB{
-		roles: make(map[string]*data.Role),
-		keys:  make(map[string]data.PublicKey),
-	}
-}
-
-// AddKey adds a public key to the database
-func (db *KeyDB) AddKey(k data.PublicKey) {
-	db.keys[k.ID()] = k
-}
-
-// AddRole adds a role to the database. Any keys associated with the
-// role must have already been added.
-func (db *KeyDB) AddRole(r *data.Role) error {
-	if !data.ValidRole(r.Name) {
-		return data.ErrInvalidRole{Role: r.Name}
-	}
-	if r.Threshold < 1 {
-		return ErrInvalidThreshold
-	}
-
-	// validate all key ids are in the keys maps
-	for _, id := range r.KeyIDs {
-		if _, ok := db.keys[id]; !ok {
-			return ErrInvalidKeyID
-		}
-	}
-
-	db.roles[r.Name] = r
-	return nil
-}
-
-// GetAllRoles gets all roles from the database
-func (db *KeyDB) GetAllRoles() []*data.Role {
-	roles := []*data.Role{}
-	for _, role := range db.roles {
-		roles = append(roles, role)
-	}
-	return roles
-}
-
-// GetKey pulls a key out of the database by its ID
-func (db *KeyDB) GetKey(id string) data.PublicKey {
-	return db.keys[id]
-}
-
-// GetRole retrieves a role based on its name
-func (db *KeyDB) GetRole(name string) *data.Role {
-	return db.roles[name]
-}
diff --git a/vendor/src/github.com/docker/notary/tuf/signed/verify.go b/vendor/src/github.com/docker/notary/tuf/signed/verify.go
index 9548e4e53df22..4869b170745ce 100644
--- a/vendor/src/github.com/docker/notary/tuf/signed/verify.go
+++ b/vendor/src/github.com/docker/notary/tuf/signed/verify.go
@@ -8,7 +8,6 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/go/canonical/json"
 	"github.com/docker/notary/tuf/data"
-	"github.com/docker/notary/tuf/keys"
 )
 
 // Various basic signing errors
@@ -57,18 +56,18 @@ func VerifyRoot(s *data.Signed, minVersion int, keys map[string]data.PublicKey)
 			continue
 		}
 		// threshold of 1 so return on first success
-		return verifyMeta(s, "root", minVersion)
+		return verifyMeta(s, data.CanonicalRootRole, minVersion)
 	}
 	return ErrRoleThreshold{}
 }
 
 // Verify checks the signatures and metadata (expiry, version) for the signed role
 // data
-func Verify(s *data.Signed, role string, minVersion int, db *keys.KeyDB) error {
-	if err := verifyMeta(s, role, minVersion); err != nil {
+func Verify(s *data.Signed, role data.BaseRole, minVersion int) error {
+	if err := verifyMeta(s, role.Name, minVersion); err != nil {
 		return err
 	}
-	return VerifySignatures(s, role, db)
+	return VerifySignatures(s, role)
 }
 
 func verifyMeta(s *data.Signed, role string, minVersion int) error {
@@ -96,21 +95,18 @@ func IsExpired(t time.Time) bool {
 }
 
 // VerifySignatures checks the we have sufficient valid signatures for the given role
-func VerifySignatures(s *data.Signed, role string, db *keys.KeyDB) error {
+func VerifySignatures(s *data.Signed, roleData data.BaseRole) error {
 	if len(s.Signatures) == 0 {
 		return ErrNoSignatures
 	}
 
-	roleData := db.GetRole(role)
-	if roleData == nil {
-		return ErrUnknownRole
-	}
-
 	if roleData.Threshold < 1 {
 		return ErrRoleThreshold{}
 	}
-	logrus.Debugf("%s role has key IDs: %s", role, strings.Join(roleData.KeyIDs, ","))
+	logrus.Debugf("%s role has key IDs: %s", roleData.Name, strings.Join(roleData.ListKeyIDs(), ","))
 
+	// remarshal the signed part so we can verify the signature, since the signature has
+	// to be of a canonically marshalled signed object
 	var decoded map[string]interface{}
 	if err := json.Unmarshal(s.Signed, &decoded); err != nil {
 		return err
@@ -123,12 +119,8 @@ func VerifySignatures(s *data.Signed, role string, db *keys.KeyDB) error {
 	valid := make(map[string]struct{})
 	for _, sig := range s.Signatures {
 		logrus.Debug("verifying signature for key ID: ", sig.KeyID)
-		if !roleData.ValidKey(sig.KeyID) {
-			logrus.Debugf("continuing b/c keyid was invalid: %s for roledata %s\n", sig.KeyID, roleData)
-			continue
-		}
-		key := db.GetKey(sig.KeyID)
-		if key == nil {
+		key, ok := roleData.Keys[sig.KeyID]
+		if !ok {
 			logrus.Debugf("continuing b/c keyid lookup was nil: %s\n", sig.KeyID)
 			continue
 		}
@@ -153,28 +145,3 @@ func VerifySignatures(s *data.Signed, role string, db *keys.KeyDB) error {
 
 	return nil
 }
-
-// Unmarshal unmarshals and verifys the raw bytes for a given role's metadata
-func Unmarshal(b []byte, v interface{}, role string, minVersion int, db *keys.KeyDB) error {
-	s := &data.Signed{}
-	if err := json.Unmarshal(b, s); err != nil {
-		return err
-	}
-	if err := Verify(s, role, minVersion, db); err != nil {
-		return err
-	}
-	return json.Unmarshal(s.Signed, v)
-}
-
-// UnmarshalTrusted unmarshals and verifies signatures only, not metadata, for a
-// given role's metadata
-func UnmarshalTrusted(b []byte, v interface{}, role string, db *keys.KeyDB) error {
-	s := &data.Signed{}
-	if err := json.Unmarshal(b, s); err != nil {
-		return err
-	}
-	if err := VerifySignatures(s, role, db); err != nil {
-		return err
-	}
-	return json.Unmarshal(s.Signed, v)
-}
diff --git a/vendor/src/github.com/docker/notary/tuf/store/filestore.go b/vendor/src/github.com/docker/notary/tuf/store/filestore.go
index 52e7c8f2893b2..44401707c4464 100644
--- a/vendor/src/github.com/docker/notary/tuf/store/filestore.go
+++ b/vendor/src/github.com/docker/notary/tuf/store/filestore.go
@@ -2,6 +2,7 @@ package store
 
 import (
 	"fmt"
+	"github.com/docker/notary"
 	"io/ioutil"
 	"os"
 	"path"
@@ -9,25 +10,19 @@ import (
 )
 
 // NewFilesystemStore creates a new store in a directory tree
-func NewFilesystemStore(baseDir, metaSubDir, metaExtension, targetsSubDir string) (*FilesystemStore, error) {
+func NewFilesystemStore(baseDir, metaSubDir, metaExtension string) (*FilesystemStore, error) {
 	metaDir := path.Join(baseDir, metaSubDir)
-	targetsDir := path.Join(baseDir, targetsSubDir)
 
 	// Make sure we can create the necessary dirs and they are writable
 	err := os.MkdirAll(metaDir, 0700)
 	if err != nil {
 		return nil, err
 	}
-	err = os.MkdirAll(targetsDir, 0700)
-	if err != nil {
-		return nil, err
-	}
 
 	return &FilesystemStore{
 		baseDir:       baseDir,
 		metaDir:       metaDir,
 		metaExtension: metaExtension,
-		targetsDir:    targetsDir,
 	}, nil
 }
 
@@ -36,7 +31,6 @@ type FilesystemStore struct {
 	baseDir       string
 	metaDir       string
 	metaExtension string
-	targetsDir    string
 }
 
 func (f *FilesystemStore) getPath(name string) string {
@@ -44,7 +38,8 @@ func (f *FilesystemStore) getPath(name string) string {
 	return filepath.Join(f.metaDir, fileName)
 }
 
-// GetMeta returns the meta for the given name (a role)
+// GetMeta returns the meta for the given name (a role) up to size bytes
+// If size is -1, this corresponds to "infinite," but we cut off at 100MB
 func (f *FilesystemStore) GetMeta(name string, size int64) ([]byte, error) {
 	meta, err := ioutil.ReadFile(f.getPath(name))
 	if err != nil {
@@ -53,7 +48,14 @@ func (f *FilesystemStore) GetMeta(name string, size int64) ([]byte, error) {
 		}
 		return nil, err
 	}
-	return meta, nil
+	if size == -1 {
+		size = notary.MaxDownloadSize
+	}
+	// Only return up to size bytes
+	if int64(len(meta)) < size {
+		return meta, nil
+	}
+	return meta[:size], nil
 }
 
 // SetMultiMeta sets the metadata for multiple roles in one operation
diff --git a/vendor/src/github.com/docker/notary/tuf/store/httpstore.go b/vendor/src/github.com/docker/notary/tuf/store/httpstore.go
index 7444a311b94b1..8b0d8501143bd 100644
--- a/vendor/src/github.com/docker/notary/tuf/store/httpstore.go
+++ b/vendor/src/github.com/docker/notary/tuf/store/httpstore.go
@@ -23,6 +23,7 @@ import (
 	"path"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/notary"
 	"github.com/docker/notary/tuf/validation"
 )
 
@@ -33,6 +34,9 @@ type ErrServerUnavailable struct {
 }
 
 func (err ErrServerUnavailable) Error() string {
+	if err.code == 401 {
+		return fmt.Sprintf("you are not authorized to perform this operation: server returned 401.")
+	}
 	return fmt.Sprintf("unable to reach trust server at this time: %d.", err.code)
 }
 
@@ -71,13 +75,12 @@ type HTTPStore struct {
 	baseURL       url.URL
 	metaPrefix    string
 	metaExtension string
-	targetsPrefix string
 	keyExtension  string
 	roundTrip     http.RoundTripper
 }
 
 // NewHTTPStore initializes a new store against a URL and a number of configuration options
-func NewHTTPStore(baseURL, metaPrefix, metaExtension, targetsPrefix, keyExtension string, roundTrip http.RoundTripper) (RemoteStore, error) {
+func NewHTTPStore(baseURL, metaPrefix, metaExtension, keyExtension string, roundTrip http.RoundTripper) (RemoteStore, error) {
 	base, err := url.Parse(baseURL)
 	if err != nil {
 		return nil, err
@@ -92,7 +95,6 @@ func NewHTTPStore(baseURL, metaPrefix, metaExtension, targetsPrefix, keyExtensio
 		baseURL:       *base,
 		metaPrefix:    metaPrefix,
 		metaExtension: metaExtension,
-		targetsPrefix: targetsPrefix,
 		keyExtension:  keyExtension,
 		roundTrip:     roundTrip,
 	}, nil
@@ -137,6 +139,7 @@ func translateStatusToError(resp *http.Response, resource string) error {
 // GetMeta downloads the named meta file with the given size. A short body
 // is acceptable because in the case of timestamp.json, the size is a cap,
 // not an exact length.
+// If size is -1, this corresponds to "infinite," but we cut off at 100MB
 func (s HTTPStore) GetMeta(name string, size int64) ([]byte, error) {
 	url, err := s.buildMetaURL(name)
 	if err != nil {
@@ -155,6 +158,9 @@ func (s HTTPStore) GetMeta(name string, size int64) ([]byte, error) {
 		logrus.Debugf("received HTTP status %d when requesting %s.", resp.StatusCode, name)
 		return nil, err
 	}
+	if size == -1 {
+		size = notary.MaxDownloadSize
+	}
 	if resp.ContentLength > size {
 		return nil, ErrMaliciousServer{}
 	}
@@ -250,11 +256,6 @@ func (s HTTPStore) buildMetaURL(name string) (*url.URL, error) {
 	return s.buildURL(uri)
 }
 
-func (s HTTPStore) buildTargetsURL(name string) (*url.URL, error) {
-	uri := path.Join(s.targetsPrefix, name)
-	return s.buildURL(uri)
-}
-
 func (s HTTPStore) buildKeyURL(name string) (*url.URL, error) {
 	filename := fmt.Sprintf("%s.%s", name, s.keyExtension)
 	uri := path.Join(s.metaPrefix, filename)
@@ -269,29 +270,6 @@ func (s HTTPStore) buildURL(uri string) (*url.URL, error) {
 	return s.baseURL.ResolveReference(sub), nil
 }
 
-// GetTarget returns a reader for the desired target or an error.
-// N.B. The caller is responsible for closing the reader.
-func (s HTTPStore) GetTarget(path string) (io.ReadCloser, error) {
-	url, err := s.buildTargetsURL(path)
-	if err != nil {
-		return nil, err
-	}
-	logrus.Debug("Attempting to download target: ", url.String())
-	req, err := http.NewRequest("GET", url.String(), nil)
-	if err != nil {
-		return nil, err
-	}
-	resp, err := s.roundTrip.RoundTrip(req)
-	if err != nil {
-		return nil, err
-	}
-	defer resp.Body.Close()
-	if err := translateStatusToError(resp, path); err != nil {
-		return nil, err
-	}
-	return resp.Body, nil
-}
-
 // GetKey retrieves a public key from the remote server
 func (s HTTPStore) GetKey(role string) ([]byte, error) {
 	url, err := s.buildKeyURL(role)
diff --git a/vendor/src/github.com/docker/notary/tuf/store/interfaces.go b/vendor/src/github.com/docker/notary/tuf/store/interfaces.go
index 6d73da8a96450..dd307168bf113 100644
--- a/vendor/src/github.com/docker/notary/tuf/store/interfaces.go
+++ b/vendor/src/github.com/docker/notary/tuf/store/interfaces.go
@@ -1,13 +1,5 @@
 package store
 
-import (
-	"io"
-
-	"github.com/docker/notary/tuf/data"
-)
-
-type targetsWalkFunc func(path string, meta data.FileMeta) error
-
 // MetadataStore must be implemented by anything that intends to interact
 // with a store of TUF files
 type MetadataStore interface {
@@ -23,17 +15,9 @@ type PublicKeyStore interface {
 	GetKey(role string) ([]byte, error)
 }
 
-// TargetStore represents a collection of targets that can be walked similarly
-// to walking a directory, passing a callback that receives the path and meta
-// for each target
-type TargetStore interface {
-	WalkStagedTargets(paths []string, targetsFn targetsWalkFunc) error
-}
-
 // LocalStore represents a local TUF sture
 type LocalStore interface {
 	MetadataStore
-	TargetStore
 }
 
 // RemoteStore is similar to LocalStore with the added expectation that it should
@@ -41,5 +25,4 @@ type LocalStore interface {
 type RemoteStore interface {
 	MetadataStore
 	PublicKeyStore
-	GetTarget(path string) (io.ReadCloser, error)
 }
diff --git a/vendor/src/github.com/docker/notary/tuf/store/memorystore.go b/vendor/src/github.com/docker/notary/tuf/store/memorystore.go
index 6072a8c44674d..493bb6f0b52c3 100644
--- a/vendor/src/github.com/docker/notary/tuf/store/memorystore.go
+++ b/vendor/src/github.com/docker/notary/tuf/store/memorystore.go
@@ -1,38 +1,59 @@
 package store
 
 import (
-	"bytes"
+	"crypto/sha256"
 	"fmt"
-	"io"
 
+	"github.com/docker/notary"
 	"github.com/docker/notary/tuf/data"
 	"github.com/docker/notary/tuf/utils"
 )
 
 // NewMemoryStore returns a MetadataStore that operates entirely in memory.
 // Very useful for testing
-func NewMemoryStore(meta map[string][]byte, files map[string][]byte) RemoteStore {
+func NewMemoryStore(meta map[string][]byte) *MemoryStore {
+	var consistent = make(map[string][]byte)
 	if meta == nil {
 		meta = make(map[string][]byte)
+	} else {
+		// add all seed meta to consistent
+		for name, data := range meta {
+			checksum := sha256.Sum256(data)
+			path := utils.ConsistentName(name, checksum[:])
+			consistent[path] = data
+		}
 	}
-	if files == nil {
-		files = make(map[string][]byte)
-	}
-	return &memoryStore{
-		meta:  meta,
-		files: files,
-		keys:  make(map[string][]data.PrivateKey),
+	return &MemoryStore{
+		meta:       meta,
+		consistent: consistent,
+		keys:       make(map[string][]data.PrivateKey),
 	}
 }
 
-type memoryStore struct {
-	meta  map[string][]byte
-	files map[string][]byte
-	keys  map[string][]data.PrivateKey
+// MemoryStore implements a mock RemoteStore entirely in memory.
+// For testing purposes only.
+type MemoryStore struct {
+	meta       map[string][]byte
+	consistent map[string][]byte
+	keys       map[string][]data.PrivateKey
 }
 
-func (m *memoryStore) GetMeta(name string, size int64) ([]byte, error) {
+// GetMeta returns up to size bytes of data references by name.
+// If size is -1, this corresponds to "infinite," but we cut off at 100MB
+// as we will always know the size for everything but a timestamp and
+// sometimes a root, neither of which should be exceptionally large
+func (m *MemoryStore) GetMeta(name string, size int64) ([]byte, error) {
 	d, ok := m.meta[name]
+	if ok {
+		if size == -1 {
+			size = notary.MaxDownloadSize
+		}
+		if int64(len(d)) < size {
+			return d, nil
+		}
+		return d[:size], nil
+	}
+	d, ok = m.consistent[name]
 	if ok {
 		if int64(len(d)) < size {
 			return d, nil
@@ -42,12 +63,19 @@ func (m *memoryStore) GetMeta(name string, size int64) ([]byte, error) {
 	return nil, ErrMetaNotFound{Resource: name}
 }
 
-func (m *memoryStore) SetMeta(name string, meta []byte) error {
+// SetMeta sets the metadata value for the given name
+func (m *MemoryStore) SetMeta(name string, meta []byte) error {
 	m.meta[name] = meta
+
+	checksum := sha256.Sum256(meta)
+	path := utils.ConsistentName(name, checksum[:])
+	m.consistent[path] = meta
 	return nil
 }
 
-func (m *memoryStore) SetMultiMeta(metas map[string][]byte) error {
+// SetMultiMeta sets multiple pieces of metadata for multiple names
+// in a single operation.
+func (m *MemoryStore) SetMultiMeta(metas map[string][]byte) error {
 	for role, blob := range metas {
 		m.SetMeta(role, blob)
 	}
@@ -56,57 +84,23 @@ func (m *memoryStore) SetMultiMeta(metas map[string][]byte) error {
 
 // RemoveMeta removes the metadata for a single role - if the metadata doesn't
 // exist, no error is returned
-func (m *memoryStore) RemoveMeta(name string) error {
-	delete(m.meta, name)
-	return nil
-}
-
-func (m *memoryStore) GetTarget(path string) (io.ReadCloser, error) {
-	return &utils.NoopCloser{Reader: bytes.NewReader(m.files[path])}, nil
-}
-
-func (m *memoryStore) WalkStagedTargets(paths []string, targetsFn targetsWalkFunc) error {
-	if len(paths) == 0 {
-		for path, dat := range m.files {
-			meta, err := data.NewFileMeta(bytes.NewReader(dat), "sha256")
-			if err != nil {
-				return err
-			}
-			if err = targetsFn(path, meta); err != nil {
-				return err
-			}
-		}
-		return nil
-	}
-
-	for _, path := range paths {
-		dat, ok := m.files[path]
-		if !ok {
-			return ErrMetaNotFound{Resource: path}
-		}
-		meta, err := data.NewFileMeta(bytes.NewReader(dat), "sha256")
-		if err != nil {
-			return err
-		}
-		if err = targetsFn(path, meta); err != nil {
-			return err
-		}
+func (m *MemoryStore) RemoveMeta(name string) error {
+	if meta, ok := m.meta[name]; ok {
+		checksum := sha256.Sum256(meta)
+		path := utils.ConsistentName(name, checksum[:])
+		delete(m.meta, name)
+		delete(m.consistent, path)
 	}
 	return nil
 }
 
-func (m *memoryStore) Commit(map[string][]byte, bool, map[string]data.Hashes) error {
-	return nil
-}
-
-func (m *memoryStore) GetKey(role string) ([]byte, error) {
-	return nil, fmt.Errorf("GetKey is not implemented for the memoryStore")
+// GetKey returns the public key for the given role
+func (m *MemoryStore) GetKey(role string) ([]byte, error) {
+	return nil, fmt.Errorf("GetKey is not implemented for the MemoryStore")
 }
 
-// Clear this existing memory store by setting this store as new empty one
-func (m *memoryStore) RemoveAll() error {
-	m.meta = make(map[string][]byte)
-	m.files = make(map[string][]byte)
-	m.keys = make(map[string][]data.PrivateKey)
+// RemoveAll clears the existing memory store by setting this store as new empty one
+func (m *MemoryStore) RemoveAll() error {
+	*m = *NewMemoryStore(nil)
 	return nil
 }
diff --git a/vendor/src/github.com/docker/notary/tuf/tuf.go b/vendor/src/github.com/docker/notary/tuf/tuf.go
index 96ab7da1d636d..0a1912a5f5fb8 100644
--- a/vendor/src/github.com/docker/notary/tuf/tuf.go
+++ b/vendor/src/github.com/docker/notary/tuf/tuf.go
@@ -3,8 +3,6 @@ package tuf
 
 import (
 	"bytes"
-	"crypto/sha256"
-	"encoding/hex"
 	"encoding/json"
 	"fmt"
 	"path"
@@ -12,8 +10,8 @@ import (
 	"time"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/notary"
 	"github.com/docker/notary/tuf/data"
-	"github.com/docker/notary/tuf/keys"
 	"github.com/docker/notary/tuf/signed"
 	"github.com/docker/notary/tuf/utils"
 )
@@ -40,15 +38,19 @@ func (e ErrLocalRootExpired) Error() string {
 }
 
 // ErrNotLoaded - attempted to access data that has not been loaded into
-// the repo
+// the repo. This means specifically that the relevant JSON file has not
+// been loaded.
 type ErrNotLoaded struct {
-	role string
+	Role string
 }
 
 func (err ErrNotLoaded) Error() string {
-	return fmt.Sprintf("%s role has not been loaded", err.role)
+	return fmt.Sprintf("%s role has not been loaded", err.Role)
 }
 
+// StopWalk - used by visitor functions to signal WalkTargets to stop walking
+type StopWalk struct{}
+
 // Repo is an in memory representation of the TUF Repo.
 // It operates at the data.Signed level, accepting and producing
 // data.Signed objects. Users of a Repo are responsible for
@@ -59,16 +61,15 @@ type Repo struct {
 	Targets       map[string]*data.SignedTargets
 	Snapshot      *data.SignedSnapshot
 	Timestamp     *data.SignedTimestamp
-	keysDB        *keys.KeyDB
 	cryptoService signed.CryptoService
 }
 
-// NewRepo initializes a Repo instance with a keysDB and a signer.
-// If the Repo will only be used for reading, the signer should be nil.
-func NewRepo(keysDB *keys.KeyDB, cryptoService signed.CryptoService) *Repo {
+// NewRepo initializes a Repo instance with a CryptoService.
+// If the Repo will only be used for reading, the CryptoService
+// can be nil.
+func NewRepo(cryptoService signed.CryptoService) *Repo {
 	repo := &Repo{
 		Targets:       make(map[string]*data.SignedTargets),
-		keysDB:        keysDB,
 		cryptoService: cryptoService,
 	}
 	return repo
@@ -77,27 +78,15 @@ func NewRepo(keysDB *keys.KeyDB, cryptoService signed.CryptoService) *Repo {
 // AddBaseKeys is used to add keys to the role in root.json
 func (tr *Repo) AddBaseKeys(role string, keys ...data.PublicKey) error {
 	if tr.Root == nil {
-		return ErrNotLoaded{role: "root"}
+		return ErrNotLoaded{Role: data.CanonicalRootRole}
 	}
 	ids := []string{}
 	for _, k := range keys {
 		// Store only the public portion
 		tr.Root.Signed.Keys[k.ID()] = k
-		tr.keysDB.AddKey(k)
 		tr.Root.Signed.Roles[role].KeyIDs = append(tr.Root.Signed.Roles[role].KeyIDs, k.ID())
 		ids = append(ids, k.ID())
 	}
-	r, err := data.NewRole(
-		role,
-		tr.Root.Signed.Roles[role].Threshold,
-		ids,
-		nil,
-		nil,
-	)
-	if err != nil {
-		return err
-	}
-	tr.keysDB.AddRole(r)
 	tr.Root.Dirty = true
 
 	// also, whichever role was switched out needs to be re-signed
@@ -121,8 +110,11 @@ func (tr *Repo) AddBaseKeys(role string, keys ...data.PublicKey) error {
 
 // ReplaceBaseKeys is used to replace all keys for the given role with the new keys
 func (tr *Repo) ReplaceBaseKeys(role string, keys ...data.PublicKey) error {
-	r := tr.keysDB.GetRole(role)
-	err := tr.RemoveBaseKeys(role, r.KeyIDs...)
+	r, err := tr.GetBaseRole(role)
+	if err != nil {
+		return err
+	}
+	err = tr.RemoveBaseKeys(role, r.ListKeyIDs()...)
 	if err != nil {
 		return err
 	}
@@ -132,7 +124,7 @@ func (tr *Repo) ReplaceBaseKeys(role string, keys ...data.PublicKey) error {
 // RemoveBaseKeys is used to remove keys from the roles in root.json
 func (tr *Repo) RemoveBaseKeys(role string, keyIDs ...string) error {
 	if tr.Root == nil {
-		return ErrNotLoaded{role: "root"}
+		return ErrNotLoaded{Role: data.CanonicalRootRole}
 	}
 	var keep []string
 	toDelete := make(map[string]struct{})
@@ -173,117 +165,253 @@ func (tr *Repo) RemoveBaseKeys(role string, keyIDs ...string) error {
 	return nil
 }
 
-// GetAllLoadedRoles returns a list of all role entries loaded in this TUF repo, could be empty
-func (tr *Repo) GetAllLoadedRoles() []*data.Role {
-	return tr.keysDB.GetAllRoles()
+// GetBaseRole gets a base role from this repo's metadata
+func (tr *Repo) GetBaseRole(name string) (data.BaseRole, error) {
+	if !data.ValidRole(name) {
+		return data.BaseRole{}, data.ErrInvalidRole{Role: name, Reason: "invalid base role name"}
+	}
+	if tr.Root == nil {
+		return data.BaseRole{}, ErrNotLoaded{data.CanonicalRootRole}
+	}
+	// Find the role data public keys for the base role from TUF metadata
+	baseRole, err := tr.Root.BuildBaseRole(name)
+	if err != nil {
+		return data.BaseRole{}, err
+	}
+
+	return baseRole, nil
 }
 
-// GetDelegation finds the role entry representing the provided
-// role name or ErrInvalidRole
-func (tr *Repo) GetDelegation(role string) (*data.Role, error) {
-	r := data.Role{Name: role}
-	if !r.IsDelegation() {
-		return nil, data.ErrInvalidRole{Role: role, Reason: "not a valid delegated role"}
+// GetDelegationRole gets a delegation role from this repo's metadata, walking from the targets role down to the delegation itself
+func (tr *Repo) GetDelegationRole(name string) (data.DelegationRole, error) {
+	if !data.IsDelegation(name) {
+		return data.DelegationRole{}, data.ErrInvalidRole{Role: name, Reason: "invalid delegation name"}
+	}
+	if tr.Root == nil {
+		return data.DelegationRole{}, ErrNotLoaded{data.CanonicalRootRole}
+	}
+	_, ok := tr.Root.Signed.Roles[data.CanonicalTargetsRole]
+	if !ok {
+		return data.DelegationRole{}, ErrNotLoaded{data.CanonicalTargetsRole}
+	}
+	// Traverse target metadata, down to delegation itself
+	// Get all public keys for the base role from TUF metadata
+	_, ok = tr.Targets[data.CanonicalTargetsRole]
+	if !ok {
+		return data.DelegationRole{}, ErrNotLoaded{data.CanonicalTargetsRole}
+	}
+
+	// Start with top level roles in targets. Walk the chain of ancestors
+	// until finding the desired role, or we run out of targets files to search.
+	var foundRole *data.DelegationRole
+	buildDelegationRoleVisitor := func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} {
+		// Try to find the delegation and build a DelegationRole structure
+		for _, role := range tgt.Signed.Delegations.Roles {
+			if role.Name == name {
+				delgRole, err := tgt.BuildDelegationRole(name)
+				if err != nil {
+					return err
+				}
+				foundRole = &delgRole
+				return StopWalk{}
+			}
+		}
+		return nil
 	}
 
-	parent := path.Dir(role)
+	// Walk to the parent of this delegation, since that is where its role metadata exists
+	err := tr.WalkTargets("", path.Dir(name), buildDelegationRoleVisitor)
+	if err != nil {
+		return data.DelegationRole{}, err
+	}
 
-	// check the parent role
-	if parentRole := tr.keysDB.GetRole(parent); parentRole == nil {
-		return nil, data.ErrInvalidRole{Role: role, Reason: "parent role not found"}
+	// We never found the delegation. In the context of this repo it is considered
+	// invalid. N.B. it may be that it existed at one point but an ancestor has since
+	// been modified/removed.
+	if foundRole == nil {
+		return data.DelegationRole{}, data.ErrInvalidRole{Role: name, Reason: "delegation does not exist"}
 	}
 
-	// check the parent role's metadata
-	p, ok := tr.Targets[parent]
-	if !ok { // the parent targetfile may not exist yet, so it can't be in the list
-		return nil, data.ErrNoSuchRole{Role: role}
+	return *foundRole, nil
+}
+
+// GetAllLoadedRoles returns a list of all role entries loaded in this TUF repo, could be empty
+func (tr *Repo) GetAllLoadedRoles() []*data.Role {
+	var res []*data.Role
+	if tr.Root == nil {
+		// if root isn't loaded, we should consider we have no loaded roles because we can't
+		// trust any other state that might be present
+		return res
+	}
+	for name, rr := range tr.Root.Signed.Roles {
+		res = append(res, &data.Role{
+			RootRole: *rr,
+			Name:     name,
+		})
+	}
+	for _, delegate := range tr.Targets {
+		for _, r := range delegate.Signed.Delegations.Roles {
+			res = append(res, r)
+		}
 	}
+	return res
+}
 
-	foundAt := utils.FindRoleIndex(p.Signed.Delegations.Roles, role)
-	if foundAt < 0 {
-		return nil, data.ErrNoSuchRole{Role: role}
+// Walk to parent, and either create or update this delegation.  We can only create a new delegation if we're given keys
+// Ensure all updates are valid, by checking against parent ancestor paths and ensuring the keys meet the role threshold.
+func delegationUpdateVisitor(roleName string, addKeys data.KeyList, removeKeys, addPaths, removePaths []string, clearAllPaths bool, newThreshold int) walkVisitorFunc {
+	return func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} {
+		var err error
+		// Validate the changes underneath this restricted validRole for adding paths, reject invalid path additions
+		if len(addPaths) != len(data.RestrictDelegationPathPrefixes(validRole.Paths, addPaths)) {
+			return data.ErrInvalidRole{Role: roleName, Reason: "invalid paths to add to role"}
+		}
+		// Try to find the delegation and amend it using our changelist
+		var delgRole *data.Role
+		for _, role := range tgt.Signed.Delegations.Roles {
+			if role.Name == roleName {
+				// Make a copy and operate on this role until we validate the changes
+				keyIDCopy := make([]string, len(role.KeyIDs))
+				copy(keyIDCopy, role.KeyIDs)
+				pathsCopy := make([]string, len(role.Paths))
+				copy(pathsCopy, role.Paths)
+				delgRole = &data.Role{
+					RootRole: data.RootRole{
+						KeyIDs:    keyIDCopy,
+						Threshold: role.Threshold,
+					},
+					Name:  role.Name,
+					Paths: pathsCopy,
+				}
+				delgRole.RemovePaths(removePaths)
+				if clearAllPaths {
+					delgRole.Paths = []string{}
+				}
+				delgRole.AddPaths(addPaths)
+				delgRole.RemoveKeys(removeKeys)
+				break
+			}
+		}
+		// We didn't find the role earlier, so create it only if we have keys to add
+		if delgRole == nil {
+			if len(addKeys) > 0 {
+				delgRole, err = data.NewRole(roleName, newThreshold, addKeys.IDs(), addPaths)
+				if err != nil {
+					return err
+				}
+			} else {
+				// If we can't find the role and didn't specify keys to add, this is an error
+				return data.ErrInvalidRole{Role: roleName, Reason: "cannot create new delegation without keys"}
+			}
+		}
+		// Add the key IDs to the role and the keys themselves to the parent
+		for _, k := range addKeys {
+			if !utils.StrSliceContains(delgRole.KeyIDs, k.ID()) {
+				delgRole.KeyIDs = append(delgRole.KeyIDs, k.ID())
+			}
+		}
+		// Make sure we have a valid role still
+		if len(delgRole.KeyIDs) < delgRole.Threshold {
+			return data.ErrInvalidRole{Role: roleName, Reason: "insufficient keys to meet threshold"}
+		}
+		// NOTE: this closure CANNOT error after this point, as we've committed to editing the SignedTargets metadata in the repo object.
+		// Any errors related to updating this delegation must occur before this point.
+		// If all of our changes were valid, we should edit the actual SignedTargets to match our copy
+		for _, k := range addKeys {
+			tgt.Signed.Delegations.Keys[k.ID()] = k
+		}
+		foundAt := utils.FindRoleIndex(tgt.Signed.Delegations.Roles, delgRole.Name)
+		if foundAt < 0 {
+			tgt.Signed.Delegations.Roles = append(tgt.Signed.Delegations.Roles, delgRole)
+		} else {
+			tgt.Signed.Delegations.Roles[foundAt] = delgRole
+		}
+		tgt.Dirty = true
+		utils.RemoveUnusedKeys(tgt)
+		return StopWalk{}
 	}
-	return p.Signed.Delegations.Roles[foundAt], nil
 }
 
-// UpdateDelegations updates the appropriate delegations, either adding
+// UpdateDelegationKeys updates the appropriate delegations, either adding
 // a new delegation or updating an existing one. If keys are
 // provided, the IDs will be added to the role (if they do not exist
 // there already), and the keys will be added to the targets file.
-func (tr *Repo) UpdateDelegations(role *data.Role, keys []data.PublicKey) error {
-	if !role.IsDelegation() || !role.IsValid() {
-		return data.ErrInvalidRole{Role: role.Name, Reason: "not a valid delegated role"}
+func (tr *Repo) UpdateDelegationKeys(roleName string, addKeys data.KeyList, removeKeys []string, newThreshold int) error {
+	if !data.IsDelegation(roleName) {
+		return data.ErrInvalidRole{Role: roleName, Reason: "not a valid delegated role"}
 	}
-	parent := path.Dir(role.Name)
+	parent := path.Dir(roleName)
 
 	if err := tr.VerifyCanSign(parent); err != nil {
 		return err
 	}
 
 	// check the parent role's metadata
-	p, ok := tr.Targets[parent]
+	_, ok := tr.Targets[parent]
 	if !ok { // the parent targetfile may not exist yet - if not, then create it
 		var err error
-		p, err = tr.InitTargets(parent)
+		_, err = tr.InitTargets(parent)
 		if err != nil {
 			return err
 		}
 	}
 
-	for _, k := range keys {
-		if !utils.StrSliceContains(role.KeyIDs, k.ID()) {
-			role.KeyIDs = append(role.KeyIDs, k.ID())
-		}
-		p.Signed.Delegations.Keys[k.ID()] = k
-		tr.keysDB.AddKey(k)
+	// Walk to the parent of this delegation, since that is where its role metadata exists
+	// We do not have to verify that the walker reached its desired role in this scenario
+	// since we've already done another walk to the parent role in VerifyCanSign, and potentially made a targets file
+	err := tr.WalkTargets("", parent, delegationUpdateVisitor(roleName, addKeys, removeKeys, []string{}, []string{}, false, newThreshold))
+	if err != nil {
+		return err
 	}
+	return nil
+}
 
-	// if the role has fewer keys than the threshold, it
-	// will never be able to create a valid targets file
-	// and should be considered invalid.
-	if len(role.KeyIDs) < role.Threshold {
-		return data.ErrInvalidRole{Role: role.Name, Reason: "insufficient keys to meet threshold"}
+// UpdateDelegationPaths updates the appropriate delegation's paths.
+// It is not allowed to create a new delegation.
+func (tr *Repo) UpdateDelegationPaths(roleName string, addPaths, removePaths []string, clearPaths bool) error {
+	if !data.IsDelegation(roleName) {
+		return data.ErrInvalidRole{Role: roleName, Reason: "not a valid delegated role"}
 	}
+	parent := path.Dir(roleName)
 
-	foundAt := utils.FindRoleIndex(p.Signed.Delegations.Roles, role.Name)
-
-	if foundAt >= 0 {
-		p.Signed.Delegations.Roles[foundAt] = role
-	} else {
-		p.Signed.Delegations.Roles = append(p.Signed.Delegations.Roles, role)
+	if err := tr.VerifyCanSign(parent); err != nil {
+		return err
 	}
-	// We've made a change to parent. Set it to dirty
-	p.Dirty = true
-
-	// We don't actually want to create the new delegation metadata yet.
-	// When we add a delegation, it may only be signable by a key we don't have
-	// (hence we are delegating signing).
 
-	tr.keysDB.AddRole(role)
-	utils.RemoveUnusedKeys(p)
+	// check the parent role's metadata
+	_, ok := tr.Targets[parent]
+	if !ok { // the parent targetfile may not exist yet
+		// if not, this is an error because a delegation must exist to edit only paths
+		return data.ErrInvalidRole{Role: roleName, Reason: "no valid delegated role exists"}
+	}
 
+	// Walk to the parent of this delegation, since that is where its role metadata exists
+	// We do not have to verify that the walker reached its desired role in this scenario
+	// since we've already done another walk to the parent role in VerifyCanSign
+	err := tr.WalkTargets("", parent, delegationUpdateVisitor(roleName, data.KeyList{}, []string{}, addPaths, removePaths, clearPaths, notary.MinThreshold))
+	if err != nil {
+		return err
+	}
 	return nil
 }
 
 // DeleteDelegation removes a delegated targets role from its parent
 // targets object. It also deletes the delegation from the snapshot.
 // DeleteDelegation will only make use of the role Name field.
-func (tr *Repo) DeleteDelegation(role data.Role) error {
-	if !role.IsDelegation() {
-		return data.ErrInvalidRole{Role: role.Name, Reason: "not a valid delegated role"}
+func (tr *Repo) DeleteDelegation(roleName string) error {
+	if !data.IsDelegation(roleName) {
+		return data.ErrInvalidRole{Role: roleName, Reason: "not a valid delegated role"}
 	}
-	// the role variable must not be used past this assignment for safety
-	name := role.Name
 
-	parent := path.Dir(name)
+	parent := path.Dir(roleName)
 	if err := tr.VerifyCanSign(parent); err != nil {
 		return err
 	}
 
 	// delete delegated data from Targets map and Snapshot - if they don't
 	// exist, these are no-op
-	delete(tr.Targets, name)
-	tr.Snapshot.DeleteMeta(name)
+	delete(tr.Targets, roleName)
+	tr.Snapshot.DeleteMeta(roleName)
 
 	p, ok := tr.Targets[parent]
 	if !ok {
@@ -292,7 +420,7 @@ func (tr *Repo) DeleteDelegation(role data.Role) error {
 		return nil
 	}
 
-	foundAt := utils.FindRoleIndex(p.Signed.Delegations.Roles, name)
+	foundAt := utils.FindRoleIndex(p.Signed.Delegations.Roles, roleName)
 
 	if foundAt >= 0 {
 		var roles []*data.Role
@@ -311,53 +439,32 @@ func (tr *Repo) DeleteDelegation(role data.Role) error {
 	return nil
 }
 
-// InitRepo creates the base files for a repo. It inspects data.BaseRoles and
-// data.ValidTypes to determine what the role names and filename should be. It
-// also relies on the keysDB having already been populated with the keys and
-// roles.
-func (tr *Repo) InitRepo(consistent bool) error {
-	if err := tr.InitRoot(consistent); err != nil {
-		return err
-	}
-	if _, err := tr.InitTargets(data.CanonicalTargetsRole); err != nil {
-		return err
-	}
-	if err := tr.InitSnapshot(); err != nil {
-		return err
-	}
-	return tr.InitTimestamp()
-}
-
-// InitRoot initializes an empty root file with the 4 core roles based
-// on the current content of th ekey db
-func (tr *Repo) InitRoot(consistent bool) error {
+// InitRoot initializes an empty root file with the 4 core roles passed to the
+// method, and the consistent flag.
+func (tr *Repo) InitRoot(root, timestamp, snapshot, targets data.BaseRole, consistent bool) error {
 	rootRoles := make(map[string]*data.RootRole)
 	rootKeys := make(map[string]data.PublicKey)
-	for _, r := range data.BaseRoles {
-		role := tr.keysDB.GetRole(r)
-		if role == nil {
-			return data.ErrInvalidRole{Role: data.CanonicalRootRole, Reason: "root role not initialized in key database"}
+
+	for _, r := range []data.BaseRole{root, timestamp, snapshot, targets} {
+		rootRoles[r.Name] = &data.RootRole{
+			Threshold: r.Threshold,
+			KeyIDs:    r.ListKeyIDs(),
 		}
-		rootRoles[r] = &role.RootRole
-		for _, kid := range role.KeyIDs {
-			// don't need to check if GetKey returns nil, Key presence was
-			// checked by KeyDB when role was added.
-			key := tr.keysDB.GetKey(kid)
-			rootKeys[kid] = key
+		for kid, k := range r.Keys {
+			rootKeys[kid] = k
 		}
 	}
-	root, err := data.NewRoot(rootKeys, rootRoles, consistent)
+	r, err := data.NewRoot(rootKeys, rootRoles, consistent)
 	if err != nil {
 		return err
 	}
-	tr.Root = root
+	tr.Root = r
 	return nil
 }
 
 // InitTargets initializes an empty targets, and returns the new empty target
 func (tr *Repo) InitTargets(role string) (*data.SignedTargets, error) {
-	r := data.Role{Name: role}
-	if !r.IsDelegation() && role != data.CanonicalTargetsRole {
+	if !data.IsDelegation(role) && role != data.CanonicalTargetsRole {
 		return nil, data.ErrInvalidRole{
 			Role:   role,
 			Reason: fmt.Sprintf("role is not a valid targets role name: %s", role),
@@ -371,7 +478,7 @@ func (tr *Repo) InitTargets(role string) (*data.SignedTargets, error) {
 // InitSnapshot initializes a snapshot based on the current root and targets
 func (tr *Repo) InitSnapshot() error {
 	if tr.Root == nil {
-		return ErrNotLoaded{role: "root"}
+		return ErrNotLoaded{Role: data.CanonicalRootRole}
 	}
 	root, err := tr.Root.ToSigned()
 	if err != nil {
@@ -379,7 +486,7 @@ func (tr *Repo) InitSnapshot() error {
 	}
 
 	if _, ok := tr.Targets[data.CanonicalTargetsRole]; !ok {
-		return ErrNotLoaded{role: "targets"}
+		return ErrNotLoaded{Role: data.CanonicalTargetsRole}
 	}
 	targets, err := tr.Targets[data.CanonicalTargetsRole].ToSigned()
 	if err != nil {
@@ -408,31 +515,8 @@ func (tr *Repo) InitTimestamp() error {
 	return nil
 }
 
-// SetRoot parses the Signed object into a SignedRoot object, sets
-// the keys and roles in the KeyDB, and sets the Repo.Root field
-// to the SignedRoot object.
+// SetRoot sets the Repo.Root field to the SignedRoot object.
 func (tr *Repo) SetRoot(s *data.SignedRoot) error {
-	for _, key := range s.Signed.Keys {
-		logrus.Debug("Adding key ", key.ID())
-		tr.keysDB.AddKey(key)
-	}
-	for roleName, role := range s.Signed.Roles {
-		logrus.Debugf("Adding role %s with keys %s", roleName, strings.Join(role.KeyIDs, ","))
-		baseRole, err := data.NewRole(
-			roleName,
-			role.Threshold,
-			role.KeyIDs,
-			nil,
-			nil,
-		)
-		if err != nil {
-			return err
-		}
-		err = tr.keysDB.AddRole(baseRole)
-		if err != nil {
-			return err
-		}
-	}
 	tr.Root = s
 	return nil
 }
@@ -451,16 +535,9 @@ func (tr *Repo) SetSnapshot(s *data.SignedSnapshot) error {
 	return nil
 }
 
-// SetTargets parses the Signed object into a SignedTargets object,
-// reads the delegated roles and keys into the KeyDB, and sets the
-// SignedTargets object agaist the role in the Repo.Targets map.
+// SetTargets sets the SignedTargets object agaist the role in the
+// Repo.Targets map.
 func (tr *Repo) SetTargets(role string, s *data.SignedTargets) error {
-	for _, k := range s.Signed.Delegations.Keys {
-		tr.keysDB.AddKey(k)
-	}
-	for _, r := range s.Signed.Delegations.Roles {
-		tr.keysDB.AddRole(r)
-	}
 	tr.Targets[role] = s
 	return nil
 }
@@ -479,15 +556,11 @@ func (tr Repo) TargetMeta(role, path string) *data.FileMeta {
 
 // TargetDelegations returns a slice of Roles that are valid publishers
 // for the target path provided.
-func (tr Repo) TargetDelegations(role, path, pathHex string) []*data.Role {
-	if pathHex == "" {
-		pathDigest := sha256.Sum256([]byte(path))
-		pathHex = hex.EncodeToString(pathDigest[:])
-	}
+func (tr Repo) TargetDelegations(role, path string) []*data.Role {
 	var roles []*data.Role
 	if t, ok := tr.Targets[role]; ok {
 		for _, r := range t.Signed.Delegations.Roles {
-			if r.CheckPrefixes(pathHex) || r.CheckPaths(path) {
+			if r.CheckPaths(path) {
 				roles = append(roles, r)
 			}
 		}
@@ -495,50 +568,34 @@ func (tr Repo) TargetDelegations(role, path, pathHex string) []*data.Role {
 	return roles
 }
 
-// FindTarget attempts to find the target represented by the given
-// path by starting at the top targets file and traversing
-// appropriate delegations until the first entry is found or it
-// runs out of locations to search.
-// N.B. Multiple entries may exist in different delegated roles
-//      for the same target. Only the first one encountered is returned.
-func (tr Repo) FindTarget(path string) *data.FileMeta {
-	pathDigest := sha256.Sum256([]byte(path))
-	pathHex := hex.EncodeToString(pathDigest[:])
-
-	var walkTargets func(role string) *data.FileMeta
-	walkTargets = func(role string) *data.FileMeta {
-		if m := tr.TargetMeta(role, path); m != nil {
-			return m
-		}
-		// Depth first search of delegations based on order
-		// as presented in current targets file for role:
-		for _, r := range tr.TargetDelegations(role, path, pathHex) {
-			if m := walkTargets(r.Name); m != nil {
-				return m
-			}
-		}
-		return nil
-	}
-
-	return walkTargets("targets")
-}
-
 // VerifyCanSign returns nil if the role exists and we have at least one
 // signing key for the role, false otherwise.  This does not check that we have
 // enough signing keys to meet the threshold, since we want to support the use
 // case of multiple signers for a role.  It returns an error if the role doesn't
 // exist or if there are no signing keys.
 func (tr *Repo) VerifyCanSign(roleName string) error {
-	role := tr.keysDB.GetRole(roleName)
-	if role == nil {
+	var (
+		role data.BaseRole
+		err  error
+	)
+	// we only need the BaseRole part of a delegation because we're just
+	// checking KeyIDs
+	if data.IsDelegation(roleName) {
+		r, err := tr.GetDelegationRole(roleName)
+		if err != nil {
+			return err
+		}
+		role = r.BaseRole
+	} else {
+		role, err = tr.GetBaseRole(roleName)
+	}
+	if err != nil {
 		return data.ErrInvalidRole{Role: roleName, Reason: "does not exist"}
 	}
 
-	for _, keyID := range role.KeyIDs {
-		k := tr.keysDB.GetKey(keyID)
-		canonicalID, err := utils.CanonicalKeyID(k)
+	for keyID, k := range role.Keys {
 		check := []string{keyID}
-		if err == nil {
+		if canonicalID, err := utils.CanonicalKeyID(k); err == nil {
 			check = append(check, canonicalID)
 		}
 		for _, id := range check {
@@ -548,45 +605,123 @@ func (tr *Repo) VerifyCanSign(roleName string) error {
 			}
 		}
 	}
-	return signed.ErrNoKeys{KeyIDs: role.KeyIDs}
+	return signed.ErrNoKeys{KeyIDs: role.ListKeyIDs()}
+}
+
+// used for walking the targets/delegations tree, potentially modifying the underlying SignedTargets for the repo
+type walkVisitorFunc func(*data.SignedTargets, data.DelegationRole) interface{}
+
+// WalkTargets will apply the specified visitor function to iteratively walk the targets/delegation metadata tree,
+// until receiving a StopWalk.  The walk starts from the base "targets" role, and searches for the correct targetPath and/or rolePath
+// to call the visitor function on.  Any roles passed into skipRoles will be excluded from the walk, as well as roles in those subtrees
+func (tr *Repo) WalkTargets(targetPath, rolePath string, visitTargets walkVisitorFunc, skipRoles ...string) error {
+	// Start with the base targets role, which implicitly has the "" targets path
+	targetsRole, err := tr.GetBaseRole(data.CanonicalTargetsRole)
+	if err != nil {
+		return err
+	}
+	// Make the targets role have the empty path, when we treat it as a delegation role
+	roles := []data.DelegationRole{
+		{
+			BaseRole: targetsRole,
+			Paths:    []string{""},
+		},
+	}
+
+	for len(roles) > 0 {
+		role := roles[0]
+		roles = roles[1:]
+
+		// Check the role metadata
+		signedTgt, ok := tr.Targets[role.Name]
+		if !ok {
+			// The role meta doesn't exist in the repo so continue onward
+			continue
+		}
+
+		// We're at a prefix of the desired role subtree, so add its delegation role children and continue walking
+		if strings.HasPrefix(rolePath, role.Name+"/") {
+			roles = append(roles, signedTgt.GetValidDelegations(role)...)
+			continue
+		}
+
+		// Determine whether to visit this role or not:
+		// If the paths validate against the specified targetPath and the rolePath is empty or is in the subtree
+		// Also check if we are choosing to skip visiting this role on this walk (see ListTargets and GetTargetByName priority)
+		if isValidPath(targetPath, role) && isAncestorRole(role.Name, rolePath) && !utils.StrSliceContains(skipRoles, role.Name) {
+			// If we had matching path or role name, visit this target and determine whether or not to keep walking
+			res := visitTargets(signedTgt, role)
+			switch typedRes := res.(type) {
+			case StopWalk:
+				// If the visitor function signalled a stop, return nil to finish the walk
+				return nil
+			case nil:
+				// If the visitor function signalled to continue, add this role's delegation to the walk
+				roles = append(roles, signedTgt.GetValidDelegations(role)...)
+			case error:
+				// Propagate any errors from the visitor
+				return typedRes
+			default:
+				// Return out with an error if we got a different result
+				return fmt.Errorf("unexpected return while walking: %v", res)
+			}
+
+		}
+	}
+	return nil
+}
+
+// helper function that returns whether the candidateChild role name is an ancestor or equal to the candidateAncestor role name
+// Will return true if given an empty candidateAncestor role name
+// The HasPrefix check is for determining whether the role name for candidateChild is a child (direct or further down the chain)
+// of candidateAncestor, for ex: candidateAncestor targets/a and candidateChild targets/a/b/c
+func isAncestorRole(candidateChild, candidateAncestor string) bool {
+	return candidateAncestor == "" || candidateAncestor == candidateChild || strings.HasPrefix(candidateChild, candidateAncestor+"/")
+}
+
+// helper function that returns whether the delegation Role is valid against the given path
+// Will return true if given an empty candidatePath
+func isValidPath(candidatePath string, delgRole data.DelegationRole) bool {
+	return candidatePath == "" || delgRole.CheckPaths(candidatePath)
 }
 
 // AddTargets will attempt to add the given targets specifically to
 // the directed role. If the metadata for the role doesn't exist yet,
 // AddTargets will create one.
 func (tr *Repo) AddTargets(role string, targets data.Files) (data.Files, error) {
-
 	err := tr.VerifyCanSign(role)
 	if err != nil {
 		return nil, err
 	}
 
-	// check the role's metadata
-	t, ok := tr.Targets[role]
+	// check existence of the role's metadata
+	_, ok := tr.Targets[role]
 	if !ok { // the targetfile may not exist yet - if not, then create it
 		var err error
-		t, err = tr.InitTargets(role)
+		_, err = tr.InitTargets(role)
 		if err != nil {
 			return nil, err
 		}
 	}
 
-	// VerifyCanSign already makes sure this is not nil
-	r := tr.keysDB.GetRole(role)
+	addedTargets := make(data.Files)
+	addTargetVisitor := func(targetPath string, targetMeta data.FileMeta) func(*data.SignedTargets, data.DelegationRole) interface{} {
+		return func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} {
+			// We've already validated the role's target path in our walk, so just modify the metadata
+			tgt.Signed.Targets[targetPath] = targetMeta
+			tgt.Dirty = true
+			// Also add to our new addedTargets map to keep track of every target we've added successfully
+			addedTargets[targetPath] = targetMeta
+			return StopWalk{}
+		}
+	}
 
-	invalid := make(data.Files)
+	// Walk the role tree while validating the target paths, and add all of our targets
 	for path, target := range targets {
-		pathDigest := sha256.Sum256([]byte(path))
-		pathHex := hex.EncodeToString(pathDigest[:])
-		if role == data.CanonicalTargetsRole || (r.CheckPaths(path) || r.CheckPrefixes(pathHex)) {
-			t.Signed.Targets[path] = target
-		} else {
-			invalid[path] = target
-		}
+		tr.WalkTargets(path, role, addTargetVisitor(path, target))
 	}
-	t.Dirty = true
-	if len(invalid) > 0 {
-		return invalid, fmt.Errorf("Could not add all targets")
+	if len(addedTargets) != len(targets) {
+		return nil, fmt.Errorf("Could not add all targets")
 	}
 	return nil, nil
 }
@@ -597,13 +732,23 @@ func (tr *Repo) RemoveTargets(role string, targets ...string) error {
 		return err
 	}
 
+	removeTargetVisitor := func(targetPath string) func(*data.SignedTargets, data.DelegationRole) interface{} {
+		return func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} {
+			// We've already validated the role path in our walk, so just modify the metadata
+			// We don't check against the target path against the valid role paths because it's
+			// possible we got into an invalid state and are trying to fix it
+			delete(tgt.Signed.Targets, targetPath)
+			tgt.Dirty = true
+			return StopWalk{}
+		}
+	}
+
 	// if the role exists but metadata does not yet, then our work is done
-	t, ok := tr.Targets[role]
+	_, ok := tr.Targets[role]
 	if ok {
 		for _, path := range targets {
-			delete(t.Signed.Targets, path)
+			tr.WalkTargets("", role, removeTargetVisitor(path))
 		}
-		t.Dirty = true
 	}
 
 	return nil
@@ -644,12 +789,15 @@ func (tr *Repo) SignRoot(expires time.Time) (*data.Signed, error) {
 	logrus.Debug("signing root...")
 	tr.Root.Signed.Expires = expires
 	tr.Root.Signed.Version++
-	root := tr.keysDB.GetRole(data.CanonicalRootRole)
+	root, err := tr.GetBaseRole(data.CanonicalRootRole)
+	if err != nil {
+		return nil, err
+	}
 	signed, err := tr.Root.ToSigned()
 	if err != nil {
 		return nil, err
 	}
-	signed, err = tr.sign(signed, *root)
+	signed, err = tr.sign(signed, root)
 	if err != nil {
 		return nil, err
 	}
@@ -673,8 +821,22 @@ func (tr *Repo) SignTargets(role string, expires time.Time) (*data.Signed, error
 		logrus.Debug("errored getting targets data.Signed object")
 		return nil, err
 	}
-	targets := tr.keysDB.GetRole(role)
-	signed, err = tr.sign(signed, *targets)
+
+	var targets data.BaseRole
+	if role == data.CanonicalTargetsRole {
+		targets, err = tr.GetBaseRole(role)
+	} else {
+		tr, err := tr.GetDelegationRole(role)
+		if err != nil {
+			return nil, err
+		}
+		targets = tr.BaseRole
+	}
+	if err != nil {
+		return nil, err
+	}
+
+	signed, err = tr.sign(signed, targets)
 	if err != nil {
 		logrus.Debug("errored signing ", role)
 		return nil, err
@@ -712,8 +874,11 @@ func (tr *Repo) SignSnapshot(expires time.Time) (*data.Signed, error) {
 	if err != nil {
 		return nil, err
 	}
-	snapshot := tr.keysDB.GetRole(data.CanonicalSnapshotRole)
-	signed, err = tr.sign(signed, *snapshot)
+	snapshot, err := tr.GetBaseRole(data.CanonicalSnapshotRole)
+	if err != nil {
+		return nil, err
+	}
+	signed, err = tr.sign(signed, snapshot)
 	if err != nil {
 		return nil, err
 	}
@@ -738,8 +903,11 @@ func (tr *Repo) SignTimestamp(expires time.Time) (*data.Signed, error) {
 	if err != nil {
 		return nil, err
 	}
-	timestamp := tr.keysDB.GetRole(data.CanonicalTimestampRole)
-	signed, err = tr.sign(signed, *timestamp)
+	timestamp, err := tr.GetBaseRole(data.CanonicalTimestampRole)
+	if err != nil {
+		return nil, err
+	}
+	signed, err = tr.sign(signed, timestamp)
 	if err != nil {
 		return nil, err
 	}
@@ -748,17 +916,10 @@ func (tr *Repo) SignTimestamp(expires time.Time) (*data.Signed, error) {
 	return signed, nil
 }
 
-func (tr Repo) sign(signedData *data.Signed, role data.Role) (*data.Signed, error) {
-	ks := make([]data.PublicKey, 0, len(role.KeyIDs))
-	for _, kid := range role.KeyIDs {
-		k := tr.keysDB.GetKey(kid)
-		if k == nil {
-			continue
-		}
-		ks = append(ks, k)
-	}
+func (tr Repo) sign(signedData *data.Signed, role data.BaseRole) (*data.Signed, error) {
+	ks := role.ListKeys()
 	if len(ks) < 1 {
-		return nil, keys.ErrInvalidKey
+		return nil, signed.ErrNoKeys{}
 	}
 	err := signed.Sign(tr.cryptoService, signedData, ks...)
 	if err != nil {
diff --git a/vendor/src/github.com/docker/notary/tuf/utils/utils.go b/vendor/src/github.com/docker/notary/tuf/utils/utils.go
index c09019c2e5dcc..8190c5eccd09d 100644
--- a/vendor/src/github.com/docker/notary/tuf/utils/utils.go
+++ b/vendor/src/github.com/docker/notary/tuf/utils/utils.go
@@ -5,6 +5,7 @@ import (
 	"crypto/sha256"
 	"crypto/sha512"
 	"crypto/tls"
+	"encoding/hex"
 	"fmt"
 	"io"
 	"net/http"
@@ -61,6 +62,17 @@ func StrSliceContains(ss []string, s string) bool {
 	return false
 }
 
+// StrSliceRemove removes the the given string from the slice, returning a new slice
+func StrSliceRemove(ss []string, s string) []string {
+	res := []string{}
+	for _, v := range ss {
+		if v != s {
+			res = append(res, v)
+		}
+	}
+	return res
+}
+
 // StrSliceContainsI checks if the given string appears in the slice
 // in a case insensitive manner
 func StrSliceContainsI(ss []string, s string) bool {
@@ -146,3 +158,14 @@ func FindRoleIndex(rs []*data.Role, name string) int {
 	}
 	return -1
 }
+
+// ConsistentName generates the appropriate HTTP URL path for the role,
+// based on whether the repo is marked as consistent. The RemoteStore
+// is responsible for adding file extensions.
+func ConsistentName(role string, hashSha256 []byte) string {
+	if len(hashSha256) > 0 {
+		hash := hex.EncodeToString(hashSha256)
+		return fmt.Sprintf("%s.%s", role, hash)
+	}
+	return role
+}