Merge pull request #1156 from RichardScothern/manifest-verification

Manifest Verification
pull/1163/head
Richard Scothern 2015-11-04 14:09:12 -08:00
commit 362ae9cc41
5 changed files with 76 additions and 12 deletions

View File

@ -10,10 +10,10 @@ import (
) )
type testEnv struct { type testEnv struct {
name, tag string name, tag string
manifest *Manifest invalidSigned *SignedManifest
signed *SignedManifest signed *SignedManifest
pk libtrust.PrivateKey pk libtrust.PrivateKey
} }
func TestManifestMarshaling(t *testing.T) { func TestManifestMarshaling(t *testing.T) {
@ -42,6 +42,7 @@ func TestManifestUnmarshaling(t *testing.T) {
if !reflect.DeepEqual(&signed, env.signed) { if !reflect.DeepEqual(&signed, env.signed) {
t.Fatalf("manifests are different after unmarshaling: %v != %v", signed, env.signed) t.Fatalf("manifests are different after unmarshaling: %v != %v", signed, env.signed)
} }
} }
func TestManifestVerification(t *testing.T) { func TestManifestVerification(t *testing.T) {
@ -69,6 +70,12 @@ func TestManifestVerification(t *testing.T) {
if !found { if !found {
t.Fatalf("expected public key, %v, not found in verified keys: %v", publicKey, publicKeys) t.Fatalf("expected public key, %v, not found in verified keys: %v", publicKey, publicKeys)
} }
// Check that an invalid manifest fails verification
_, err = Verify(env.invalidSigned)
if err != nil {
t.Fatalf("Invalid manifest should not pass Verify()")
}
} }
func genEnv(t *testing.T) *testEnv { func genEnv(t *testing.T) *testEnv {
@ -79,7 +86,7 @@ func genEnv(t *testing.T) *testEnv {
name, tag := "foo/bar", "test" name, tag := "foo/bar", "test"
m := Manifest{ invalid := Manifest{
Versioned: SchemaVersion, Versioned: SchemaVersion,
Name: name, Name: name,
Tag: tag, Tag: tag,
@ -93,16 +100,37 @@ func genEnv(t *testing.T) *testEnv {
}, },
} }
sm, err := Sign(&m, pk) valid := Manifest{
Versioned: SchemaVersion,
Name: name,
Tag: tag,
FSLayers: []FSLayer{
{
BlobSum: "asdf",
},
},
History: []History{
{
V1Compatibility: "",
},
},
}
sm, err := Sign(&valid, pk)
if err != nil {
t.Fatalf("error signing manifest: %v", err)
}
invalidSigned, err := Sign(&invalid, pk)
if err != nil { if err != nil {
t.Fatalf("error signing manifest: %v", err) t.Fatalf("error signing manifest: %v", err)
} }
return &testEnv{ return &testEnv{
name: name, name: name,
tag: tag, tag: tag,
manifest: &m, invalidSigned: invalidSigned,
signed: sm, signed: sm,
pk: pk, pk: pk,
} }
} }

View File

@ -131,6 +131,9 @@ func checkExerciseRepository(t *testing.T, repository distribution.Repository) {
m.FSLayers = append(m.FSLayers, schema1.FSLayer{ m.FSLayers = append(m.FSLayers, schema1.FSLayer{
BlobSum: dgst, BlobSum: dgst,
}) })
m.History = append(m.History, schema1.History{
V1Compatibility: "",
})
// Then fetch the blobs // Then fetch the blobs
if rc, err := blobs.Open(ctx, dgst); err != nil { if rc, err := blobs.Open(ctx, dgst); err != nil {

View File

@ -804,6 +804,14 @@ func testManifestAPI(t *testing.T, env *testEnv, args manifestArgs) (*testEnv, m
BlobSum: "qwer", BlobSum: "qwer",
}, },
}, },
History: []schema1.History{
{
V1Compatibility: "",
},
{
V1Compatibility: "",
},
},
} }
resp = putManifest(t, "putting unsigned manifest", manifestURL, unsignedManifest) resp = putManifest(t, "putting unsigned manifest", manifestURL, unsignedManifest)
@ -999,6 +1007,19 @@ func testManifestAPI(t *testing.T, env *testEnv, args manifestArgs) (*testEnv, m
t.Fatalf("tag not as expected: %q != %q", tagsResponse.Tags[0], tag) t.Fatalf("tag not as expected: %q != %q", tagsResponse.Tags[0], tag)
} }
// Attempt to put a manifest with mismatching FSLayer and History array cardinalities
unsignedManifest.History = append(unsignedManifest.History, schema1.History{
V1Compatibility: "",
})
invalidSigned, err := schema1.Sign(unsignedManifest, env.pk)
if err != nil {
t.Fatalf("error signing manifest")
}
resp = putManifest(t, "putting invalid signed manifest", manifestDigestURL, invalidSigned)
checkResponse(t, "putting invalid signed manifest", resp, http.StatusBadRequest)
return env, args return env, args
} }
@ -1432,8 +1453,10 @@ func createRepository(env *testEnv, t *testing.T, imageName string, tag string)
{ {
BlobSum: "asdf", BlobSum: "asdf",
}, },
},
History: []schema1.History{
{ {
BlobSum: "qwer", V1Compatibility: "",
}, },
}, },
} }
@ -1499,6 +1522,7 @@ func TestRegistryAsCacheMutationAPIs(t *testing.T) {
Name: imageName, Name: imageName,
Tag: tag, Tag: tag,
FSLayers: []schema1.FSLayer{}, FSLayers: []schema1.FSLayer{},
History: []schema1.History{},
} }
sm, err := schema1.Sign(m, env.pk) sm, err := schema1.Sign(m, env.pk)

View File

@ -110,6 +110,11 @@ func (ms *manifestStore) verifyManifest(ctx context.Context, mnfst *schema1.Sign
errs = append(errs, fmt.Errorf("repository name does not match manifest name")) errs = append(errs, fmt.Errorf("repository name does not match manifest name"))
} }
if len(mnfst.History) != len(mnfst.FSLayers) {
errs = append(errs, fmt.Errorf("mismatched history and fslayer cardinality %d != %d",
len(mnfst.History), len(mnfst.FSLayers)))
}
if _, err := schema1.Verify(mnfst); err != nil { if _, err := schema1.Verify(mnfst); err != nil {
switch err { switch err {
case libtrust.ErrMissingSignatureKey, libtrust.ErrInvalidJSONContent, libtrust.ErrMissingSignatureKey: case libtrust.ErrMissingSignatureKey, libtrust.ErrInvalidJSONContent, libtrust.ErrMissingSignatureKey:

View File

@ -98,6 +98,10 @@ func TestManifestStorage(t *testing.T) {
m.FSLayers = append(m.FSLayers, schema1.FSLayer{ m.FSLayers = append(m.FSLayers, schema1.FSLayer{
BlobSum: dgst, BlobSum: dgst,
}) })
m.History = append(m.History, schema1.History{
V1Compatibility: "",
})
} }
pk, err := libtrust.GenerateECP256PrivateKey() pk, err := libtrust.GenerateECP256PrivateKey()