1 # ldd - DNS implementation in Python
2 # Copyright (C) 2006 Fredrik Tolf <fredrik@dolda2000.com>
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 from Crypto.Hash import HMAC, MD5
26 def __init__(self, name, algo, secret):
28 self.name = dn.fromstring(name)
32 self.algo = algobyname[algo]
37 def sign(self, message):
38 return self.algo.sign(self.secret, message)
41 def __init__(self, name, cname, function):
43 if type(cname) == str:
44 self.cname = dn.fromstring(cname)
47 self.function = function
49 def sign(self, secret, message):
50 return self.function(secret, message)
53 def __init__(self, key, pkt, sr):
55 self.prevmac = sr.data["mac"]
58 def signpkt(self, pkt):
59 tsigsign(pkt, None, ctx = self, error = self.error)
61 def tsigsign(pkt, key, stime = None, fudge = 300, error = 0, other = "", ctx = None):
62 if stime is None: stime = int(time.time())
67 msg += struct.pack(">H", len(ctx.prevmac)) + ctx.prevmac
69 msg += key.name.canonwire()
70 msg += struct.pack(">HL", rec.CLASSANY, 0)
71 msg += key.algo.cname.canonwire()
72 msg += struct.pack(">Q", stime)[-6:]
73 msg += struct.pack(">3H", fudge, error, len(other))
75 digest = key.sign(msg)
76 pkt.addad(rec.rr((key.name, "TSIG", rec.CLASSANY), 0, rec.rrdata("TSIG", key.algo.cname, stime, fudge, digest, pkt.qid, error, other)))
79 def tsigverify(pkt, keys, vertime = None):
80 if vertime is None: vertime = int(time.time())
81 if len(pkt.adlist) < 1:
84 pkt.adlist = pkt.adlist[:-1]
85 if not sr.head.istype("TSIG") or sr.head.rclass != rec.CLASSANY:
88 if key.name == sr.head.name:
92 if key.algo.cname != sr.data["algo"]:
95 pkt.tsigctx = ctx = tsigctx(key, pkt, sr)
97 other = sr.data["other"]
99 msg += key.name.canonwire()
100 msg += struct.pack(">HL", rec.CLASSANY, 0)
101 msg += key.algo.cname.canonwire()
102 msg += struct.pack(">Q", sr.data["stime"])[-6:]
103 msg += struct.pack(">3H", sr.data["fudge"], sr.data["err"], len(other))
105 digest = key.sign(msg)
106 if digest != sr.data["mac"]:
107 pkt.tsigctx = proto.BADSIG
110 if abs(vertime - sr.data["stime"]) > sr.data["fudge"]:
111 pkt.tsigctx = proto.BADTIME
115 def signhmacmd5(secret, message):
116 s = HMAC.HMAC(secret, digestmod = MD5)
120 def readkeys(keyfile):
122 if type(keyfile) == str:
123 keyfile = open(keyfile, "r")
131 ret += [tsigkey(dn.fromstring(words[0]), words[1], base64.b64decode(words[2]))]
134 if close: keyfile.close()
136 algos = [tsigalgo("hmac-md5", "hmac-md5.sig-alg.reg.int.", signhmacmd5)]
138 algobyname = dict([(a.name, a) for a in algos])