1 package dns
2
3 import (
4 "crypto/hmac"
5 "crypto/sha1"
6 "crypto/sha256"
7 "crypto/sha512"
8 "encoding/binary"
9 "encoding/hex"
10 "hash"
11 "strconv"
12 "strings"
13 "time"
14 )
15
16
17 const (
18 HmacSHA1 = "hmac-sha1."
19 HmacSHA224 = "hmac-sha224."
20 HmacSHA256 = "hmac-sha256."
21 HmacSHA384 = "hmac-sha384."
22 HmacSHA512 = "hmac-sha512."
23
24 HmacMD5 = "hmac-md5.sig-alg.reg.int."
25 )
26
27
28 type TsigProvider interface {
29
30 Generate(msg []byte, t *TSIG) ([]byte, error)
31
32 Verify(msg []byte, t *TSIG) error
33 }
34
35 type tsigHMACProvider string
36
37 func (key tsigHMACProvider) Generate(msg []byte, t *TSIG) ([]byte, error) {
38
39 rawsecret, err := fromBase64([]byte(key))
40 if err != nil {
41 return nil, err
42 }
43 var h hash.Hash
44 switch CanonicalName(t.Algorithm) {
45 case HmacSHA1:
46 h = hmac.New(sha1.New, rawsecret)
47 case HmacSHA224:
48 h = hmac.New(sha256.New224, rawsecret)
49 case HmacSHA256:
50 h = hmac.New(sha256.New, rawsecret)
51 case HmacSHA384:
52 h = hmac.New(sha512.New384, rawsecret)
53 case HmacSHA512:
54 h = hmac.New(sha512.New, rawsecret)
55 default:
56 return nil, ErrKeyAlg
57 }
58 h.Write(msg)
59 return h.Sum(nil), nil
60 }
61
62 func (key tsigHMACProvider) Verify(msg []byte, t *TSIG) error {
63 b, err := key.Generate(msg, t)
64 if err != nil {
65 return err
66 }
67 mac, err := hex.DecodeString(t.MAC)
68 if err != nil {
69 return err
70 }
71 if !hmac.Equal(b, mac) {
72 return ErrSig
73 }
74 return nil
75 }
76
77 type tsigSecretProvider map[string]string
78
79 func (ts tsigSecretProvider) Generate(msg []byte, t *TSIG) ([]byte, error) {
80 key, ok := ts[t.Hdr.Name]
81 if !ok {
82 return nil, ErrSecret
83 }
84 return tsigHMACProvider(key).Generate(msg, t)
85 }
86
87 func (ts tsigSecretProvider) Verify(msg []byte, t *TSIG) error {
88 key, ok := ts[t.Hdr.Name]
89 if !ok {
90 return ErrSecret
91 }
92 return tsigHMACProvider(key).Verify(msg, t)
93 }
94
95
96
97 type TSIG struct {
98 Hdr RR_Header
99 Algorithm string `dns:"domain-name"`
100 TimeSigned uint64 `dns:"uint48"`
101 Fudge uint16
102 MACSize uint16
103 MAC string `dns:"size-hex:MACSize"`
104 OrigId uint16
105 Error uint16
106 OtherLen uint16
107 OtherData string `dns:"size-hex:OtherLen"`
108 }
109
110
111
112 func (rr *TSIG) String() string {
113 s := "\n;; TSIG PSEUDOSECTION:\n; "
114 s += rr.Hdr.String() +
115 " " + rr.Algorithm +
116 " " + tsigTimeToString(rr.TimeSigned) +
117 " " + strconv.Itoa(int(rr.Fudge)) +
118 " " + strconv.Itoa(int(rr.MACSize)) +
119 " " + strings.ToUpper(rr.MAC) +
120 " " + strconv.Itoa(int(rr.OrigId)) +
121 " " + strconv.Itoa(int(rr.Error)) +
122 " " + strconv.Itoa(int(rr.OtherLen)) +
123 " " + rr.OtherData
124 return s
125 }
126
127 func (*TSIG) parse(c *zlexer, origin string) *ParseError {
128 return &ParseError{err: "TSIG records do not have a presentation format"}
129 }
130
131
132
133 type tsigWireFmt struct {
134
135 Name string `dns:"domain-name"`
136 Class uint16
137 Ttl uint32
138
139 Algorithm string `dns:"domain-name"`
140 TimeSigned uint64 `dns:"uint48"`
141 Fudge uint16
142
143 Error uint16
144 OtherLen uint16
145 OtherData string `dns:"size-hex:OtherLen"`
146 }
147
148
149 type macWireFmt struct {
150 MACSize uint16
151 MAC string `dns:"size-hex:MACSize"`
152 }
153
154
155 type timerWireFmt struct {
156 TimeSigned uint64 `dns:"uint48"`
157 Fudge uint16
158 }
159
160
161
162
163
164
165
166 func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
167 return TsigGenerateWithProvider(m, tsigHMACProvider(secret), requestMAC, timersOnly)
168 }
169
170
171 func TsigGenerateWithProvider(m *Msg, provider TsigProvider, requestMAC string, timersOnly bool) ([]byte, string, error) {
172 if m.IsTsig() == nil {
173 panic("dns: TSIG not last RR in additional")
174 }
175
176 rr := m.Extra[len(m.Extra)-1].(*TSIG)
177 m.Extra = m.Extra[0 : len(m.Extra)-1]
178 mbuf, err := m.Pack()
179 if err != nil {
180 return nil, "", err
181 }
182
183 buf, err := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
184 if err != nil {
185 return nil, "", err
186 }
187
188 t := new(TSIG)
189
190 *t = *rr
191 t.TimeSigned = 0
192 t.MAC = ""
193 t.MACSize = 0
194
195
196 if rr.Error != RcodeBadKey && rr.Error != RcodeBadSig {
197 mac, err := provider.Generate(buf, rr)
198 if err != nil {
199 return nil, "", err
200 }
201 t.TimeSigned = rr.TimeSigned
202 t.MAC = hex.EncodeToString(mac)
203 t.MACSize = uint16(len(t.MAC) / 2)
204 }
205
206 tbuf := make([]byte, Len(t))
207 off, err := PackRR(t, tbuf, 0, nil, false)
208 if err != nil {
209 return nil, "", err
210 }
211 mbuf = append(mbuf, tbuf[:off]...)
212
213 binary.BigEndian.PutUint16(mbuf[10:], uint16(len(m.Extra)+1))
214
215 return mbuf, t.MAC, nil
216 }
217
218
219
220
221 func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
222 return tsigVerify(msg, tsigHMACProvider(secret), requestMAC, timersOnly, uint64(time.Now().Unix()))
223 }
224
225
226 func TsigVerifyWithProvider(msg []byte, provider TsigProvider, requestMAC string, timersOnly bool) error {
227 return tsigVerify(msg, provider, requestMAC, timersOnly, uint64(time.Now().Unix()))
228 }
229
230
231 func tsigVerify(msg []byte, provider TsigProvider, requestMAC string, timersOnly bool, now uint64) error {
232
233 stripped, tsig, err := stripTsig(msg)
234 if err != nil {
235 return err
236 }
237
238 buf, err := tsigBuffer(stripped, tsig, requestMAC, timersOnly)
239 if err != nil {
240 return err
241 }
242
243 if err := provider.Verify(buf, tsig); err != nil {
244 return err
245 }
246
247
248
249
250
251 ti := now - tsig.TimeSigned
252 if now < tsig.TimeSigned {
253 ti = tsig.TimeSigned - now
254 }
255 if uint64(tsig.Fudge) < ti {
256 return ErrTime
257 }
258
259 return nil
260 }
261
262
263 func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) ([]byte, error) {
264 var buf []byte
265 if rr.TimeSigned == 0 {
266 rr.TimeSigned = uint64(time.Now().Unix())
267 }
268 if rr.Fudge == 0 {
269 rr.Fudge = 300
270 }
271
272
273 binary.BigEndian.PutUint16(msgbuf[0:2], rr.OrigId)
274
275 if requestMAC != "" {
276 m := new(macWireFmt)
277 m.MACSize = uint16(len(requestMAC) / 2)
278 m.MAC = requestMAC
279 buf = make([]byte, len(requestMAC))
280 n, err := packMacWire(m, buf)
281 if err != nil {
282 return nil, err
283 }
284 buf = buf[:n]
285 }
286
287 tsigvar := make([]byte, DefaultMsgSize)
288 if timersOnly {
289 tsig := new(timerWireFmt)
290 tsig.TimeSigned = rr.TimeSigned
291 tsig.Fudge = rr.Fudge
292 n, err := packTimerWire(tsig, tsigvar)
293 if err != nil {
294 return nil, err
295 }
296 tsigvar = tsigvar[:n]
297 } else {
298 tsig := new(tsigWireFmt)
299 tsig.Name = CanonicalName(rr.Hdr.Name)
300 tsig.Class = ClassANY
301 tsig.Ttl = rr.Hdr.Ttl
302 tsig.Algorithm = CanonicalName(rr.Algorithm)
303 tsig.TimeSigned = rr.TimeSigned
304 tsig.Fudge = rr.Fudge
305 tsig.Error = rr.Error
306 tsig.OtherLen = rr.OtherLen
307 tsig.OtherData = rr.OtherData
308 n, err := packTsigWire(tsig, tsigvar)
309 if err != nil {
310 return nil, err
311 }
312 tsigvar = tsigvar[:n]
313 }
314
315 if requestMAC != "" {
316 x := append(buf, msgbuf...)
317 buf = append(x, tsigvar...)
318 } else {
319 buf = append(msgbuf, tsigvar...)
320 }
321 return buf, nil
322 }
323
324
325 func stripTsig(msg []byte) ([]byte, *TSIG, error) {
326
327 var (
328 dh Header
329 err error
330 )
331 off, tsigoff := 0, 0
332
333 if dh, off, err = unpackMsgHdr(msg, off); err != nil {
334 return nil, nil, err
335 }
336 if dh.Arcount == 0 {
337 return nil, nil, ErrNoSig
338 }
339
340
341 if int(dh.Bits&0xF) == RcodeNotAuth {
342 return nil, nil, ErrAuth
343 }
344
345 for i := 0; i < int(dh.Qdcount); i++ {
346 _, off, err = unpackQuestion(msg, off)
347 if err != nil {
348 return nil, nil, err
349 }
350 }
351
352 _, off, err = unpackRRslice(int(dh.Ancount), msg, off)
353 if err != nil {
354 return nil, nil, err
355 }
356 _, off, err = unpackRRslice(int(dh.Nscount), msg, off)
357 if err != nil {
358 return nil, nil, err
359 }
360
361 rr := new(TSIG)
362 var extra RR
363 for i := 0; i < int(dh.Arcount); i++ {
364 tsigoff = off
365 extra, off, err = UnpackRR(msg, off)
366 if err != nil {
367 return nil, nil, err
368 }
369 if extra.Header().Rrtype == TypeTSIG {
370 rr = extra.(*TSIG)
371
372 arcount := binary.BigEndian.Uint16(msg[10:])
373 binary.BigEndian.PutUint16(msg[10:], arcount-1)
374 break
375 }
376 }
377 if rr == nil {
378 return nil, nil, ErrNoSig
379 }
380 return msg[:tsigoff], rr, nil
381 }
382
383
384
385 func tsigTimeToString(t uint64) string {
386 ti := time.Unix(int64(t), 0).UTC()
387 return ti.Format("20060102150405")
388 }
389
390 func packTsigWire(tw *tsigWireFmt, msg []byte) (int, error) {
391
392
393 off, err := PackDomainName(tw.Name, msg, 0, nil, false)
394 if err != nil {
395 return off, err
396 }
397 off, err = packUint16(tw.Class, msg, off)
398 if err != nil {
399 return off, err
400 }
401 off, err = packUint32(tw.Ttl, msg, off)
402 if err != nil {
403 return off, err
404 }
405
406 off, err = PackDomainName(tw.Algorithm, msg, off, nil, false)
407 if err != nil {
408 return off, err
409 }
410 off, err = packUint48(tw.TimeSigned, msg, off)
411 if err != nil {
412 return off, err
413 }
414 off, err = packUint16(tw.Fudge, msg, off)
415 if err != nil {
416 return off, err
417 }
418
419 off, err = packUint16(tw.Error, msg, off)
420 if err != nil {
421 return off, err
422 }
423 off, err = packUint16(tw.OtherLen, msg, off)
424 if err != nil {
425 return off, err
426 }
427 off, err = packStringHex(tw.OtherData, msg, off)
428 if err != nil {
429 return off, err
430 }
431 return off, nil
432 }
433
434 func packMacWire(mw *macWireFmt, msg []byte) (int, error) {
435 off, err := packUint16(mw.MACSize, msg, 0)
436 if err != nil {
437 return off, err
438 }
439 off, err = packStringHex(mw.MAC, msg, off)
440 if err != nil {
441 return off, err
442 }
443 return off, nil
444 }
445
446 func packTimerWire(tw *timerWireFmt, msg []byte) (int, error) {
447 off, err := packUint48(tw.TimeSigned, msg, 0)
448 if err != nil {
449 return off, err
450 }
451 off, err = packUint16(tw.Fudge, msg, off)
452 if err != nil {
453 return off, err
454 }
455 return off, nil
456 }
457
View as plain text