package verify import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/sha256" "encoding/json" "errors" "testing" "time" "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/pkg/keys" "github.com/theupdateframework/go-tuf/sign" "golang.org/x/crypto/ed25519" . "gopkg.in/check.v1" ) // Hook up gocheck into the "go test" runner. func Test(t *testing.T) { TestingT(t) } type VerifySuite struct{} var _ = Suite(&VerifySuite{}) type ecdsaSigner struct { *ecdsa.PrivateKey } type ecdsaPublic struct { PublicKey *keys.PKIXPublicKey `json:"public"` } func (s ecdsaSigner) PublicData() *data.PublicKey { keyValBytes, _ := json.Marshal(ecdsaPublic{PublicKey: &keys.PKIXPublicKey{PublicKey: s.Public()}}) return &data.PublicKey{ Type: data.KeyTypeECDSA_SHA2_P256, Scheme: data.KeySchemeECDSA_SHA2_P256, Algorithms: data.HashAlgorithms, Value: keyValBytes, } } func (s ecdsaSigner) SignMessage(message []byte) ([]byte, error) { hash := sha256.Sum256(message) return s.PrivateKey.Sign(rand.Reader, hash[:], crypto.SHA256) } func (s ecdsaSigner) ContainsID(id string) bool { return s.PublicData().ContainsID(id) } func (ecdsaSigner) MarshalPrivateKey() (*data.PrivateKey, error) { return nil, errors.New("not implemented for test") } func (ecdsaSigner) UnmarshalPrivateKey(key *data.PrivateKey) error { return errors.New("not implemented for test") } func (VerifySuite) Test(c *C) { type test struct { name string keys []*data.PublicKey roles map[string]*data.Role s *data.Signed ver int64 exp *time.Time typ string role string err error mut func(*test) } expiredTime := time.Now().Add(-time.Hour) minVer := int64(10) tests := []test{ { name: "no signatures", mut: func(t *test) { t.s.Signatures = []data.Signature{} }, err: ErrNoSignatures, }, { name: "unknown role", role: "foo", err: ErrUnknownRole{"foo"}, }, { // It is impossible to distinguish between an error of an invalid // signature and a threshold not achieved. Invalid signatures lead // to not achieving the threshold. name: "signature wrong length", mut: func(t *test) { t.s.Signatures[0].Signature = []byte{0} }, err: ErrRoleThreshold{1, 0}, }, { name: "key missing from role", mut: func(t *test) { t.roles["root"].KeyIDs = nil }, err: ErrRoleThreshold{1, 0}, }, { name: "invalid signature", mut: func(t *test) { t.s.Signatures[0].Signature = make([]byte, ed25519.SignatureSize) }, err: ErrRoleThreshold{1, 0}, }, { name: "enough signatures with extra invalid signature", mut: func(t *test) { t.s.Signatures = append(t.s.Signatures, data.Signature{ KeyID: t.s.Signatures[0].KeyID, Signature: make([]byte, ed25519.SignatureSize)}) }, }, { name: "not enough signatures", mut: func(t *test) { t.roles["root"].Threshold = 2 }, err: ErrRoleThreshold{2, 1}, }, { name: "exactly enough signatures", }, { name: "more than enough signatures", mut: func(t *test) { k, _ := keys.GenerateEd25519Key() sign.Sign(t.s, k) t.keys = append(t.keys, k.PublicData()) t.roles["root"].KeyIDs = append(t.roles["root"].KeyIDs, k.PublicData().IDs()...) }, }, { name: "duplicate key id", mut: func(t *test) { t.roles["root"].Threshold = 2 t.s.Signatures = append(t.s.Signatures, t.s.Signatures[0]) }, err: ErrRoleThreshold{2, 1}, }, { name: "unknown key", mut: func(t *test) { k, _ := keys.GenerateEd25519Key() sign.Sign(t.s, k) }, }, { name: "unknown key below threshold", mut: func(t *test) { k, _ := keys.GenerateEd25519Key() sign.Sign(t.s, k) t.roles["root"].Threshold = 2 }, err: ErrRoleThreshold{2, 1}, }, { name: "unknown keys in db", mut: func(t *test) { k, _ := keys.GenerateEd25519Key() sign.Sign(t.s, k) t.keys = append(t.keys, k.PublicData()) }, }, { name: "unknown keys in db below threshold", mut: func(t *test) { k, _ := keys.GenerateEd25519Key() sign.Sign(t.s, k) t.keys = append(t.keys, k.PublicData()) t.roles["root"].Threshold = 2 }, err: ErrRoleThreshold{2, 1}, }, { name: "wrong type", typ: "bar", err: ErrWrongMetaType, }, { name: "low version", ver: minVer - 1, err: ErrLowVersion{minVer - 1, minVer}, }, { name: "expired", exp: &expiredTime, err: ErrExpired{expiredTime}, }, { name: "valid ecdsa signature", mut: func(t *test) { k, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) s := ecdsaSigner{k} sign.Sign(t.s, s) t.s.Signatures = t.s.Signatures[1:] t.keys = []*data.PublicKey{s.PublicData()} t.roles["root"].KeyIDs = s.PublicData().IDs() }, }, { // The threshold is still achieved. name: "invalid second ecdsa signature", mut: func(t *test) { k, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) s := ecdsaSigner{k} sign.Sign(t.s, s) t.s.Signatures[1].Signature[0]++ t.keys = append(t.keys, s.PublicData()) t.roles["root"].KeyIDs = append(t.roles["root"].KeyIDs, s.PublicData().IDs()...) }, }, } for _, t := range tests { if t.role == "" { t.role = "root" } if t.ver == 0 { t.ver = minVer } if t.exp == nil { expires := time.Now().Add(time.Hour) t.exp = &expires } if t.typ == "" { t.typ = t.role } if t.keys == nil && t.s == nil { k, _ := keys.GenerateEd25519Key() t.s, _ = sign.Marshal(&signedMeta{Type: t.typ, Version: t.ver, Expires: *t.exp}, k) t.keys = []*data.PublicKey{k.PublicData()} } if t.roles == nil { t.roles = map[string]*data.Role{ "root": { KeyIDs: t.keys[0].IDs(), Threshold: 1, }, } } if t.mut != nil { t.mut(&t) } db := NewDB() for _, k := range t.keys { for _, id := range k.IDs() { err := db.AddKey(id, k) c.Assert(err, IsNil) } } for n, r := range t.roles { err := db.AddRole(n, r) c.Assert(err, IsNil) } err := db.Verify(t.s, t.role, minVer) if e, ok := t.err.(ErrExpired); ok { assertErrExpired(c, err, e) } else { c.Assert(err, DeepEquals, t.err, Commentf("name = %s", t.name)) } } } func (VerifySuite) TestVerifyIgnoreExpired(c *C) { minVer := int64(10) role := "root" k, _ := keys.GenerateEd25519Key() s, _ := sign.Marshal(&signedMeta{Type: role, Version: minVer, Expires: time.Now().Add(-time.Hour)}, k) keys := []*data.PublicKey{k.PublicData()} roles := map[string]*data.Role{ "root": { KeyIDs: keys[0].IDs(), Threshold: 1, }, } db := NewDB() for _, k := range keys { for _, id := range k.IDs() { err := db.AddKey(id, k) c.Assert(err, IsNil) } } for n, r := range roles { err := db.AddRole(n, r) c.Assert(err, IsNil) } err := db.VerifyIgnoreExpiredCheck(s, role, minVer) c.Assert(err, IsNil) } func assertErrExpired(c *C, err error, expected ErrExpired) { actual, ok := err.(ErrExpired) if !ok { c.Fatalf("expected err to have type ErrExpired, got %T", err) } c.Assert(actual.Expired.Unix(), Equals, expected.Expired.Unix()) }