G1: Parse TUF-1.0 key ids if present

To ease transition to TUF-1.0, this patch allows go-tuf to both
consume TUF-0.9 and TUF-1.0 metadata, but produce TUF-0.9 metadata
that's still compatible with the original go-tuf 0.9. It does
this by defaulting to generating TUF-0.9 key ids, but if go-tuf
receives metadata produced by TUF-1.0, it will parse out both
the 0.9 and 1.0 key ids.

Note that it is only safe for this version of go-tuf to produce
TUF-0.9 metadata based off of other TUF-0.9 metadata. It will produce
incorrect metadata or error out if it is used to advance TUF-1.0
metadata.

Change-Id: I87fffdc17a5456f7e04f990fbd2a0e060340125a
diff --git a/client/interop_test.go b/client/interop_test.go
index 5a16f88..e03e4ea 100644
--- a/client/interop_test.go
+++ b/client/interop_test.go
@@ -38,6 +38,7 @@
 		"go-tuf-transition-M1",
 		"go-tuf-transition-M2",
 		"go-tuf-transition-M3",
+		"go-tuf-transition-M4",
 	}
 
 	for _, version := range versions {
diff --git a/data/types.go b/data/types.go
index c7c79b7..7eda908 100644
--- a/data/types.go
+++ b/data/types.go
@@ -11,9 +11,15 @@
 )
 
 const (
-	KeyIDLength            = sha256.Size * 2
-	KeyTypeEd25519         = "ed25519"
-	KeyTypeECDSA_SHA2_P256 = "ecdsa-sha2-nistp256"
+	KeyIDLength              = sha256.Size * 2
+	KeyTypeEd25519           = "ed25519"
+	KeyTypeECDSA_SHA2_P256   = "ecdsa-sha2-nistp256"
+	KeySchemeEd25519         = "ed25519"
+	KeySchemeECDSA_SHA2_P256 = "ecdsa-sha2-nistp256"
+)
+
+var (
+	KeyAlgorithms = []string{"sha256"}
 )
 
 type Signed struct {
@@ -22,14 +28,20 @@
 }
 
 type Signature struct {
-	KeyID     string   `json:"keyid"`
-	Method    string   `json:"method"`
+	KeyID string `json:"keyid"`
+
+	// FIXME(TUF-0.9) removed in TUF 1.0, keeping it around for backwards
+	// compatibility with TUF 0.9.
+	Method string `json:"method"`
+
 	Signature HexBytes `json:"sig"`
 }
 
 type Key struct {
-	Type  string   `json:"keytype"`
-	Value KeyValue `json:"keyval"`
+	Type       string   `json:"keytype"`
+	Scheme     string   `json:"scheme,omitempty"`
+	Algorithms []string `json:"keyid_hash_algorithms,omitempty"`
+	Value      KeyValue `json:"keyval"`
 
 	ids    []string
 	idOnce sync.Once
@@ -40,6 +52,19 @@
 		data, _ := cjson.Marshal(k)
 		digest := sha256.Sum256(data)
 		k.ids = []string{hex.EncodeToString(digest[:])}
+
+		// FIXME(TUF-0.9) If we receive TUF-1.0 compatible metadata,
+		// the key id we just calculated won't be compatible with
+		// TUF-0.9. So we also need to calculate the TUF-0.9 key id to
+		// be backwards compatible.
+		if k.Scheme != "" || len(k.Algorithms) != 0 {
+			data, _ = cjson.Marshal(Key{
+				Type:  k.Type,
+				Value: k.Value,
+			})
+			digest = sha256.Sum256(data)
+			k.ids = append(k.ids, hex.EncodeToString(digest[:]))
+		}
 	})
 	return k.ids
 }
diff --git a/data/types_test.go b/data/types_test.go
new file mode 100644
index 0000000..1239224
--- /dev/null
+++ b/data/types_test.go
@@ -0,0 +1,51 @@
+package data
+
+import (
+	"encoding/json"
+
+	. "gopkg.in/check.v1"
+)
+
+type TypesSuite struct{}
+
+var _ = Suite(&TypesSuite{})
+
+func (TypesSuite) TestKeyIDs(c *C) {
+	// This public key is from the TUF specs:
+	//
+	// https://github.com/theupdateframework/specification
+	//
+	// Unfortunately there was a bug in the 1.0 spec, which reused the 0.9
+	// key ids. This patch fixes it:
+	//
+	// https://github.com/theupdateframework/specification/pull/43
+	public := `"72378e5bc588793e58f81c8533da64a2e8f1565c1fcc7f253496394ffc52542c"`
+	keyid09 := "1a2b4110927d4cba257262f614896179ff85ca1f1353a41b5224ac474ca71cb4"
+	keyid10 := "1bf1c6e3cdd3d3a8420b19199e27511999850f4b376c4547b2f32fba7e80fca3"
+	keyid10algos := "8e1824bd4e2de736e1388208c41e439fa1cfa19f4852f9ca80015e1da981cad5"
+
+	var hexbytes HexBytes
+	err := json.Unmarshal([]byte(public), &hexbytes)
+	c.Assert(err, IsNil)
+
+	key := Key{
+		Type:  KeyTypeEd25519,
+		Value: KeyValue{Public: hexbytes},
+	}
+	c.Assert(key.IDs(), DeepEquals, []string{keyid09})
+
+	key = Key{
+		Type:   KeyTypeEd25519,
+		Scheme: KeySchemeEd25519,
+		Value:  KeyValue{Public: hexbytes},
+	}
+	c.Assert(key.IDs(), DeepEquals, []string{keyid10, keyid09})
+
+	key = Key{
+		Type:       KeyTypeEd25519,
+		Scheme:     KeySchemeEd25519,
+		Algorithms: KeyAlgorithms,
+		Value:      KeyValue{Public: hexbytes},
+	}
+	c.Assert(key.IDs(), DeepEquals, []string{keyid10algos, keyid09})
+}