Package dns :: Module tsig
[hide private]
[frames] | no frames]

Source Code for Module dns.tsig

  1  # Copyright (C) 2001-2007, 2009 Nominum, Inc. 
  2  # 
  3  # Permission to use, copy, modify, and distribute this software and its 
  4  # documentation for any purpose with or without fee is hereby granted, 
  5  # provided that the above copyright notice and this permission notice 
  6  # appear in all copies. 
  7  # 
  8  # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 
  9  # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 
 10  # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 
 11  # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
 12  # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
 13  # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 
 14  # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
 15   
 16  """DNS TSIG support.""" 
 17   
 18  import hmac 
 19  import struct 
 20   
 21  import dns.exception 
 22  import dns.rdataclass 
 23  import dns.name 
 24   
25 -class BadTime(dns.exception.DNSException):
26 """Raised if the current time is not within the TSIG's validity time.""" 27 pass
28
29 -class BadSignature(dns.exception.DNSException):
30 """Raised if the TSIG signature fails to verify.""" 31 pass
32
33 -class PeerError(dns.exception.DNSException):
34 """Base class for all TSIG errors generated by the remote peer""" 35 pass
36
37 -class PeerBadKey(PeerError):
38 """Raised if the peer didn't know the key we used""" 39 pass
40
41 -class PeerBadSignature(PeerError):
42 """Raised if the peer didn't like the signature we sent""" 43 pass
44
45 -class PeerBadTime(PeerError):
46 """Raised if the peer didn't like the time we sent""" 47 pass
48
49 -class PeerBadTruncation(PeerError):
50 """Raised if the peer didn't like amount of truncation in the TSIG we sent""" 51 pass
52 53 _alg_name = dns.name.from_text('HMAC-MD5.SIG-ALG.REG.INT.').to_digestable() 54 55 BADSIG = 16 56 BADKEY = 17 57 BADTIME = 18 58 BADTRUNC = 22 59
60 -def hmac_md5(wire, keyname, secret, time, fudge, original_id, error, 61 other_data, request_mac, ctx=None, multi=False, first=True):
62 """Return a (tsig_rdata, mac, ctx) tuple containing the HMAC-MD5 TSIG rdata 63 for the input parameters, the HMAC-MD5 MAC calculated by applying the 64 TSIG signature algorithm, and the TSIG digest context. 65 @rtype: (string, string, hmac.HMAC object) 66 @raises ValueError: I{other_data} is too long 67 """ 68 69 if first: 70 ctx = hmac.new(secret) 71 ml = len(request_mac) 72 if ml > 0: 73 ctx.update(struct.pack('!H', ml)) 74 ctx.update(request_mac) 75 id = struct.pack('!H', original_id) 76 ctx.update(id) 77 ctx.update(wire[2:]) 78 if first: 79 ctx.update(keyname.to_digestable()) 80 ctx.update(struct.pack('!H', dns.rdataclass.ANY)) 81 ctx.update(struct.pack('!I', 0)) 82 long_time = time + 0L 83 upper_time = (long_time >> 32) & 0xffffL 84 lower_time = long_time & 0xffffffffL 85 time_mac = struct.pack('!HIH', upper_time, lower_time, fudge) 86 pre_mac = _alg_name + time_mac 87 ol = len(other_data) 88 if ol > 65535: 89 raise ValueError, 'TSIG Other Data is > 65535 bytes' 90 post_mac = struct.pack('!HH', error, ol) + other_data 91 if first: 92 ctx.update(pre_mac) 93 ctx.update(post_mac) 94 else: 95 ctx.update(time_mac) 96 mac = ctx.digest() 97 mpack = struct.pack('!H', len(mac)) 98 tsig_rdata = pre_mac + mpack + mac + id + post_mac 99 if multi: 100 ctx = hmac.new(secret) 101 ml = len(mac) 102 ctx.update(struct.pack('!H', ml)) 103 ctx.update(mac) 104 else: 105 ctx = None 106 return (tsig_rdata, mac, ctx)
107
108 -def validate(wire, keyname, secret, now, request_mac, tsig_start, tsig_rdata, 109 tsig_rdlen, ctx=None, multi=False, first=True):
110 """Validate the specified TSIG rdata against the other input parameters. 111 112 @raises FormError: The TSIG is badly formed. 113 @raises BadTime: There is too much time skew between the client and the 114 server. 115 @raises BadSignature: The TSIG signature did not validate 116 @rtype: hmac.HMAC object""" 117 118 (adcount,) = struct.unpack("!H", wire[10:12]) 119 if adcount == 0: 120 raise dns.exception.FormError 121 adcount -= 1 122 new_wire = wire[0:10] + struct.pack("!H", adcount) + wire[12:tsig_start] 123 current = tsig_rdata 124 (aname, used) = dns.name.from_wire(wire, current) 125 current = current + used 126 (upper_time, lower_time, fudge, mac_size) = \ 127 struct.unpack("!HIHH", wire[current:current + 10]) 128 time = ((upper_time + 0L) << 32) + (lower_time + 0L) 129 current += 10 130 mac = wire[current:current + mac_size] 131 current += mac_size 132 (original_id, error, other_size) = \ 133 struct.unpack("!HHH", wire[current:current + 6]) 134 current += 6 135 other_data = wire[current:current + other_size] 136 current += other_size 137 if current != tsig_rdata + tsig_rdlen: 138 raise dns.exception.FormError 139 if error != 0: 140 if error == BADSIG: 141 raise PeerBadSignature 142 elif error == BADKEY: 143 raise PeerBadKey 144 elif error == BADTIME: 145 raise PeerBadTime 146 elif error == BADTRUNC: 147 raise PeerBadTruncation 148 else: 149 raise PeerError, 'unknown TSIG error code %d' % error 150 time_low = time - fudge 151 time_high = time + fudge 152 if now < time_low or now > time_high: 153 raise BadTime 154 (junk, our_mac, ctx) = hmac_md5(new_wire, keyname, secret, time, fudge, 155 original_id, error, other_data, 156 request_mac, ctx, multi, first) 157 if (our_mac != mac): 158 raise BadSignature 159 return ctx
160