OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / miekg / dns / tsig.go
1 package dns
2
3 import (
4         "crypto/hmac"
5         "crypto/md5"
6         "crypto/sha1"
7         "crypto/sha256"
8         "crypto/sha512"
9         "encoding/binary"
10         "encoding/hex"
11         "hash"
12         "strconv"
13         "strings"
14         "time"
15 )
16
17 // HMAC hashing codes. These are transmitted as domain names.
18 const (
19         HmacMD5    = "hmac-md5.sig-alg.reg.int."
20         HmacSHA1   = "hmac-sha1."
21         HmacSHA256 = "hmac-sha256."
22         HmacSHA512 = "hmac-sha512."
23 )
24
25 // TSIG is the RR the holds the transaction signature of a message.
26 // See RFC 2845 and RFC 4635.
27 type TSIG struct {
28         Hdr        RR_Header
29         Algorithm  string `dns:"domain-name"`
30         TimeSigned uint64 `dns:"uint48"`
31         Fudge      uint16
32         MACSize    uint16
33         MAC        string `dns:"size-hex:MACSize"`
34         OrigId     uint16
35         Error      uint16
36         OtherLen   uint16
37         OtherData  string `dns:"size-hex:OtherLen"`
38 }
39
40 // TSIG has no official presentation format, but this will suffice.
41
42 func (rr *TSIG) String() string {
43         s := "\n;; TSIG PSEUDOSECTION:\n"
44         s += rr.Hdr.String() +
45                 " " + rr.Algorithm +
46                 " " + tsigTimeToString(rr.TimeSigned) +
47                 " " + strconv.Itoa(int(rr.Fudge)) +
48                 " " + strconv.Itoa(int(rr.MACSize)) +
49                 " " + strings.ToUpper(rr.MAC) +
50                 " " + strconv.Itoa(int(rr.OrigId)) +
51                 " " + strconv.Itoa(int(rr.Error)) + // BIND prints NOERROR
52                 " " + strconv.Itoa(int(rr.OtherLen)) +
53                 " " + rr.OtherData
54         return s
55 }
56
57 func (rr *TSIG) parse(c *zlexer, origin, file string) *ParseError {
58         panic("dns: internal error: parse should never be called on TSIG")
59 }
60
61 // The following values must be put in wireformat, so that the MAC can be calculated.
62 // RFC 2845, section 3.4.2. TSIG Variables.
63 type tsigWireFmt struct {
64         // From RR_Header
65         Name  string `dns:"domain-name"`
66         Class uint16
67         Ttl   uint32
68         // Rdata of the TSIG
69         Algorithm  string `dns:"domain-name"`
70         TimeSigned uint64 `dns:"uint48"`
71         Fudge      uint16
72         // MACSize, MAC and OrigId excluded
73         Error     uint16
74         OtherLen  uint16
75         OtherData string `dns:"size-hex:OtherLen"`
76 }
77
78 // If we have the MAC use this type to convert it to wiredata. Section 3.4.3. Request MAC
79 type macWireFmt struct {
80         MACSize uint16
81         MAC     string `dns:"size-hex:MACSize"`
82 }
83
84 // 3.3. Time values used in TSIG calculations
85 type timerWireFmt struct {
86         TimeSigned uint64 `dns:"uint48"`
87         Fudge      uint16
88 }
89
90 // TsigGenerate fills out the TSIG record attached to the message.
91 // The message should contain
92 // a "stub" TSIG RR with the algorithm, key name (owner name of the RR),
93 // time fudge (defaults to 300 seconds) and the current time
94 // The TSIG MAC is saved in that Tsig RR.
95 // When TsigGenerate is called for the first time requestMAC is set to the empty string and
96 // timersOnly is false.
97 // If something goes wrong an error is returned, otherwise it is nil.
98 func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
99         if m.IsTsig() == nil {
100                 panic("dns: TSIG not last RR in additional")
101         }
102         // If we barf here, the caller is to blame
103         rawsecret, err := fromBase64([]byte(secret))
104         if err != nil {
105                 return nil, "", err
106         }
107
108         rr := m.Extra[len(m.Extra)-1].(*TSIG)
109         m.Extra = m.Extra[0 : len(m.Extra)-1] // kill the TSIG from the msg
110         mbuf, err := m.Pack()
111         if err != nil {
112                 return nil, "", err
113         }
114         buf := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
115
116         t := new(TSIG)
117         var h hash.Hash
118         switch strings.ToLower(rr.Algorithm) {
119         case HmacMD5:
120                 h = hmac.New(md5.New, rawsecret)
121         case HmacSHA1:
122                 h = hmac.New(sha1.New, rawsecret)
123         case HmacSHA256:
124                 h = hmac.New(sha256.New, rawsecret)
125         case HmacSHA512:
126                 h = hmac.New(sha512.New, rawsecret)
127         default:
128                 return nil, "", ErrKeyAlg
129         }
130         h.Write(buf)
131         t.MAC = hex.EncodeToString(h.Sum(nil))
132         t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
133
134         t.Hdr = RR_Header{Name: rr.Hdr.Name, Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0}
135         t.Fudge = rr.Fudge
136         t.TimeSigned = rr.TimeSigned
137         t.Algorithm = rr.Algorithm
138         t.OrigId = m.Id
139
140         tbuf := make([]byte, Len(t))
141         off, err := PackRR(t, tbuf, 0, nil, false)
142         if err != nil {
143                 return nil, "", err
144         }
145         mbuf = append(mbuf, tbuf[:off]...)
146         // Update the ArCount directly in the buffer.
147         binary.BigEndian.PutUint16(mbuf[10:], uint16(len(m.Extra)+1))
148
149         return mbuf, t.MAC, nil
150 }
151
152 // TsigVerify verifies the TSIG on a message.
153 // If the signature does not validate err contains the
154 // error, otherwise it is nil.
155 func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
156         rawsecret, err := fromBase64([]byte(secret))
157         if err != nil {
158                 return err
159         }
160         // Strip the TSIG from the incoming msg
161         stripped, tsig, err := stripTsig(msg)
162         if err != nil {
163                 return err
164         }
165
166         msgMAC, err := hex.DecodeString(tsig.MAC)
167         if err != nil {
168                 return err
169         }
170
171         buf := tsigBuffer(stripped, tsig, requestMAC, timersOnly)
172
173         // Fudge factor works both ways. A message can arrive before it was signed because
174         // of clock skew.
175         now := uint64(time.Now().Unix())
176         ti := now - tsig.TimeSigned
177         if now < tsig.TimeSigned {
178                 ti = tsig.TimeSigned - now
179         }
180         if uint64(tsig.Fudge) < ti {
181                 return ErrTime
182         }
183
184         var h hash.Hash
185         switch strings.ToLower(tsig.Algorithm) {
186         case HmacMD5:
187                 h = hmac.New(md5.New, rawsecret)
188         case HmacSHA1:
189                 h = hmac.New(sha1.New, rawsecret)
190         case HmacSHA256:
191                 h = hmac.New(sha256.New, rawsecret)
192         case HmacSHA512:
193                 h = hmac.New(sha512.New, rawsecret)
194         default:
195                 return ErrKeyAlg
196         }
197         h.Write(buf)
198         if !hmac.Equal(h.Sum(nil), msgMAC) {
199                 return ErrSig
200         }
201         return nil
202 }
203
204 // Create a wiredata buffer for the MAC calculation.
205 func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []byte {
206         var buf []byte
207         if rr.TimeSigned == 0 {
208                 rr.TimeSigned = uint64(time.Now().Unix())
209         }
210         if rr.Fudge == 0 {
211                 rr.Fudge = 300 // Standard (RFC) default.
212         }
213
214         // Replace message ID in header with original ID from TSIG
215         binary.BigEndian.PutUint16(msgbuf[0:2], rr.OrigId)
216
217         if requestMAC != "" {
218                 m := new(macWireFmt)
219                 m.MACSize = uint16(len(requestMAC) / 2)
220                 m.MAC = requestMAC
221                 buf = make([]byte, len(requestMAC)) // long enough
222                 n, _ := packMacWire(m, buf)
223                 buf = buf[:n]
224         }
225
226         tsigvar := make([]byte, DefaultMsgSize)
227         if timersOnly {
228                 tsig := new(timerWireFmt)
229                 tsig.TimeSigned = rr.TimeSigned
230                 tsig.Fudge = rr.Fudge
231                 n, _ := packTimerWire(tsig, tsigvar)
232                 tsigvar = tsigvar[:n]
233         } else {
234                 tsig := new(tsigWireFmt)
235                 tsig.Name = strings.ToLower(rr.Hdr.Name)
236                 tsig.Class = ClassANY
237                 tsig.Ttl = rr.Hdr.Ttl
238                 tsig.Algorithm = strings.ToLower(rr.Algorithm)
239                 tsig.TimeSigned = rr.TimeSigned
240                 tsig.Fudge = rr.Fudge
241                 tsig.Error = rr.Error
242                 tsig.OtherLen = rr.OtherLen
243                 tsig.OtherData = rr.OtherData
244                 n, _ := packTsigWire(tsig, tsigvar)
245                 tsigvar = tsigvar[:n]
246         }
247
248         if requestMAC != "" {
249                 x := append(buf, msgbuf...)
250                 buf = append(x, tsigvar...)
251         } else {
252                 buf = append(msgbuf, tsigvar...)
253         }
254         return buf
255 }
256
257 // Strip the TSIG from the raw message.
258 func stripTsig(msg []byte) ([]byte, *TSIG, error) {
259         // Copied from msg.go's Unpack() Header, but modified.
260         var (
261                 dh  Header
262                 err error
263         )
264         off, tsigoff := 0, 0
265
266         if dh, off, err = unpackMsgHdr(msg, off); err != nil {
267                 return nil, nil, err
268         }
269         if dh.Arcount == 0 {
270                 return nil, nil, ErrNoSig
271         }
272
273         // Rcode, see msg.go Unpack()
274         if int(dh.Bits&0xF) == RcodeNotAuth {
275                 return nil, nil, ErrAuth
276         }
277
278         for i := 0; i < int(dh.Qdcount); i++ {
279                 _, off, err = unpackQuestion(msg, off)
280                 if err != nil {
281                         return nil, nil, err
282                 }
283         }
284
285         _, off, err = unpackRRslice(int(dh.Ancount), msg, off)
286         if err != nil {
287                 return nil, nil, err
288         }
289         _, off, err = unpackRRslice(int(dh.Nscount), msg, off)
290         if err != nil {
291                 return nil, nil, err
292         }
293
294         rr := new(TSIG)
295         var extra RR
296         for i := 0; i < int(dh.Arcount); i++ {
297                 tsigoff = off
298                 extra, off, err = UnpackRR(msg, off)
299                 if err != nil {
300                         return nil, nil, err
301                 }
302                 if extra.Header().Rrtype == TypeTSIG {
303                         rr = extra.(*TSIG)
304                         // Adjust Arcount.
305                         arcount := binary.BigEndian.Uint16(msg[10:])
306                         binary.BigEndian.PutUint16(msg[10:], arcount-1)
307                         break
308                 }
309         }
310         if rr == nil {
311                 return nil, nil, ErrNoSig
312         }
313         return msg[:tsigoff], rr, nil
314 }
315
316 // Translate the TSIG time signed into a date. There is no
317 // need for RFC1982 calculations as this date is 48 bits.
318 func tsigTimeToString(t uint64) string {
319         ti := time.Unix(int64(t), 0).UTC()
320         return ti.Format("20060102150405")
321 }
322
323 func packTsigWire(tw *tsigWireFmt, msg []byte) (int, error) {
324         // copied from zmsg.go TSIG packing
325         // RR_Header
326         off, err := PackDomainName(tw.Name, msg, 0, nil, false)
327         if err != nil {
328                 return off, err
329         }
330         off, err = packUint16(tw.Class, msg, off)
331         if err != nil {
332                 return off, err
333         }
334         off, err = packUint32(tw.Ttl, msg, off)
335         if err != nil {
336                 return off, err
337         }
338
339         off, err = PackDomainName(tw.Algorithm, msg, off, nil, false)
340         if err != nil {
341                 return off, err
342         }
343         off, err = packUint48(tw.TimeSigned, msg, off)
344         if err != nil {
345                 return off, err
346         }
347         off, err = packUint16(tw.Fudge, msg, off)
348         if err != nil {
349                 return off, err
350         }
351
352         off, err = packUint16(tw.Error, msg, off)
353         if err != nil {
354                 return off, err
355         }
356         off, err = packUint16(tw.OtherLen, msg, off)
357         if err != nil {
358                 return off, err
359         }
360         off, err = packStringHex(tw.OtherData, msg, off)
361         if err != nil {
362                 return off, err
363         }
364         return off, nil
365 }
366
367 func packMacWire(mw *macWireFmt, msg []byte) (int, error) {
368         off, err := packUint16(mw.MACSize, msg, 0)
369         if err != nil {
370                 return off, err
371         }
372         off, err = packStringHex(mw.MAC, msg, off)
373         if err != nil {
374                 return off, err
375         }
376         return off, nil
377 }
378
379 func packTimerWire(tw *timerWireFmt, msg []byte) (int, error) {
380         off, err := packUint48(tw.TimeSigned, msg, 0)
381         if err != nil {
382                 return off, err
383         }
384         off, err = packUint16(tw.Fudge, msg, off)
385         if err != nil {
386                 return off, err
387         }
388         return off, nil
389 }