tsig.go (12028B)
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 // HMAC hashing codes. These are transmitted as domain names. 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." // Deprecated: HmacMD5 is no longer supported. 25 ) 26 27 // TsigProvider provides the API to plug-in a custom TSIG implementation. 28 type TsigProvider interface { 29 // Generate is passed the DNS message to be signed and the partial TSIG RR. It returns the signature and nil, otherwise an error. 30 Generate(msg []byte, t *TSIG) ([]byte, error) 31 // Verify is passed the DNS message to be verified and the TSIG RR. If the signature is valid it will return nil, otherwise an error. 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 // If we barf here, the caller is to blame 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 // TSIG is the RR the holds the transaction signature of a message. 96 // See RFC 2845 and RFC 4635. 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 // TSIG has no official presentation format, but this will suffice. 111 112 func (rr *TSIG) String() string { 113 s := "\n;; TSIG PSEUDOSECTION:\n; " // add another semi-colon to signify TSIG does not have a presentation format 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)) + // BIND prints NOERROR 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 // The following values must be put in wireformat, so that the MAC can be calculated. 132 // RFC 2845, section 3.4.2. TSIG Variables. 133 type tsigWireFmt struct { 134 // From RR_Header 135 Name string `dns:"domain-name"` 136 Class uint16 137 Ttl uint32 138 // Rdata of the TSIG 139 Algorithm string `dns:"domain-name"` 140 TimeSigned uint64 `dns:"uint48"` 141 Fudge uint16 142 // MACSize, MAC and OrigId excluded 143 Error uint16 144 OtherLen uint16 145 OtherData string `dns:"size-hex:OtherLen"` 146 } 147 148 // If we have the MAC use this type to convert it to wiredata. Section 3.4.3. Request MAC 149 type macWireFmt struct { 150 MACSize uint16 151 MAC string `dns:"size-hex:MACSize"` 152 } 153 154 // 3.3. Time values used in TSIG calculations 155 type timerWireFmt struct { 156 TimeSigned uint64 `dns:"uint48"` 157 Fudge uint16 158 } 159 160 // TsigGenerate fills out the TSIG record attached to the message. 161 // The message should contain a "stub" TSIG RR with the algorithm, key name 162 // (owner name of the RR), time fudge (defaults to 300 seconds) and the current 163 // time The TSIG MAC is saved in that Tsig RR. When TsigGenerate is called for 164 // the first time requestMAC should be set to the empty string and timersOnly to 165 // false. 166 func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) { 167 return TsigGenerateWithProvider(m, tsigHMACProvider(secret), requestMAC, timersOnly) 168 } 169 170 // TsigGenerateWithProvider is similar to TsigGenerate, but allows for a custom TsigProvider. 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] // kill the TSIG from the msg 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 // Copy all TSIG fields except MAC, its size, and time signed which are filled when signing. 190 *t = *rr 191 t.TimeSigned = 0 192 t.MAC = "" 193 t.MACSize = 0 194 195 // Sign unless there is a key or MAC validation error (RFC 8945 5.3.2) 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) // Size is half! 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 // Update the ArCount directly in the buffer. 213 binary.BigEndian.PutUint16(mbuf[10:], uint16(len(m.Extra)+1)) 214 215 return mbuf, t.MAC, nil 216 } 217 218 // TsigVerify verifies the TSIG on a message. If the signature does not 219 // validate the returned error contains the cause. If the signature is OK, the 220 // error is nil. 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 // TsigVerifyWithProvider is similar to TsigVerify, but allows for a custom TsigProvider. 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 // actual implementation of TsigVerify, taking the current time ('now') as a parameter for the convenience of tests. 231 func tsigVerify(msg []byte, provider TsigProvider, requestMAC string, timersOnly bool, now uint64) error { 232 // Strip the TSIG from the incoming msg 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 // Fudge factor works both ways. A message can arrive before it was signed because 248 // of clock skew. 249 // We check this after verifying the signature, following draft-ietf-dnsop-rfc2845bis 250 // instead of RFC2845, in order to prevent a security vulnerability as reported in CVE-2017-3142/3143. 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 // Create a wiredata buffer for the MAC calculation. 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 // Standard (RFC) default. 270 } 271 272 // Replace message ID in header with original ID from TSIG 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)) // long enough 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 // Strip the TSIG from the raw message. 325 func stripTsig(msg []byte) ([]byte, *TSIG, error) { 326 // Copied from msg.go's Unpack() Header, but modified. 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 // Rcode, see msg.go Unpack() 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 // Adjust Arcount. 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 // Translate the TSIG time signed into a date. There is no 384 // need for RFC1982 calculations as this date is 48 bits. 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 // copied from zmsg.go TSIG packing 392 // RR_Header 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 }