From 9e8df3cd16409ab9f4fda05d59f931e70f1c98db Mon Sep 17 00:00:00 2001 From: Jonathan Rudenberg Date: Tue, 9 Aug 2016 18:19:55 -0400 Subject: [PATCH 1/2] verify: Don't assume signature method, use key type It is unsafe to use the signature method field, as it could result in a key confusion attack. Use the key type instead. Also, don't assume that we're only working with Ed25519. Signed-off-by: Jonathan Rudenberg --- verify/verify.go | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/verify/verify.go b/verify/verify.go index b0823c76..ee07210d 100644 --- a/verify/verify.go +++ b/verify/verify.go @@ -7,7 +7,6 @@ import ( "github.com/flynn/go-tuf/data" "github.com/tent/canonical-json-go" - "golang.org/x/crypto/ed25519" ) type signedMeta struct { @@ -62,15 +61,7 @@ func (db *DB) VerifySignatures(s *data.Signed, role string) error { } valid := make(map[string]struct{}) - var sigBytes [ed25519.SignatureSize]byte for _, sig := range s.Signatures { - if _, ok := Verifiers[sig.Method]; !ok { - return ErrWrongMethod - } - if len(sig.Signature) != len(sigBytes) { - return ErrInvalid - } - if !roleData.ValidKey(sig.KeyID) { continue } @@ -79,8 +70,7 @@ func (db *DB) VerifySignatures(s *data.Signed, role string) error { continue } - copy(sigBytes[:], sig.Signature) - if err := Verifiers[sig.Method].Verify(key.Value.Public, msg, sigBytes[:]); err != nil { + if err := Verifiers[key.Type].Verify(key.Value.Public, msg, sig.Signature); err != nil { return err } valid[sig.KeyID] = struct{}{} From 596db52f15e802e10bc9b957c49e5ab3f1d06c9e Mon Sep 17 00:00:00 2001 From: Jonathan Rudenberg Date: Tue, 9 Aug 2016 18:38:49 -0400 Subject: [PATCH 2/2] verify: Add support for ecdsa-sha2-p256 signatures Signed-off-by: Jonathan Rudenberg --- data/types.go | 5 ++-- verify/verifiers.go | 41 +++++++++++++++++++++++++++++- verify/verify_test.go | 59 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 97 insertions(+), 8 deletions(-) diff --git a/data/types.go b/data/types.go index 4fd4fda8..fb4be673 100644 --- a/data/types.go +++ b/data/types.go @@ -11,8 +11,9 @@ import ( ) const ( - KeyIDLength = sha256.Size * 2 - KeyTypeEd25519 = "ed25519" + KeyIDLength = sha256.Size * 2 + KeyTypeEd25519 = "ed25519" + KeyTypeECDSA_SHA2_P256 = "ecdsa-sha2-nistp256" ) type Signed struct { diff --git a/verify/verifiers.go b/verify/verifiers.go index ac9ce344..fad080b6 100644 --- a/verify/verifiers.go +++ b/verify/verifiers.go @@ -1,6 +1,12 @@ package verify import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/sha256" + "encoding/asn1" + "math/big" + "github.com/flynn/go-tuf/data" "golang.org/x/crypto/ed25519" ) @@ -19,7 +25,8 @@ type Verifier interface { // Verifiers is used to map key types to Verifier instances. var Verifiers = map[string]Verifier{ - data.KeyTypeEd25519: ed25519Verifier{}, + data.KeyTypeEd25519: ed25519Verifier{}, + data.KeyTypeECDSA_SHA2_P256: p256Verifier{}, } type ed25519Verifier struct{} @@ -34,3 +41,35 @@ func (ed25519Verifier) Verify(key, msg, sig []byte) error { func (ed25519Verifier) ValidKey(k []byte) bool { return len(k) == ed25519.PublicKeySize } + +type ecdsaSignature struct { + R, S *big.Int +} + +type p256Verifier struct{} + +func (p256Verifier) Verify(key, msg, sigBytes []byte) error { + x, y := elliptic.Unmarshal(elliptic.P256(), key) + k := &ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: x, + Y: y, + } + + var sig ecdsaSignature + if _, err := asn1.Unmarshal(sigBytes, &sig); err != nil { + return ErrInvalid + } + + hash := sha256.Sum256(msg) + + if !ecdsa.Verify(k, hash[:], sig.R, sig.S) { + return ErrInvalid + } + return nil +} + +func (p256Verifier) ValidKey(k []byte) bool { + x, _ := elliptic.Unmarshal(elliptic.P256(), k) + return x != nil +} diff --git a/verify/verify_test.go b/verify/verify_test.go index 2e15dc0f..7e303e7e 100644 --- a/verify/verify_test.go +++ b/verify/verify_test.go @@ -1,6 +1,12 @@ package verify import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/sha256" + "io" "testing" "time" @@ -18,6 +24,31 @@ type VerifySuite struct{} var _ = Suite(&VerifySuite{}) +type ecdsaSigner struct { + *ecdsa.PrivateKey +} + +func (s ecdsaSigner) PublicData() *data.Key { + pub := s.Public().(*ecdsa.PublicKey) + return &data.Key{ + Type: data.KeyTypeECDSA_SHA2_P256, + Value: data.KeyValue{Public: elliptic.Marshal(pub.Curve, pub.X, pub.Y)}, + } +} + +func (s ecdsaSigner) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { + hash := sha256.Sum256(msg) + return s.PrivateKey.Sign(rand, hash[:], crypto.SHA256) +} + +func (s ecdsaSigner) ID() string { + return s.PublicData().ID() +} + +func (ecdsaSigner) Type() string { + return data.KeyTypeECDSA_SHA2_P256 +} + func (VerifySuite) Test(c *C) { type test struct { name string @@ -45,11 +76,6 @@ func (VerifySuite) Test(c *C) { role: "foo", err: ErrUnknownRole, }, - { - name: "wrong signature method", - mut: func(t *test) { t.s.Signatures[0].Method = "foo" }, - err: ErrWrongMethod, - }, { name: "signature wrong length", mut: func(t *test) { t.s.Signatures[0].Signature = []byte{0} }, @@ -139,6 +165,29 @@ func (VerifySuite) Test(c *C) { 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.Key{s.PublicData()} + t.roles["root"].KeyIDs = []string{s.PublicData().ID()} + }, + }, + { + name: "invalid 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().ID()) + }, + err: ErrInvalid, + }, } for _, t := range tests { if t.role == "" {