diff --git a/graph/manifest_test.go b/graph/manifest_test.go index 2702dcaf56..63086f4d55 100644 --- a/graph/manifest_test.go +++ b/graph/manifest_test.go @@ -8,11 +8,13 @@ import ( "os" "testing" + "github.com/docker/distribution/digest" "github.com/docker/docker/image" "github.com/docker/docker/pkg/tarsum" "github.com/docker/docker/registry" "github.com/docker/docker/runconfig" "github.com/docker/docker/utils" + "github.com/docker/libtrust" ) const ( @@ -181,3 +183,121 @@ func TestManifestTarsumCache(t *testing.T) { t.Fatalf("Unexpected json value\nExpected:\n%s\nActual:\n%s", v1compat, manifest.History[0].V1Compatibility) } } + +// TestManifestDigestCheck ensures that loadManifest properly verifies the +// remote and local digest. +func TestManifestDigestCheck(t *testing.T) { + tmp, err := utils.TestDirectory("") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmp) + store := mkTestTagStore(tmp, t) + defer store.graph.driver.Cleanup() + + archive, err := fakeTar() + if err != nil { + t.Fatal(err) + } + img := &image.Image{ID: testManifestImageID} + if err := store.graph.Register(img, archive); err != nil { + t.Fatal(err) + } + if err := store.Tag(testManifestImageName, testManifestTag, testManifestImageID, false); err != nil { + t.Fatal(err) + } + + if cs, err := img.GetCheckSum(store.graph.ImageRoot(testManifestImageID)); err != nil { + t.Fatal(err) + } else if cs != "" { + t.Fatalf("Non-empty checksum file after register") + } + + // Generate manifest + payload, err := store.newManifest(testManifestImageName, testManifestImageName, testManifestTag) + if err != nil { + t.Fatalf("unexpected error generating test manifest: %v", err) + } + + pk, err := libtrust.GenerateECP256PrivateKey() + if err != nil { + t.Fatalf("unexpected error generating private key: %v", err) + } + + sig, err := libtrust.NewJSONSignature(payload) + if err != nil { + t.Fatalf("error creating signature: %v", err) + } + + if err := sig.Sign(pk); err != nil { + t.Fatalf("error signing manifest bytes: %v", err) + } + + signedBytes, err := sig.PrettySignature("signatures") + if err != nil { + t.Fatalf("error getting signed bytes: %v", err) + } + + dgst, err := digest.FromBytes(payload) + if err != nil { + t.Fatalf("error getting digest of manifest: %v", err) + } + + // use this as the "bad" digest + zeroDigest, err := digest.FromBytes([]byte{}) + if err != nil { + t.Fatalf("error making zero digest: %v", err) + } + + // Remote and local match, everything should look good + local, _, _, err := store.loadManifest(signedBytes, dgst.String(), dgst) + if err != nil { + t.Fatalf("unexpected error verifying local and remote digest: %v", err) + } + + if local != dgst { + t.Fatalf("local digest not correctly calculated: %v", err) + } + + // remote and no local, since pulling by tag + local, _, _, err = store.loadManifest(signedBytes, "tag", dgst) + if err != nil { + t.Fatalf("unexpected error verifying tag pull and remote digest: %v", err) + } + + if local != dgst { + t.Fatalf("local digest not correctly calculated: %v", err) + } + + // remote and differing local, this is the most important to fail + local, _, _, err = store.loadManifest(signedBytes, zeroDigest.String(), dgst) + if err == nil { + t.Fatalf("error expected when verifying with differing local digest") + } + + // no remote, no local (by tag) + local, _, _, err = store.loadManifest(signedBytes, "tag", "") + if err != nil { + t.Fatalf("unexpected error verifying manifest without remote digest: %v", err) + } + + if local != dgst { + t.Fatalf("local digest not correctly calculated: %v", err) + } + + // no remote, with local + local, _, _, err = store.loadManifest(signedBytes, dgst.String(), "") + if err != nil { + t.Fatalf("unexpected error verifying manifest without remote digest: %v", err) + } + + if local != dgst { + t.Fatalf("local digest not correctly calculated: %v", err) + } + + // bad remote, we fail the check. + local, _, _, err = store.loadManifest(signedBytes, dgst.String(), zeroDigest) + if err == nil { + t.Fatalf("error expected when verifying with differing remote digest") + } +} diff --git a/graph/tags_unit_test.go b/graph/tags_unit_test.go index d1ddc67617..ad919d9bb8 100644 --- a/graph/tags_unit_test.go +++ b/graph/tags_unit_test.go @@ -12,6 +12,7 @@ import ( "github.com/docker/docker/daemon/graphdriver" _ "github.com/docker/docker/daemon/graphdriver/vfs" // import the vfs driver so it is used in the tests "github.com/docker/docker/image" + "github.com/docker/docker/trust" "github.com/docker/docker/utils" ) @@ -60,9 +61,16 @@ func mkTestTagStore(root string, t *testing.T) *TagStore { if err != nil { t.Fatal(err) } + + trust, err := trust.NewTrustStore(root + "/trust") + if err != nil { + t.Fatal(err) + } + tagCfg := &TagStoreConfig{ Graph: graph, Events: events.New(), + Trust: trust, } store, err := NewTagStore(path.Join(root, "tags"), tagCfg) if err != nil {