Skip to content

Commit

Permalink
Per RFC 8945 5.3.2, responses with BADKEY and BADSIG errors must not …
Browse files Browse the repository at this point in the history
…be signed.

Signed-off-by: Chris O'Haver <cohaver@infoblox.com>
  • Loading branch information
chrisohaver committed Dec 3, 2021
1 parent 3b8982c commit a695a65
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 11 deletions.
33 changes: 22 additions & 11 deletions tsig.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,20 +162,31 @@ func tsigGenerateProvider(m *Msg, provider TsigProvider, requestMAC string, time
if err != nil {
return nil, "", err
}
buf, err := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
if err != nil {
return nil, "", err
}

t := new(TSIG)
// 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

if rr.Error == RcodeSuccess || rr.Error == RcodeBadTime {
// Only compute response MAC for non-errors and bad time errors (RFC 8945 5.3.2)
buf, err := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
if err != nil {
return nil, "", err
}
// 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
}
t.TimeSigned = rr.TimeSigned
t.MAC = hex.EncodeToString(mac)
t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
} else {
// Copy all TSIG fields except MAC, its size and time signed, since we aren't signing.
*t = *rr
t.TimeSigned = 0
t.MAC = ""
t.MACSize = 0
}
t.MAC = hex.EncodeToString(mac)
t.MACSize = uint16(len(t.MAC) / 2) // Size is half!

tbuf := make([]byte, Len(t))
off, err := PackRR(t, tbuf, 0, nil, false)
Expand Down
56 changes: 56 additions & 0 deletions tsig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,62 @@ func TestTsigCase(t *testing.T) {
}
}

func TestTsigErrorResponse(t *testing.T) {
for _, rcode := range []uint16{RcodeBadSig, RcodeBadKey} {
m := newTsig(strings.ToUpper(HmacSHA256))
m.IsTsig().Error = rcode
buf, _, err := TsigGenerate(m, "pRZgBrBvI4NAHZYhxmhs/Q==", "", false)
if err != nil {
t.Fatal(err)
}

err = m.Unpack(buf)
if err != nil {
t.Fatal(err)
}

mTsig := m.IsTsig()
if mTsig.MAC != "" {
t.Error("Expected empty MAC")
}
if mTsig.MACSize != 0 {
t.Error("Expected 0 MACSize")
}
if mTsig.TimeSigned != 0 {
t.Errorf("Expected TimeSigned to be 0, got %v", mTsig.TimeSigned)
}
}
}

func TestTsigBadTimeResponse(t *testing.T) {
clientTime := uint64(time.Now().Unix()) - 3600
m := newTsig(strings.ToUpper(HmacSHA256))
m.IsTsig().Error = RcodeBadTime
m.IsTsig().TimeSigned = clientTime

buf, _, err := TsigGenerate(m, "pRZgBrBvI4NAHZYhxmhs/Q==", "", false)
if err != nil {
t.Fatal(err)
}

err = m.Unpack(buf)
if err != nil {
t.Fatal(err)
}

mTsig := m.IsTsig()
if mTsig.MAC == "" {
t.Error("Expected non-empty MAC")
}
if int(mTsig.MACSize) != len(mTsig.MAC)/2 {
t.Errorf("Expected MACSize %v, got %v", len(mTsig.MAC)/2, mTsig.MACSize)
}

if mTsig.TimeSigned != clientTime {
t.Errorf("Expected TimeSigned %v to be retained, got %v", clientTime, mTsig.TimeSigned)
}
}

const (
// A template wire-format DNS message (in hex form) containing a TSIG RR.
// Its time signed field will be filled by tests.
Expand Down

0 comments on commit a695a65

Please sign in to comment.