diff --git a/sig0.go b/sig0.go index 50fd232e..46cf7a2e 100644 --- a/sig0.go +++ b/sig0.go @@ -8,6 +8,11 @@ // // It works like TSIG, except that SIG(0) uses public key cryptography, instead of the shared // secret approach in TSIG. +// Supported algorithms: DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256 and +// RSASHA512. +// +// Signing subsequent messages in multi-message sessions is not implemented. +// package dns import ( @@ -16,7 +21,6 @@ import ( "crypto/ecdsa" "crypto/rand" "crypto/rsa" - "fmt" "math/big" "strings" "time" @@ -160,29 +164,34 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error { adc, offset := unpackUint16(buf, 10) var err error for i := uint16(0); i < qdc && offset < buflen; i++ { - // decode a name _, offset, err = UnpackDomainName(buf, offset) if err != nil { return err } - // skip past Type and Class + // Skip past Type and Class offset += 2 + 2 } for i := uint16(1); i < anc+auc+adc && offset < buflen; i++ { - // decode a name _, offset, err = UnpackDomainName(buf, offset) if err != nil { return err } - // skip past Type, Class and TTL + // Skip past Type, Class and TTL offset += 2 + 2 + 4 + if offset+1 >= buflen { + continue + } var rdlen uint16 rdlen, offset = unpackUint16(buf, offset) offset += int(rdlen) } + if offset >= buflen { + return &Error{err: "overflowing unpacking signed message"} + } + // offset should be just prior to SIG bodyend := offset - // Owner name SHOULD be root + // owner name SHOULD be root _, offset, err = UnpackDomainName(buf, offset) if err != nil { return err @@ -190,20 +199,21 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error { // Skip Type, Class, TTL, RDLen offset += 2 + 2 + 4 + 2 sigstart := offset - offset += 2 + 1 + 1 + 4 // skip Type Covered, Algorithm, Labels, Original TTL - // TODO: This should be moved out and used elsewhere - unpackUint32 := func(buf []byte, off int) (uint32, int) { - r := uint32(buf[off])<<24 | uint32(buf[off+1])<<16 | uint32(buf[off+2])<<8 | uint32(buf[off+3]) - return r, off + 4 + // Skip Type Covered, Algorithm, Labels, Original TTL + offset += 2 + 1 + 1 + 4 + if offset+4+4 >= buflen { + return &Error{err: "overflow unpacking signed message"} } - var expire, incept uint32 - expire, offset = unpackUint32(buf, offset) - incept, offset = unpackUint32(buf, offset) + expire := uint32(buf[offset])<<24 | uint32(buf[offset+1])<<16 | uint32(buf[offset+2])<<8 | uint32(buf[offset+3]) + offset += 4 + incept := uint32(buf[offset])<<24 | uint32(buf[offset+1])<<16 | uint32(buf[offset+2])<<8 | uint32(buf[offset+3]) + offset += 4 now := uint32(time.Now().Unix()) if now < incept || now > expire { return ErrTime } - offset += 2 // skip key tag + // Skip key tag + offset += 2 var signername string signername, offset, err = UnpackDomainName(buf, offset) if err != nil { @@ -212,7 +222,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error { // If key has come from the DNS name compression might // have mangled the case of the name if strings.ToLower(signername) != strings.ToLower(k.Header().Name) { - return fmt.Errorf("Signer name doesn't match key name") + return &Error{err: "signer name doesn't match key name"} } sigend := offset hasher.Write(buf[sigstart:sigend]) diff --git a/sig0_test.go b/sig0_test.go index 921b7974..1a18e260 100644 --- a/sig0_test.go +++ b/sig0_test.go @@ -6,51 +6,39 @@ import ( ) func TestSIG0(t *testing.T) { - keys := []struct { - alg uint8 - rr *KEY - pk PrivateKey - }{{alg: DSA}, {alg: ECDSAP256SHA256}, {alg: ECDSAP384SHA384}, {alg: RSASHA1}, {alg: RSASHA256}, {alg: RSASHA512}} - for i := range keys { - keys[i].rr = new(KEY) - keys[i].rr.Hdr.Name = AlgorithmToString[keys[i].alg] + "." - keys[i].rr.Hdr.Rrtype = TypeKEY - keys[i].rr.Hdr.Class = ClassINET - keys[i].rr.Algorithm = keys[i].alg + m := new(Msg) + m.SetQuestion("example.org.", TypeSOA) + for _, alg := range []uint8{DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256, RSASHA512} { + algstr := AlgorithmToString[alg] + keyrr := new(KEY) + keyrr.Hdr.Name = algstr + "." + keyrr.Hdr.Rrtype = TypeKEY + keyrr.Hdr.Class = ClassINET + keyrr.Algorithm = alg keysize := 1024 - switch keys[i].alg { + switch alg { case ECDSAP256SHA256: keysize = 256 case ECDSAP384SHA384: keysize = 384 } - pk, err := keys[i].rr.Generate(keysize) + pk, err := keyrr.Generate(keysize) if err != nil { - t.Logf("Failed to generate key for “%s”: %v", AlgorithmToString[keys[i].alg], err) + t.Logf("Failed to generate key for “%s”: %v", algstr, err) t.Fail() continue } - keys[i].pk = pk - } - - m := new(Msg) - m.SetQuestion("example.org.", TypeSOA) - for _, key := range keys { - if key.pk == nil { - continue - } - algstr := AlgorithmToString[key.alg] now := uint32(time.Now().Unix()) sigrr := new(SIG) sigrr.Hdr.Name = "." sigrr.Hdr.Rrtype = TypeSIG sigrr.Hdr.Class = ClassANY - sigrr.Algorithm = key.rr.Algorithm + sigrr.Algorithm = alg sigrr.Expiration = now + 300 sigrr.Inception = now - 300 - sigrr.KeyTag = key.rr.KeyTag() - sigrr.SignerName = key.rr.Hdr.Name - mb, err := sigrr.Sign(key.pk, m) + sigrr.KeyTag = keyrr.KeyTag() + sigrr.SignerName = keyrr.Hdr.Name + mb, err := sigrr.Sign(pk, m) if err != nil { t.Logf("Failed to sign message using “%s”: %v", algstr, err) t.Fail() @@ -81,22 +69,22 @@ func TestSIG0(t *testing.T) { if rr == sigrrwire { id = "sigrrwire" } - if err := rr.Verify(key.rr, mb); err != nil { + if err := rr.Verify(keyrr, mb); err != nil { t.Logf("Failed to verify “%s” signed SIG(%s): %v", algstr, id, err) t.Fail() continue } } mb[13]++ - if err := sigrr.Verify(key.rr, mb); err == nil { + if err := sigrr.Verify(keyrr, mb); err == nil { t.Logf("Verify succeeded on an altered message using “%s”", algstr) t.Fail() continue } sigrr.Expiration = 2 sigrr.Inception = 1 - mb, _ = sigrr.Sign(key.pk, m) - if err := sigrr.Verify(key.rr, mb); err == nil { + mb, _ = sigrr.Sign(pk, m) + if err := sigrr.Verify(keyrr, mb); err == nil { t.Logf("Verify succeeded on an expired message using “%s”", algstr) t.Fail() continue