From 2c5184ff110ea43fd61b0afeae3a60f595bbb32f Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Sun, 20 Mar 2011 20:55:27 +0100 Subject: [PATCH] Add tsig stuff --- dns.go | 6 ++- tsig.go | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/dns.go b/dns.go index d97eb92f..79c04d70 100644 --- a/dns.go +++ b/dns.go @@ -59,7 +59,7 @@ type Conn struct { Addr net.Addr // If TSIG is used, this holds all the information - Signature *Tsig + Tsig *Tsig // Timeout in sec Timeout int @@ -108,6 +108,10 @@ func (d *Conn) Read(p []byte) (n int, err os.Error) { i += n } } + if d.Tsig != nil { + // Check the TSIG that we should be read + d.Tsig.Verify(p) + } return } diff --git a/tsig.go b/tsig.go index 0ebfd5ad..bf6a2b03 100644 --- a/tsig.go +++ b/tsig.go @@ -10,6 +10,8 @@ import ( "encoding/hex" ) +// Structure used in Read/Write lowlevel functions +// for TSIG generation and verification. type Tsig struct { // The name of the key. Name string @@ -20,9 +22,12 @@ type Tsig struct { Secret string // MAC (if known) MAC string + // Request MAC + RequestMAC string + // Include the timers if true + Timers bool } - // HMAC hashing codes. These are transmitted as domain names. const ( HmacMD5 = "hmac-md5.sig-alg.reg.int." @@ -99,6 +104,29 @@ type timerWireFmt struct { Fudge uint16 } +// In a message and out a new message with the tsig +// added +func (t *Tsig) Generate(msg []byte) ([]byte, bool) { + rawsecret, err := packBase64([]byte(t.Secret)) + if err != nil { + return nil, false + } + buf, ok := t.Buffer(msg) + if !ok { + return nil, false + } + + h := hmac.NewMD5([]byte(rawsecret)) + io.WriteString(h, string(buf)) + + t.MAC = hex.EncodeToString(h.Sum()) // Size is half! + if !ok { + return nil, false + } + // okay, create TSIG, add to message + return nil, true +} + // Generate the HMAC for message. The TSIG RR is modified // to include the MAC and MACSize. Note the the msg Id must // already be set, otherwise the MAC will not be correct when @@ -130,6 +158,29 @@ func (t *RR_TSIG) Generate(m *Msg, secret string) bool { return true } +// Verify a TSIG on a message. All relevant data should +// be set in the Tsig structure. +func (t *Tsig) Verify(msg []byte) bool { + rawsecret, err := packBase64([]byte(t.Secret)) + if err != nil { + return false + } + // Stipped the TSIG from the incoming msg + stripped, ok := stripTsig(msg) + if !ok { + return false + } + + buf, ok := t.Buffer(stripped) + if !ok { + return false + } + + h := hmac.NewMD5([]byte(rawsecret)) + io.WriteString(h, string(buf)) + return strings.ToUpper(hex.EncodeToString(h.Sum())) == strings.ToUpper(t.MAC) +} + // Verify a TSIG. The message should be the complete with // the TSIG record still attached (as the last rr in the Additional // section). Return true on success. @@ -145,7 +196,7 @@ func (t *RR_TSIG) Verify(msg []byte, secret, reqmac string, timers bool) bool { } // t.OrigId -- need to check - stripped, ok := stripTSIG(msg) + stripped, ok := stripTsig(msg) if !ok { return false } @@ -159,6 +210,61 @@ func (t *RR_TSIG) Verify(msg []byte, secret, reqmac string, timers bool) bool { return strings.ToUpper(hex.EncodeToString(h.Sum())) == strings.ToUpper(t.MAC) } +// Create a wiredata buffer for the MAC calculation +func (t *Tsig) Buffer(msg []byte) ([]byte, bool) { + var ( + macbuf []byte + buf []byte + ) + + if t.RequestMAC != "" { + m := new(macWireFmt) + m.MACSize = uint16(len(t.RequestMAC) / 2) + m.MAC = t.RequestMAC + macbuf = make([]byte, len(t.RequestMAC)) // reqmac should be twice as long + n, ok := packStruct(m, macbuf, 0) + if !ok { + return nil, false + } + macbuf = macbuf[:n] + } + + tsigvar := make([]byte, DefaultMsgSize) + if t.Timers { + tsig := new(tsigWireFmt) + tsig.Name = strings.ToLower(t.Name) + tsig.Class = ClassANY + tsig.Ttl = 0 + tsig.Algorithm = strings.ToLower(t.Algorithm) + tsig.TimeSigned = t.TimeSigned + tsig.Fudge = t.Fudge + tsig.Error = 0 + tsig.OtherLen = 0 + tsig.OtherData = "" + n, ok1 := packStruct(tsig, tsigvar, 0) + if !ok1 { + return nil, false + } + tsigvar = tsigvar[:n] + } else { + tsig := new(timerWireFmt) + tsig.TimeSigned = t.TimeSigned + tsig.Fudge = t.Fudge + n, ok1 := packStruct(tsig, tsigvar, 0) + if !ok1 { + return nil, false + } + tsigvar = tsigvar[:n] + } + if t.RequestMAC != "" { + x := append(macbuf, msg...) + buf = append(x, tsigvar...) + } else { + buf = append(msg, tsigvar...) + } + return buf, true +} + // Create the buffer which we use for the MAC calculation. func tsigToBuf(rr *RR_TSIG, msg []byte, reqmac string, timers bool) ([]byte, bool) { var ( @@ -215,7 +321,7 @@ func tsigToBuf(rr *RR_TSIG, msg []byte, reqmac string, timers bool) ([]byte, boo } // Strip the TSIG from the pkt. -func stripTSIG(orig []byte) ([]byte, bool) { +func stripTsig(orig []byte) ([]byte, bool) { // Copied from msg.go's Unpack() // Header. var dh Header