Snapshot length and hashes fields are optional in TUF-1.0

TUF-1.0 in section 4.4.4 no longer requires the `length` and
`hashes` fields to be present on the metadata contained in the
snapshot role. This patch makes those fields optional by
only using them for equality if they are listed in the
`expected` object.

Change-Id: I42b9a26fb9b1c5115cd0005a3c489c97f7eb328e
diff --git a/util/util.go b/util/util.go
index bf6f403..18f788f 100644
--- a/util/util.go
+++ b/util/util.go
@@ -76,9 +76,18 @@
 	if actual.Length != expected.Length {
 		return ErrWrongLength{expected.Length, actual.Length}
 	}
+
+	if err := hashEqual(actual.Hashes, expected.Hashes); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func hashEqual(actual data.Hashes, expected data.Hashes) error {
 	hashChecked := false
-	for typ, hash := range expected.Hashes {
-		if h, ok := actual.Hashes[typ]; ok {
+	for typ, hash := range expected {
+		if h, ok := actual[typ]; ok {
 			hashChecked = true
 			if !hmac.Equal(h, hash) {
 				return ErrWrongHash{typ, hash, h}
@@ -86,7 +95,7 @@
 		}
 	}
 	if !hashChecked {
-		return ErrNoCommonHash{expected.Hashes, actual.Hashes}
+		return ErrNoCommonHash{expected, actual}
 	}
 	return nil
 }
@@ -102,8 +111,19 @@
 }
 
 func SnapshotFileMetaEqual(actual data.SnapshotFileMeta, expected data.SnapshotFileMeta) error {
-	if err := FileMetaEqual(actual.FileMeta, expected.FileMeta); err != nil {
-		return err
+	// TUF-1.0 no longer considers the length and hashes to be a required
+	// member of snapshots. However they are considering requiring hashes
+	// for delegated roles to avoid an attack described in Section 5.6 of
+	// the Mercury paper:
+	// https://github.com/theupdateframework/specification/pull/40
+	if expected.Length != 0 && actual.Length != expected.Length {
+		return ErrWrongLength{expected.Length, actual.Length}
+	}
+
+	if len(expected.Hashes) != 0 {
+		if err := hashEqual(actual.Hashes, expected.Hashes); err != nil {
+			return err
+		}
 	}
 
 	if err := versionEqual(actual.Version, expected.Version); err != nil {
@@ -118,6 +138,9 @@
 }
 
 func TimestampFileMetaEqual(actual data.TimestampFileMeta, expected data.TimestampFileMeta) error {
+	// As opposed to snapshots, the length and hashes are still required in
+	// TUF-1.0. See:
+	// https://github.com/theupdateframework/specification/issues/38
 	if err := FileMetaEqual(actual.FileMeta, expected.FileMeta); err != nil {
 		return err
 	}