diff options
Diffstat (limited to 'vendor/github.com/miekg/dns/tsig.go')
-rw-r--r-- | vendor/github.com/miekg/dns/tsig.go | 158 |
1 files changed, 99 insertions, 59 deletions
diff --git a/vendor/github.com/miekg/dns/tsig.go b/vendor/github.com/miekg/dns/tsig.go index 9451f1a86c..b49562d847 100644 --- a/vendor/github.com/miekg/dns/tsig.go +++ b/vendor/github.com/miekg/dns/tsig.go @@ -2,7 +2,6 @@ package dns import ( "crypto/hmac" - "crypto/md5" "crypto/sha1" "crypto/sha256" "crypto/sha512" @@ -16,12 +15,65 @@ import ( // HMAC hashing codes. These are transmitted as domain names. const ( - HmacMD5 = "hmac-md5.sig-alg.reg.int." HmacSHA1 = "hmac-sha1." + HmacSHA224 = "hmac-sha224." HmacSHA256 = "hmac-sha256." + HmacSHA384 = "hmac-sha384." HmacSHA512 = "hmac-sha512." + + HmacMD5 = "hmac-md5.sig-alg.reg.int." // Deprecated: HmacMD5 is no longer supported. ) +// TsigProvider provides the API to plug-in a custom TSIG implementation. +type TsigProvider interface { + // Generate is passed the DNS message to be signed and the partial TSIG RR. It returns the signature and nil, otherwise an error. + Generate(msg []byte, t *TSIG) ([]byte, error) + // Verify is passed the DNS message to be verified and the TSIG RR. If the signature is valid it will return nil, otherwise an error. + Verify(msg []byte, t *TSIG) error +} + +type tsigHMACProvider string + +func (key tsigHMACProvider) Generate(msg []byte, t *TSIG) ([]byte, error) { + // If we barf here, the caller is to blame + rawsecret, err := fromBase64([]byte(key)) + if err != nil { + return nil, err + } + var h hash.Hash + switch CanonicalName(t.Algorithm) { + case HmacSHA1: + h = hmac.New(sha1.New, rawsecret) + case HmacSHA224: + h = hmac.New(sha256.New224, rawsecret) + case HmacSHA256: + h = hmac.New(sha256.New, rawsecret) + case HmacSHA384: + h = hmac.New(sha512.New384, rawsecret) + case HmacSHA512: + h = hmac.New(sha512.New, rawsecret) + default: + return nil, ErrKeyAlg + } + h.Write(msg) + return h.Sum(nil), nil +} + +func (key tsigHMACProvider) Verify(msg []byte, t *TSIG) error { + b, err := key.Generate(msg, t) + if err != nil { + return err + } + mac, err := hex.DecodeString(t.MAC) + if err != nil { + return err + } + if !hmac.Equal(b, mac) { + return ErrSig + } + return nil +} + // TSIG is the RR the holds the transaction signature of a message. // See RFC 2845 and RFC 4635. type TSIG struct { @@ -54,8 +106,8 @@ func (rr *TSIG) String() string { return s } -func (rr *TSIG) parse(c *zlexer, origin string) *ParseError { - panic("dns: internal error: parse should never be called on TSIG") +func (*TSIG) parse(c *zlexer, origin string) *ParseError { + return &ParseError{err: "TSIG records do not have a presentation format"} } // The following values must be put in wireformat, so that the MAC can be calculated. @@ -96,14 +148,13 @@ type timerWireFmt struct { // timersOnly is false. // If something goes wrong an error is returned, otherwise it is nil. func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) { + return tsigGenerateProvider(m, tsigHMACProvider(secret), requestMAC, timersOnly) +} + +func tsigGenerateProvider(m *Msg, provider TsigProvider, requestMAC string, timersOnly bool) ([]byte, string, error) { if m.IsTsig() == nil { panic("dns: TSIG not last RR in additional") } - // If we barf here, the caller is to blame - rawsecret, err := fromBase64([]byte(secret)) - if err != nil { - return nil, "", err - } rr := m.Extra[len(m.Extra)-1].(*TSIG) m.Extra = m.Extra[0 : len(m.Extra)-1] // kill the TSIG from the msg @@ -111,32 +162,21 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s if err != nil { return nil, "", err } - buf := tsigBuffer(mbuf, rr, requestMAC, timersOnly) + buf, err := tsigBuffer(mbuf, rr, requestMAC, timersOnly) + if err != nil { + return nil, "", err + } t := new(TSIG) - var h hash.Hash - switch CanonicalName(rr.Algorithm) { - case HmacMD5: - h = hmac.New(md5.New, rawsecret) - case HmacSHA1: - h = hmac.New(sha1.New, rawsecret) - case HmacSHA256: - h = hmac.New(sha256.New, rawsecret) - case HmacSHA512: - h = hmac.New(sha512.New, rawsecret) - default: - return nil, "", ErrKeyAlg + // Copy all TSIG fields except MAC and its size, which are filled using the computed digest. + *t = *rr + mac, err := provider.Generate(buf, rr) + if err != nil { + return nil, "", err } - h.Write(buf) - t.MAC = hex.EncodeToString(h.Sum(nil)) + t.MAC = hex.EncodeToString(mac) t.MACSize = uint16(len(t.MAC) / 2) // Size is half! - t.Hdr = RR_Header{Name: rr.Hdr.Name, Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0} - t.Fudge = rr.Fudge - t.TimeSigned = rr.TimeSigned - t.Algorithm = rr.Algorithm - t.OrigId = m.Id - tbuf := make([]byte, Len(t)) off, err := PackRR(t, tbuf, 0, nil, false) if err != nil { @@ -153,26 +193,34 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s // If the signature does not validate err contains the // error, otherwise it is nil. func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error { - rawsecret, err := fromBase64([]byte(secret)) - if err != nil { - return err - } + return tsigVerify(msg, tsigHMACProvider(secret), requestMAC, timersOnly, uint64(time.Now().Unix())) +} + +func tsigVerifyProvider(msg []byte, provider TsigProvider, requestMAC string, timersOnly bool) error { + return tsigVerify(msg, provider, requestMAC, timersOnly, uint64(time.Now().Unix())) +} + +// actual implementation of TsigVerify, taking the current time ('now') as a parameter for the convenience of tests. +func tsigVerify(msg []byte, provider TsigProvider, requestMAC string, timersOnly bool, now uint64) error { // Strip the TSIG from the incoming msg stripped, tsig, err := stripTsig(msg) if err != nil { return err } - msgMAC, err := hex.DecodeString(tsig.MAC) + buf, err := tsigBuffer(stripped, tsig, requestMAC, timersOnly) if err != nil { return err } - buf := tsigBuffer(stripped, tsig, requestMAC, timersOnly) + if err := provider.Verify(buf, tsig); err != nil { + return err + } // Fudge factor works both ways. A message can arrive before it was signed because // of clock skew. - now := uint64(time.Now().Unix()) + // We check this after verifying the signature, following draft-ietf-dnsop-rfc2845bis + // instead of RFC2845, in order to prevent a security vulnerability as reported in CVE-2017-3142/3143. ti := now - tsig.TimeSigned if now < tsig.TimeSigned { ti = tsig.TimeSigned - now @@ -181,28 +229,11 @@ func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error { return ErrTime } - var h hash.Hash - switch CanonicalName(tsig.Algorithm) { - case HmacMD5: - h = hmac.New(md5.New, rawsecret) - case HmacSHA1: - h = hmac.New(sha1.New, rawsecret) - case HmacSHA256: - h = hmac.New(sha256.New, rawsecret) - case HmacSHA512: - h = hmac.New(sha512.New, rawsecret) - default: - return ErrKeyAlg - } - h.Write(buf) - if !hmac.Equal(h.Sum(nil), msgMAC) { - return ErrSig - } return nil } // Create a wiredata buffer for the MAC calculation. -func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []byte { +func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) ([]byte, error) { var buf []byte if rr.TimeSigned == 0 { rr.TimeSigned = uint64(time.Now().Unix()) @@ -219,7 +250,10 @@ func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []b m.MACSize = uint16(len(requestMAC) / 2) m.MAC = requestMAC buf = make([]byte, len(requestMAC)) // long enough - n, _ := packMacWire(m, buf) + n, err := packMacWire(m, buf) + if err != nil { + return nil, err + } buf = buf[:n] } @@ -228,7 +262,10 @@ func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []b tsig := new(timerWireFmt) tsig.TimeSigned = rr.TimeSigned tsig.Fudge = rr.Fudge - n, _ := packTimerWire(tsig, tsigvar) + n, err := packTimerWire(tsig, tsigvar) + if err != nil { + return nil, err + } tsigvar = tsigvar[:n] } else { tsig := new(tsigWireFmt) @@ -241,7 +278,10 @@ func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []b tsig.Error = rr.Error tsig.OtherLen = rr.OtherLen tsig.OtherData = rr.OtherData - n, _ := packTsigWire(tsig, tsigvar) + n, err := packTsigWire(tsig, tsigvar) + if err != nil { + return nil, err + } tsigvar = tsigvar[:n] } @@ -251,7 +291,7 @@ func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []b } else { buf = append(msgbuf, tsigvar...) } - return buf + return buf, nil } // Strip the TSIG from the raw message. |