1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
30 """Raised if the TSIG signature fails to verify."""
31 pass
32
34 """Base class for all TSIG errors generated by the remote peer"""
35 pass
36
38 """Raised if the peer didn't know the key we used"""
39 pass
40
42 """Raised if the peer didn't like the signature we sent"""
43 pass
44
46 """Raised if the peer didn't like the time we sent"""
47 pass
48
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