Repository: miekg/dns
Pull request #1139 (2020-07-21 19:56:16)

add support for HMAC SHA224 and 384 TSIG algorithms
This PR is a trivial implementation of supporting HMAC SHA224 and HMAC SHA384 for TSIG.

While these algorithms are "optional" per RFC4635, they are supported in other implementations such as BIND, so supporting them would be nice for better interoperability (and the implementation is trivial).

codecov-commenter: # [Codecov](https://codecov.io/gh/miekg/dns/pull/1139?src=pr&el=h1) Report
> Merging [#1139](https://codecov.io/gh/miekg/dns/pull/1139?src=pr&el=desc) into [master](https://codecov.io/gh/miekg/dns/commit/f3da20bc009ca53ef3569e107b1f82819f3cc7f1&el=desc) will **increase** coverage by `0.03%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/miekg/dns/pull/1139/graphs/tree.svg?width=650&height=150&src=pr&token=uT9fYPSeKT)](https://codecov.io/gh/miekg/dns/pull/1139?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #1139      +/-   ##
==========================================
+ Coverage   55.47%   55.51%   +0.03%     
==========================================
  Files          41       41              
  Lines       10116    10124       +8     
==========================================
+ Hits         5612     5620       +8     
  Misses       3480     3480              
  Partials     1024     1024              
```


| [Impacted Files](https://codecov.io/gh/miekg/dns/pull/1139?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [tsig.go](https://codecov.io/gh/miekg/dns/pull/1139/diff?src=pr&el=tree#diff-dHNpZy5nbw==) | `57.01% <100.00%> (+1.56%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/miekg/dns/pull/1139?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/miekg/dns/pull/1139?src=pr&el=footer). Last update [f3da20b...fd4ff98](https://codecov.io/gh/miekg/dns/pull/1139?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/tsig.go b/tsig.go
index 86d11b6f..c207d616 100644
--- a/tsig.go
+++ b/tsig.go
@@ -18,7 +18,9 @@ import (
 const (
 	HmacMD5    = "hmac-md5.sig-alg.reg.int."
 	HmacSHA1   = "hmac-sha1."
+	HmacSHA224 = "hmac-sha224."
 	HmacSHA256 = "hmac-sha256."
+	HmacSHA384 = "hmac-sha384."
 	HmacSHA512 = "hmac-sha512."
 )
 
@@ -123,8 +125,12 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s
 		h = hmac.New(md5.New, rawsecret)
 	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:
@@ -183,8 +189,12 @@ func tsigVerify(msg []byte, secret, requestMAC string, timersOnly bool, now uint
 		h = hmac.New(md5.New, rawsecret)
 	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:


Test patch:
diff --git a/tsig_test.go b/tsig_test.go
index c74b20a5..5b63fd9f 100644
--- a/tsig_test.go
+++ b/tsig_test.go
@@ -192,3 +192,48 @@ func TestTsigGenerate(t *testing.T) {
 		})
 	}
 }
+
+func TestTSIGHMAC224And384(t *testing.T) {
+	tests := []struct {
+		algorithm   string // TSIG algorithm, also used as test description
+		secret      string // (arbitrarily chosen) secret suitable for the algorithm in base64 format
+		expectedMAC string // pre-computed expected (correct) MAC in hex form
+	}{
+		{HmacSHA224, "hVEkQuAqnTmBuRrT9KF1Udr91gOMGWPw9LaTtw==",
+			"d6daf9ea189e48bc38f9aed63d6cc4140cdfa38a7a333ee2eefdbd31",
+		},
+		{HmacSHA384, "Qjer2TL2lAdpq9w6Gjs98/ClCQx/L3vtgVHCmrZ8l/oKEPjqUUMFO18gMCRwd5H4",
+			"89a48936d29187870c325cbdba5ad71609bd038d0459d6010c844d659c570e881d3650e4fe7310be53ebe5178d0d1001",
+		},
+	}
+	for _, tc := range tests {
+		tc := tc
+		t.Run(tc.algorithm, func(t *testing.T) {
+			// Build a DNS message with TSIG for the test scenario
+			tsig := TSIG{
+				Hdr:        RR_Header{Name: "testkey.", Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0},
+				Algorithm:  tc.algorithm,
+				TimeSigned: timeSigned,
+				Fudge:      300,
+				OrigId:     42,
+			}
+			req := &Msg{
+				MsgHdr:   MsgHdr{Opcode: OpcodeUpdate},
+				Question: []Question{Question{Name: "example.com.", Qtype: TypeSOA, Qclass: ClassINET}},
+				Extra:    []RR{&tsig},
+			}
+
+			// Confirm both Generate and Verify recognize the algorithm and handle it correctly
+			msgData, mac, err := TsigGenerate(req, tc.secret, "", false)
+			if err != nil {
+				t.Error(err)
+			}
+			if mac != tc.expectedMAC {
+				t.Fatalf("MAC doesn't match: expected '%s' but got '%s'", tc.expectedMAC, mac)
+			}
+			if err = tsigVerify(msgData, tc.secret, "", false, timeSigned); err != nil {
+				t.Error(err)
+			}
+		})
+	}
+}