diff --git a/dnspython-1.11.1-ecdsa-loc.patch b/dnspython-1.11.1-ecdsa-loc.patch new file mode 100644 index 0000000..7c1aba5 --- /dev/null +++ b/dnspython-1.11.1-ecdsa-loc.patch @@ -0,0 +1,1671 @@ +diff -Naur dnspython-orig/dnspython-1.11.1/ChangeLog dnspython/dnspython-1.11.1/ChangeLog +--- dnspython-orig/dnspython-1.11.1/ChangeLog 2013-09-02 14:50:25.000000000 -0400 ++++ dnspython/dnspython-1.11.1/ChangeLog 2014-02-18 18:36:33.484753464 -0500 +@@ -1,3 +1,9 @@ ++2013-12-11 Bob Halley ++ ++ * dns/query.py: Fix problems with the IXFR state machine which caused ++ long diffs to fail. Thanks to James Raftery for the fix and the ++ repeated prodding to get it applied :) ++ + 2013-09-02 Bob Halley + + * (Version 1.11.1 released) +diff -Naur dnspython-orig/dnspython-1.11.1/dns/dnssec.py dnspython/dnspython-1.11.1/dns/dnssec.py +--- dnspython-orig/dnspython-1.11.1/dns/dnssec.py 2013-08-09 13:03:27.000000000 -0400 ++++ dnspython/dnspython-1.11.1/dns/dnssec.py 2014-02-18 18:36:33.485753475 -0500 +@@ -45,6 +45,8 @@ + RSASHA1NSEC3SHA1 = 7 + RSASHA256 = 8 + RSASHA512 = 10 ++ECDSAP256SHA256 = 13 ++ECDSAP384SHA384 = 14 + INDIRECT = 252 + PRIVATEDNS = 253 + PRIVATEOID = 254 +@@ -60,6 +62,8 @@ + 'RSASHA256' : RSASHA256, + 'RSASHA512' : RSASHA512, + 'INDIRECT' : INDIRECT, ++ 'ECDSAP256SHA256' : ECDSAP256SHA256, ++ 'ECDSAP384SHA384' : ECDSAP384SHA384, + 'PRIVATEDNS' : PRIVATEDNS, + 'PRIVATEOID' : PRIVATEOID, + } +@@ -153,6 +157,9 @@ + def _is_dsa(algorithm): + return algorithm in (DSA, DSANSEC3SHA1) + ++def _is_ecdsa(algorithm): ++ return _have_ecdsa and (algorithm in (ECDSAP256SHA256, ECDSAP384SHA384)) ++ + def _is_md5(algorithm): + return algorithm == RSAMD5 + +@@ -161,7 +168,10 @@ + DSANSEC3SHA1, RSASHA1NSEC3SHA1) + + def _is_sha256(algorithm): +- return algorithm == RSASHA256 ++ return algorithm in (RSASHA256, ECDSAP256SHA256) ++ ++def _is_sha384(algorithm): ++ return algorithm == ECDSAP384SHA384 + + def _is_sha512(algorithm): + return algorithm == RSASHA512 +@@ -173,6 +183,8 @@ + return dns.hash.get('SHA1')() + if _is_sha256(algorithm): + return dns.hash.get('SHA256')() ++ if _is_sha384(algorithm): ++ return dns.hash.get('SHA384')() + if _is_sha512(algorithm): + return dns.hash.get('SHA512')() + raise ValidationFailure, 'unknown hash for algorithm %u' % algorithm +@@ -274,6 +286,30 @@ + (dsa_r, dsa_s) = struct.unpack('!20s20s', rrsig.signature[1:]) + sig = (Crypto.Util.number.bytes_to_long(dsa_r), + Crypto.Util.number.bytes_to_long(dsa_s)) ++ elif _is_ecdsa(rrsig.algorithm): ++ if rrsig.algorithm == ECDSAP256SHA256: ++ curve = ecdsa.curves.NIST256p ++ key_len = 32 ++ digest_len = 32 ++ elif rrsig.algorithm == ECDSAP384SHA384: ++ curve = ecdsa.curves.NIST384p ++ key_len = 48 ++ digest_len = 48 ++ else: ++ # shouldn't happen ++ raise ValidationFailure, 'unknown ECDSA curve' ++ keyptr = candidate_key.key ++ x = Crypto.Util.number.bytes_to_long(keyptr[0:key_len]) ++ y = Crypto.Util.number.bytes_to_long(keyptr[key_len:key_len * 2]) ++ assert ecdsa.ecdsa.point_is_valid(curve.generator, x, y) ++ point = ecdsa.ellipticcurve.Point(curve.curve, x, y, curve.order) ++ verifying_key = ecdsa.keys.VerifyingKey.from_public_point(point, ++ curve) ++ pubkey = ECKeyWrapper(verifying_key, key_len) ++ r = rrsig.signature[:key_len] ++ s = rrsig.signature[key_len:] ++ sig = ecdsa.ecdsa.Signature(Crypto.Util.number.bytes_to_long(r), ++ Crypto.Util.number.bytes_to_long(s)) + else: + raise ValidationFailure, 'unknown algorithm %u' % rrsig.algorithm + +@@ -302,7 +338,7 @@ + digest = _make_algorithm_id(rrsig.algorithm) + digest + padlen = keylen // 8 - len(digest) - 3 + digest = chr(0) + chr(1) + chr(0xFF) * padlen + chr(0) + digest +- elif _is_dsa(rrsig.algorithm): ++ elif _is_dsa(rrsig.algorithm) or _is_ecdsa(rrsig.algorithm): + pass + else: + # Raise here for code clarity; this won't actually ever happen +@@ -372,3 +408,21 @@ + except ImportError: + validate = _need_pycrypto + validate_rrsig = _need_pycrypto ++ ++try: ++ import ecdsa ++ import ecdsa.ecdsa ++ import ecdsa.ellipticcurve ++ import ecdsa.keys ++ _have_ecdsa = True ++ ++ class ECKeyWrapper(object): ++ def __init__(self, key, key_len): ++ self.key = key ++ self.key_len = key_len ++ def verify(self, digest, sig): ++ diglong = Crypto.Util.number.bytes_to_long(digest) ++ return self.key.pubkey.verifies(diglong, sig) ++ ++except ImportError: ++ _have_ecdsa = False +diff -Naur dnspython-orig/dnspython-1.11.1/dns/query.py dnspython/dnspython-1.11.1/dns/query.py +--- dnspython-orig/dnspython-1.11.1/dns/query.py 2013-08-26 12:04:21.000000000 -0400 ++++ dnspython/dnspython-1.11.1/dns/query.py 2014-02-18 18:36:33.486753487 -0500 +@@ -411,6 +411,8 @@ + tcpmsg = struct.pack("!H", l) + wire + _net_write(s, tcpmsg, expiration) + done = False ++ delete_mode = True ++ expecting_SOA = False + soa_rrset = None + soa_count = 0 + if relativize: +@@ -439,18 +441,16 @@ + tsig_ctx = r.tsig_ctx + first = False + answer_index = 0 +- delete_mode = False +- expecting_SOA = False + if soa_rrset is None: + if not r.answer or r.answer[0].name != oname: +- raise dns.exception.FormError ++ raise dns.exception.FormError("No answer or RRset not for qname") + rrset = r.answer[0] + if rrset.rdtype != dns.rdatatype.SOA: + raise dns.exception.FormError("first RRset is not an SOA") + answer_index = 1 + soa_rrset = rrset.copy() + if rdtype == dns.rdatatype.IXFR: +- if soa_rrset[0].serial == serial: ++ if soa_rrset[0].serial <= serial: + # + # We're already up-to-date. + # +@@ -471,7 +471,14 @@ + expecting_SOA = False + elif rdtype == dns.rdatatype.IXFR: + delete_mode = not delete_mode +- if rrset == soa_rrset and not delete_mode: ++ # ++ # If this SOA RRset is equal to the first we saw then we're ++ # finished. If this is an IXFR we also check that we're seeing ++ # the record in the expected part of the response. ++ # ++ if rrset == soa_rrset and \ ++ (rdtype == dns.rdatatype.AXFR or \ ++ (rdtype == dns.rdatatype.IXFR and delete_mode)): + done = True + elif expecting_SOA: + # +diff -Naur dnspython-orig/dnspython-1.11.1/dns/rdtypes/ANY/LOC.py dnspython/dnspython-1.11.1/dns/rdtypes/ANY/LOC.py +--- dnspython-orig/dnspython-1.11.1/dns/rdtypes/ANY/LOC.py 2011-07-09 10:05:21.000000000 -0400 ++++ dnspython/dnspython-1.11.1/dns/rdtypes/ANY/LOC.py 2014-02-18 18:36:33.487753499 -0500 +@@ -22,6 +22,11 @@ + _pows = (1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, + 100000000L, 1000000000L, 10000000000L) + ++# default values are in centimeters ++_default_size = 100.0 ++_default_hprec = 1000000.0 ++_default_vprec = 1000.0 ++ + def _exponent_of(what, desc): + exp = None + for i in xrange(len(_pows)): +@@ -98,13 +103,14 @@ + 'horizontal_precision', 'vertical_precision'] + + def __init__(self, rdclass, rdtype, latitude, longitude, altitude, +- size=1.0, hprec=10000.0, vprec=10.0): ++ size=_default_size, hprec=_default_hprec, vprec=_default_vprec): + """Initialize a LOC record instance. + + The parameters I{latitude} and I{longitude} may be either a 4-tuple + of integers specifying (degrees, minutes, seconds, milliseconds), + or they may be floating point values specifying the number of +- degrees. The other parameters are floats.""" ++ degrees. The other parameters are floats. Size, horizontal precision, ++ and vertical precision are specified in centimeters.""" + + super(LOC, self).__init__(rdclass, rdtype) + if isinstance(latitude, int) or isinstance(latitude, long): +@@ -141,8 +147,10 @@ + self.longitude[3], long_hemisphere, self.altitude / 100.0 + ) + +- if self.size != 1.0 or self.horizontal_precision != 10000.0 or \ +- self.vertical_precision != 10.0: ++ # do not print default values ++ if self.size != _default_size or \ ++ self.horizontal_precision != _default_hprec or \ ++ self.vertical_precision != _default_vprec: + text += " %0.2fm %0.2fm %0.2fm" % ( + self.size / 100.0, self.horizontal_precision / 100.0, + self.vertical_precision / 100.0 +@@ -152,9 +160,9 @@ + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + latitude = [0, 0, 0, 0] + longitude = [0, 0, 0, 0] +- size = 1.0 +- hprec = 10000.0 +- vprec = 10.0 ++ size = _default_size ++ hprec = _default_hprec ++ vprec = _default_vprec + + latitude[0] = tok.get_int() + t = tok.get_string() +@@ -240,8 +248,8 @@ + value = token.value + if value[-1] == 'm': + value = value[0 : -1] +- vprec = float(value) * 100.0 # m -> cm +- tok.get_eol() ++ vprec = float(value) * 100.0 # m -> cm ++ tok.get_eol() + + return cls(rdclass, rdtype, latitude, longitude, altitude, + size, hprec, vprec) +diff -Naur dnspython-orig/dnspython-1.11.1/tests/dnssec.py dnspython/dnspython-1.11.1/tests/dnssec.py +--- dnspython-orig/dnspython-1.11.1/tests/dnssec.py 2013-03-31 06:33:53.000000000 -0400 ++++ dnspython/dnspython-1.11.1/tests/dnssec.py 2014-02-18 18:36:33.487753499 -0500 +@@ -97,6 +97,40 @@ + example_ds_sha256 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS, + '18673 3 2 eb8344cbbf07c9d3d3d6c81d10c76653e28d8611a65e639ef8f716e4e4e5d913') + ++when3 = 1379801800 ++ ++abs_ecdsa256_keys = { abs_example : ++ dns.rrset.from_text('example.', 86400, 'IN', 'DNSKEY', ++ "256 3 13 +3ss1sCpdARVA61DJigEsL/8quo2a8MszKtn2gkkfxgzFs8S2UHtpb4N fY+XFmNW+JK6MsCkI3jHYN8eEQUgMw==", ++ "257 3 13 eJCEVH7AS3wnoaQpaNlAXH0W8wxymtT9P6P3qjN2ZCV641ED8pF7wZ5V yWfOpgTs6oaZevbJgehl/GaRPUgVyQ==") ++ } ++ ++abs_ecdsa256_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', ++ 'ns1.example. hostmaster.example. 4 10800 3600 604800 86400') ++ ++abs_other_ecdsa256_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', ++ 'ns1.example. hostmaster.example. 2 10800 3600 604800 86401') ++ ++abs_ecdsa256_soa_rrsig = dns.rrset.from_text('example.', 86400, 'IN', 'RRSIG', ++ "SOA 13 1 86400 20130921221753 20130921221638 7460 example. Sm09SOGz1ULB5D/duwdE2Zpn8bWbVBM77H6N1wPkc42LevvVO+kZEjpq 2nq4GOMJcih52667GIAbMrwmU5P2MQ==") ++ ++when4 = 1379804850 ++ ++abs_ecdsa384_keys = { abs_example : ++ dns.rrset.from_text('example.', 86400, 'IN', 'DNSKEY', ++ "256 3 14 1bG8qWviKNXQX3BIuG6/T5jrP1FISiLW/8qGF6BsM9DQtWYhhZUA3Owr OAEiyHAhQwjkN2kTvWiAYoPN80Ii+5ff9/atzY4F9W50P4l75Dj9PYrL HN/hLUgWMNVc9pvA", ++ "257 3 14 mSub2n0KRt6u2FaD5XJ3oQu0R4XvB/9vUJcyW6+oo0y+KzfQeTdkf1ro ZMVKoyWXW9zUKBYGJpMUIdbAxzrYi7f5HyZ3yDpBFz1hw9+o3CX+gtgb +RyhHfJDwwFXBid9") ++ } ++ ++abs_ecdsa384_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', ++ 'ns1.example. hostmaster.example. 2 10800 3600 604800 86400') ++ ++abs_other_ecdsa384_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', ++ 'ns1.example. hostmaster.example. 2 10800 3600 604800 86401') ++ ++abs_ecdsa384_soa_rrsig = dns.rrset.from_text('example.', 86400, 'IN', 'RRSIG', ++ "SOA 14 1 86400 20130929021229 20130921230729 63571 example. CrnCu34EeeRz0fEhL9PLlwjpBKGYW8QjBjFQTwd+ViVLRAS8tNkcDwQE NhSV89NEjj7ze1a/JcCfcJ+/mZgnvH4NHLNg3Tf6KuLZsgs2I4kKQXEk 37oIHravPEOlGYNI") ++ + class DNSSECValidatorTestCase(unittest.TestCase): + + def testAbsoluteRSAGood(self): +@@ -143,6 +177,35 @@ + ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA256') + self.failUnless(ds == example_ds_sha256) + ++ @unittest.skipIf(not dns.dnssec._have_ecdsa, ++ "python ECDSA can not be imported") ++ def testAbsoluteECDSA256Good(self): ++ dns.dnssec.validate(abs_ecdsa256_soa, abs_ecdsa256_soa_rrsig, ++ abs_ecdsa256_keys, None, when3) ++ ++ @unittest.skipIf(not dns.dnssec._have_ecdsa, ++ "python ECDSA can not be imported") ++ def testAbsoluteECDSA256Bad(self): ++ def bad(): ++ dns.dnssec.validate(abs_other_ecdsa256_soa, abs_ecdsa256_soa_rrsig, ++ abs_ecdsa256_keys, None, when3) ++ self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) ++ ++ @unittest.skipIf(not dns.dnssec._have_ecdsa, ++ "python ECDSA can not be imported") ++ def testAbsoluteECDSA384Good(self): ++ dns.dnssec.validate(abs_ecdsa384_soa, abs_ecdsa384_soa_rrsig, ++ abs_ecdsa384_keys, None, when4) ++ ++ @unittest.skipIf(not dns.dnssec._have_ecdsa, ++ "python ECDSA can not be imported") ++ def testAbsoluteECDSA384Bad(self): ++ def bad(): ++ dns.dnssec.validate(abs_other_ecdsa384_soa, abs_ecdsa384_soa_rrsig, ++ abs_ecdsa384_keys, None, when4) ++ self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) ++ ++ + if __name__ == '__main__': + import_ok = False + try: +diff -Naur dnspython-orig/dnspython-1.11.1/tests/rdtypeanyloc.py dnspython/dnspython-1.11.1/tests/rdtypeanyloc.py +--- dnspython-orig/dnspython-1.11.1/tests/rdtypeanyloc.py 1969-12-31 19:00:00.000000000 -0500 ++++ dnspython/dnspython-1.11.1/tests/rdtypeanyloc.py 2014-02-18 18:36:33.488753510 -0500 +@@ -0,0 +1,68 @@ ++# Copyright (C) 2014 Red Hat, Inc. ++# Author: Petr Spacek ++# ++# Permission to use, copy, modify, and distribute this software and its ++# documentation for any purpose with or without fee is hereby granted, ++# provided that the above copyright notice and this permission notice ++# appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES ++# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR ++# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ++# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++import unittest ++ ++import dns.rrset ++import dns.rdtypes.ANY.LOC ++ ++class RdtypeAnyLocTestCase(unittest.TestCase): ++ ++ def testEqual1(self): ++ '''Test default values for size, horizontal and vertical precision.''' ++ r1 = dns.rrset.from_text('foo', 300, 'IN', 'LOC', ++ '49 11 42.400 N 16 36 29.600 E 227.64m') ++ r2 = dns.rrset.from_text('FOO', 600, 'in', 'loc', ++ '49 11 42.400 N 16 36 29.600 E 227.64m ' ++ '1.00m 10000.00m 10.00m') ++ self.failUnless(r1 == r2, '"%s" != "%s"' % (r1, r2)) ++ ++ def testEqual2(self): ++ '''Test default values for size, horizontal and vertical precision.''' ++ r1 = dns.rdtypes.ANY.LOC.LOC(1, 29, (49, 11, 42, 400), ++ (16, 36, 29, 600), 22764.0) # centimeters ++ r2 = dns.rdtypes.ANY.LOC.LOC(1, 29, (49, 11, 42, 400), ++ (16, 36, 29, 600), 22764.0, # centimeters ++ 100.0, 1000000.00, 1000.0) # centimeters ++ self.failUnless(r1 == r2, '"%s" != "%s"' % (r1, r2)) ++ ++ def testEqual3(self): ++ '''Test size, horizontal and vertical precision parsers: 100 cm == 1 m. ++ ++ Parsers in from_text() and __init__() have to produce equal results.''' ++ r1 = dns.rdtypes.ANY.LOC.LOC(1, 29, (49, 11, 42, 400), ++ (16, 36, 29, 600), 22764.0, ++ 200.0, 1000.00, 200.0) # centimeters ++ r2 = dns.rrset.from_text('FOO', 600, 'in', 'loc', ++ '49 11 42.400 N 16 36 29.600 E 227.64m ' ++ '2.00m 10.00m 2.00m')[0] ++ self.failUnless(r1 == r2, '"%s" != "%s"' % (r1, r2)) ++ ++ def testEqual4(self): ++ '''Test size, horizontal and vertical precision parsers without unit. ++ ++ Parsers in from_text() and __init__() have produce equal result ++ for values with and without trailing "m".''' ++ r1 = dns.rdtypes.ANY.LOC.LOC(1, 29, (49, 11, 42, 400), ++ (16, 36, 29, 600), 22764.0, ++ 200.0, 1000.00, 200.0) # centimeters ++ r2 = dns.rrset.from_text('FOO', 600, 'in', 'loc', ++ '49 11 42.400 N 16 36 29.600 E 227.64 ' ++ '2 10 2')[0] # meters without explicit unit ++ self.failUnless(r1 == r2, '"%s" != "%s"' % (r1, r2)) ++ ++if __name__ == '__main__': ++ unittest.main() +diff -Naur dnspython-orig/dnspython3-1.11.1/ChangeLog dnspython/dnspython3-1.11.1/ChangeLog +--- dnspython-orig/dnspython3-1.11.1/ChangeLog 2013-09-02 14:59:21.000000000 -0400 ++++ dnspython/dnspython3-1.11.1/ChangeLog 2014-02-18 18:36:33.489753522 -0500 +@@ -1,3 +1,9 @@ ++2013-12-11 Bob Halley ++ ++ * dns/query.py: Fix problems with the IXFR state machine which caused ++ long diffs to fail. Thanks to James Raftery for the fix and the ++ repeated prodding to get it applied :) ++ + 2013-09-02 Bob Halley + + * (Version 1.11.1 released) +diff -Naur dnspython-orig/dnspython3-1.11.1/dns/dnssec.py dnspython/dnspython3-1.11.1/dns/dnssec.py +--- dnspython-orig/dnspython3-1.11.1/dns/dnssec.py 2013-08-09 13:04:11.000000000 -0400 ++++ dnspython/dnspython3-1.11.1/dns/dnssec.py 2014-02-18 18:37:09.537175404 -0500 +@@ -45,6 +45,8 @@ + RSASHA1NSEC3SHA1 = 7 + RSASHA256 = 8 + RSASHA512 = 10 ++ECDSAP256SHA256 = 13 ++ECDSAP384SHA384 = 14 + INDIRECT = 252 + PRIVATEDNS = 253 + PRIVATEOID = 254 +@@ -60,6 +62,8 @@ + 'RSASHA256' : RSASHA256, + 'RSASHA512' : RSASHA512, + 'INDIRECT' : INDIRECT, ++ 'ECDSAP256SHA256' : ECDSAP256SHA256, ++ 'ECDSAP384SHA384' : ECDSAP384SHA384, + 'PRIVATEDNS' : PRIVATEDNS, + 'PRIVATEOID' : PRIVATEOID, + } +@@ -153,6 +157,9 @@ + def _is_dsa(algorithm): + return algorithm in (DSA, DSANSEC3SHA1) + ++def _is_ecdsa(algorithm): ++ return _have_ecdsa and (algorithm in (ECDSAP256SHA256, ECDSAP384SHA384)) ++ + def _is_md5(algorithm): + return algorithm == RSAMD5 + +@@ -161,7 +168,10 @@ + DSANSEC3SHA1, RSASHA1NSEC3SHA1) + + def _is_sha256(algorithm): +- return algorithm == RSASHA256 ++ return algorithm in (RSASHA256, ECDSAP256SHA256) ++ ++def _is_sha384(algorithm): ++ return algorithm == ECDSAP384SHA384 + + def _is_sha512(algorithm): + return algorithm == RSASHA512 +@@ -173,6 +183,8 @@ + return dns.hash.get('SHA1')() + if _is_sha256(algorithm): + return dns.hash.get('SHA256')() ++ if _is_sha384(algorithm): ++ return dns.hash.get('SHA384')() + if _is_sha512(algorithm): + return dns.hash.get('SHA512')() + raise ValidationFailure('unknown hash for algorithm %u' % algorithm) +@@ -274,6 +286,30 @@ + (dsa_r, dsa_s) = struct.unpack('!20s20s', rrsig.signature[1:]) + sig = (Crypto.Util.number.bytes_to_long(dsa_r), + Crypto.Util.number.bytes_to_long(dsa_s)) ++ elif _is_ecdsa(rrsig.algorithm): ++ if rrsig.algorithm == ECDSAP256SHA256: ++ curve = ecdsa.curves.NIST256p ++ key_len = 32 ++ digest_len = 32 ++ elif rrsig.algorithm == ECDSAP384SHA384: ++ curve = ecdsa.curves.NIST384p ++ key_len = 48 ++ digest_len = 48 ++ else: ++ # shouldn't happen ++ raise ValidationFailure('unknown ECDSA curve') ++ keyptr = candidate_key.key ++ x = Crypto.Util.number.bytes_to_long(keyptr[0:key_len]) ++ y = Crypto.Util.number.bytes_to_long(keyptr[key_len:key_len * 2]) ++ assert ecdsa.ecdsa.point_is_valid(curve.generator, x, y) ++ point = ecdsa.ellipticcurve.Point(curve.curve, x, y, curve.order) ++ verifying_key = ecdsa.keys.VerifyingKey.from_public_point(point, ++ curve) ++ pubkey = ECKeyWrapper(verifying_key, key_len) ++ r = rrsig.signature[:key_len] ++ s = rrsig.signature[key_len:] ++ sig = ecdsa.ecdsa.Signature(Crypto.Util.number.bytes_to_long(r), ++ Crypto.Util.number.bytes_to_long(s)) + else: + raise ValidationFailure('unknown algorithm %u' % rrsig.algorithm) + +@@ -303,7 +339,7 @@ + padlen = keylen // 8 - len(digest) - 3 + digest = bytes([0]) + bytes([1]) + bytes([0xFF]) * padlen + \ + bytes([0]) + digest +- elif _is_dsa(rrsig.algorithm): ++ elif _is_dsa(rrsig.algorithm) or _is_ecdsa(rrsig.algorithm): + pass + else: + # Raise here for code clarity; this won't actually ever happen +@@ -373,3 +409,21 @@ + except ImportError: + validate = _need_pycrypto + validate_rrsig = _need_pycrypto ++ ++try: ++ import ecdsa ++ import ecdsa.ecdsa ++ import ecdsa.ellipticcurve ++ import ecdsa.keys ++ _have_ecdsa = True ++ ++ class ECKeyWrapper(object): ++ def __init__(self, key, key_len): ++ self.key = key ++ self.key_len = key_len ++ def verify(self, digest, sig): ++ diglong = Crypto.Util.number.bytes_to_long(digest) ++ return self.key.pubkey.verifies(diglong, sig) ++ ++except ImportError: ++ _have_ecdsa = False +diff -Naur dnspython-orig/dnspython3-1.11.1/dns/dnssec.py.orig dnspython/dnspython3-1.11.1/dns/dnssec.py.orig +--- dnspython-orig/dnspython3-1.11.1/dns/dnssec.py.orig 1969-12-31 19:00:00.000000000 -0500 ++++ dnspython/dnspython3-1.11.1/dns/dnssec.py.orig 2014-02-18 18:36:33.490753534 -0500 +@@ -0,0 +1,375 @@ ++# Copyright (C) 2003-2007, 2009, 2011 Nominum, Inc. ++# ++# Permission to use, copy, modify, and distribute this software and its ++# documentation for any purpose with or without fee is hereby granted, ++# provided that the above copyright notice and this permission notice ++# appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES ++# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR ++# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ++# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++"""Common DNSSEC-related functions and constants.""" ++ ++import io ++import struct ++import time ++ ++import dns.exception ++import dns.hash ++import dns.name ++import dns.node ++import dns.rdataset ++import dns.rdata ++import dns.rdatatype ++import dns.rdataclass ++ ++class UnsupportedAlgorithm(dns.exception.DNSException): ++ """Raised if an algorithm is not supported.""" ++ pass ++ ++class ValidationFailure(dns.exception.DNSException): ++ """The DNSSEC signature is invalid.""" ++ pass ++ ++RSAMD5 = 1 ++DH = 2 ++DSA = 3 ++ECC = 4 ++RSASHA1 = 5 ++DSANSEC3SHA1 = 6 ++RSASHA1NSEC3SHA1 = 7 ++RSASHA256 = 8 ++RSASHA512 = 10 ++INDIRECT = 252 ++PRIVATEDNS = 253 ++PRIVATEOID = 254 ++ ++_algorithm_by_text = { ++ 'RSAMD5' : RSAMD5, ++ 'DH' : DH, ++ 'DSA' : DSA, ++ 'ECC' : ECC, ++ 'RSASHA1' : RSASHA1, ++ 'DSANSEC3SHA1' : DSANSEC3SHA1, ++ 'RSASHA1NSEC3SHA1' : RSASHA1NSEC3SHA1, ++ 'RSASHA256' : RSASHA256, ++ 'RSASHA512' : RSASHA512, ++ 'INDIRECT' : INDIRECT, ++ 'PRIVATEDNS' : PRIVATEDNS, ++ 'PRIVATEOID' : PRIVATEOID, ++ } ++ ++# We construct the inverse mapping programmatically to ensure that we ++# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that ++# would cause the mapping not to be true inverse. ++ ++_algorithm_by_value = dict([(y, x) for x, y in _algorithm_by_text.items()]) ++ ++def algorithm_from_text(text): ++ """Convert text into a DNSSEC algorithm value ++ @rtype: int""" ++ ++ value = _algorithm_by_text.get(text.upper()) ++ if value is None: ++ value = int(text) ++ return value ++ ++def algorithm_to_text(value): ++ """Convert a DNSSEC algorithm value to text ++ @rtype: string""" ++ ++ text = _algorithm_by_value.get(value) ++ if text is None: ++ text = str(value) ++ return text ++ ++def _to_rdata(record, origin): ++ s = io.BytesIO() ++ record.to_wire(s, origin=origin) ++ return s.getvalue() ++ ++def key_id(key, origin=None): ++ rdata = _to_rdata(key, origin) ++ if key.algorithm == RSAMD5: ++ return (rdata[-3] << 8) + rdata[-2] ++ else: ++ total = 0 ++ for i in range(len(rdata) // 2): ++ total += (rdata[2 * i] << 8) + rdata[2 * i + 1] ++ if len(rdata) % 2 != 0: ++ total += rdata[len(rdata) - 1] << 8 ++ total += ((total >> 16) & 0xffff); ++ return total & 0xffff ++ ++def make_ds(name, key, algorithm, origin=None): ++ if algorithm.upper() == 'SHA1': ++ dsalg = 1 ++ hash = dns.hash.get('SHA1')() ++ elif algorithm.upper() == 'SHA256': ++ dsalg = 2 ++ hash = dns.hash.get('SHA256')() ++ else: ++ raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm) ++ ++ if isinstance(name, str): ++ name = dns.name.from_text(name, origin) ++ hash.update(name.canonicalize().to_wire()) ++ hash.update(_to_rdata(key, origin)) ++ digest = hash.digest() ++ ++ dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, dsalg) + digest ++ return dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, ++ len(dsrdata)) ++ ++def _find_candidate_keys(keys, rrsig): ++ candidate_keys=[] ++ value = keys.get(rrsig.signer) ++ if value is None: ++ return None ++ if isinstance(value, dns.node.Node): ++ try: ++ rdataset = value.find_rdataset(dns.rdataclass.IN, ++ dns.rdatatype.DNSKEY) ++ except KeyError: ++ return None ++ else: ++ rdataset = value ++ for rdata in rdataset: ++ if rdata.algorithm == rrsig.algorithm and \ ++ key_id(rdata) == rrsig.key_tag: ++ candidate_keys.append(rdata) ++ return candidate_keys ++ ++def _is_rsa(algorithm): ++ return algorithm in (RSAMD5, RSASHA1, ++ RSASHA1NSEC3SHA1, RSASHA256, ++ RSASHA512) ++ ++def _is_dsa(algorithm): ++ return algorithm in (DSA, DSANSEC3SHA1) ++ ++def _is_md5(algorithm): ++ return algorithm == RSAMD5 ++ ++def _is_sha1(algorithm): ++ return algorithm in (DSA, RSASHA1, ++ DSANSEC3SHA1, RSASHA1NSEC3SHA1) ++ ++def _is_sha256(algorithm): ++ return algorithm == RSASHA256 ++ ++def _is_sha512(algorithm): ++ return algorithm == RSASHA512 ++ ++def _make_hash(algorithm): ++ if _is_md5(algorithm): ++ return dns.hash.get('MD5')() ++ if _is_sha1(algorithm): ++ return dns.hash.get('SHA1')() ++ if _is_sha256(algorithm): ++ return dns.hash.get('SHA256')() ++ if _is_sha512(algorithm): ++ return dns.hash.get('SHA512')() ++ raise ValidationFailure('unknown hash for algorithm %u' % algorithm) ++ ++def _make_algorithm_id(algorithm): ++ if _is_md5(algorithm): ++ oid = [0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05] ++ elif _is_sha1(algorithm): ++ oid = [0x2b, 0x0e, 0x03, 0x02, 0x1a] ++ elif _is_sha256(algorithm): ++ oid = [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01] ++ elif _is_sha512(algorithm): ++ oid = [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03] ++ else: ++ raise ValidationFailure('unknown algorithm %u' % algorithm) ++ olen = len(oid) ++ dlen = _make_hash(algorithm).digest_size ++ idbytes = [0x30] + [8 + olen + dlen] + \ ++ [0x30, olen + 4] + [0x06, olen] + oid + \ ++ [0x05, 0x00] + [0x04, dlen] ++ return bytes(idbytes) ++ ++def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None): ++ """Validate an RRset against a single signature rdata ++ ++ The owner name of the rrsig is assumed to be the same as the owner name ++ of the rrset. ++ ++ @param rrset: The RRset to validate ++ @type rrset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) ++ tuple ++ @param rrsig: The signature rdata ++ @type rrsig: dns.rrset.Rdata ++ @param keys: The key dictionary. ++ @type keys: a dictionary keyed by dns.name.Name with node or rdataset values ++ @param origin: The origin to use for relative names ++ @type origin: dns.name.Name or None ++ @param now: The time to use when validating the signatures. The default ++ is the current time. ++ @type now: int ++ """ ++ ++ if isinstance(origin, str): ++ origin = dns.name.from_text(origin, dns.name.root) ++ ++ for candidate_key in _find_candidate_keys(keys, rrsig): ++ if not candidate_key: ++ raise ValidationFailure('unknown key') ++ ++ # For convenience, allow the rrset to be specified as a (name, rdataset) ++ # tuple as well as a proper rrset ++ if isinstance(rrset, tuple): ++ rrname = rrset[0] ++ rdataset = rrset[1] ++ else: ++ rrname = rrset.name ++ rdataset = rrset ++ ++ if now is None: ++ now = time.time() ++ if rrsig.expiration < now: ++ raise ValidationFailure('expired') ++ if rrsig.inception > now: ++ raise ValidationFailure('not yet valid') ++ ++ hash = _make_hash(rrsig.algorithm) ++ ++ if _is_rsa(rrsig.algorithm): ++ keyptr = candidate_key.key ++ (count,) = struct.unpack('!B', keyptr[0:1]) ++ keyptr = keyptr[1:] ++ if count == 0: ++ (count,) = struct.unpack('!H', keyptr[0:2]) ++ keyptr = keyptr[2:] ++ rsa_e = keyptr[0:count] ++ rsa_n = keyptr[count:] ++ keylen = len(rsa_n) * 8 ++ pubkey = Crypto.PublicKey.RSA.construct( ++ (Crypto.Util.number.bytes_to_long(rsa_n), ++ Crypto.Util.number.bytes_to_long(rsa_e))) ++ sig = (Crypto.Util.number.bytes_to_long(rrsig.signature),) ++ elif _is_dsa(rrsig.algorithm): ++ keyptr = candidate_key.key ++ (t,) = struct.unpack('!B', keyptr[0:1]) ++ keyptr = keyptr[1:] ++ octets = 64 + t * 8 ++ dsa_q = keyptr[0:20] ++ keyptr = keyptr[20:] ++ dsa_p = keyptr[0:octets] ++ keyptr = keyptr[octets:] ++ dsa_g = keyptr[0:octets] ++ keyptr = keyptr[octets:] ++ dsa_y = keyptr[0:octets] ++ pubkey = Crypto.PublicKey.DSA.construct( ++ (Crypto.Util.number.bytes_to_long(dsa_y), ++ Crypto.Util.number.bytes_to_long(dsa_g), ++ Crypto.Util.number.bytes_to_long(dsa_p), ++ Crypto.Util.number.bytes_to_long(dsa_q))) ++ (dsa_r, dsa_s) = struct.unpack('!20s20s', rrsig.signature[1:]) ++ sig = (Crypto.Util.number.bytes_to_long(dsa_r), ++ Crypto.Util.number.bytes_to_long(dsa_s)) ++ else: ++ raise ValidationFailure('unknown algorithm %u' % rrsig.algorithm) ++ ++ hash.update(_to_rdata(rrsig, origin)[:18]) ++ hash.update(rrsig.signer.to_digestable(origin)) ++ ++ if rrsig.labels < len(rrname) - 1: ++ suffix = rrname.split(rrsig.labels + 1)[1] ++ rrname = dns.name.from_text('*', suffix) ++ rrnamebuf = rrname.to_digestable(origin) ++ rrfixed = struct.pack('!HHI', rdataset.rdtype, rdataset.rdclass, ++ rrsig.original_ttl) ++ rrlist = sorted(rdataset); ++ for rr in rrlist: ++ hash.update(rrnamebuf) ++ hash.update(rrfixed) ++ rrdata = rr.to_digestable(origin) ++ rrlen = struct.pack('!H', len(rrdata)) ++ hash.update(rrlen) ++ hash.update(rrdata) ++ ++ digest = hash.digest() ++ ++ if _is_rsa(rrsig.algorithm): ++ # PKCS1 algorithm identifier goop ++ digest = _make_algorithm_id(rrsig.algorithm) + digest ++ padlen = keylen // 8 - len(digest) - 3 ++ digest = bytes([0]) + bytes([1]) + bytes([0xFF]) * padlen + \ ++ bytes([0]) + digest ++ elif _is_dsa(rrsig.algorithm): ++ pass ++ else: ++ # Raise here for code clarity; this won't actually ever happen ++ # since if the algorithm is really unknown we'd already have ++ # raised an exception above ++ raise ValidationFailure('unknown algorithm %u' % rrsig.algorithm) ++ ++ if pubkey.verify(digest, sig): ++ return ++ raise ValidationFailure('verify failure') ++ ++def _validate(rrset, rrsigset, keys, origin=None, now=None): ++ """Validate an RRset ++ ++ @param rrset: The RRset to validate ++ @type rrset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) ++ tuple ++ @param rrsigset: The signature RRset ++ @type rrsigset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) ++ tuple ++ @param keys: The key dictionary. ++ @type keys: a dictionary keyed by dns.name.Name with node or rdataset values ++ @param origin: The origin to use for relative names ++ @type origin: dns.name.Name or None ++ @param now: The time to use when validating the signatures. The default ++ is the current time. ++ @type now: int ++ """ ++ ++ if isinstance(origin, str): ++ origin = dns.name.from_text(origin, dns.name.root) ++ ++ if isinstance(rrset, tuple): ++ rrname = rrset[0] ++ else: ++ rrname = rrset.name ++ ++ if isinstance(rrsigset, tuple): ++ rrsigname = rrsigset[0] ++ rrsigrdataset = rrsigset[1] ++ else: ++ rrsigname = rrsigset.name ++ rrsigrdataset = rrsigset ++ ++ rrname = rrname.choose_relativity(origin) ++ rrsigname = rrname.choose_relativity(origin) ++ if rrname != rrsigname: ++ raise ValidationFailure("owner names do not match") ++ ++ for rrsig in rrsigrdataset: ++ try: ++ _validate_rrsig(rrset, rrsig, keys, origin, now) ++ return ++ except ValidationFailure: ++ pass ++ raise ValidationFailure("no RRSIGs validated") ++ ++def _need_pycrypto(*args, **kwargs): ++ raise NotImplementedError("DNSSEC validation requires pycrypto") ++ ++try: ++ import Crypto.PublicKey.RSA ++ import Crypto.PublicKey.DSA ++ import Crypto.Util.number ++ validate = _validate ++ validate_rrsig = _validate_rrsig ++except ImportError: ++ validate = _need_pycrypto ++ validate_rrsig = _need_pycrypto +diff -Naur dnspython-orig/dnspython3-1.11.1/dns/query.py dnspython/dnspython3-1.11.1/dns/query.py +--- dnspython-orig/dnspython3-1.11.1/dns/query.py 2012-05-31 04:19:04.000000000 -0400 ++++ dnspython/dnspython3-1.11.1/dns/query.py 2014-02-18 18:36:33.491753545 -0500 +@@ -411,6 +411,8 @@ + tcpmsg = struct.pack("!H", l) + wire + _net_write(s, tcpmsg, expiration) + done = False ++ delete_mode = True ++ expecting_SOA = False + soa_rrset = None + soa_count = 0 + if relativize: +@@ -439,18 +441,16 @@ + tsig_ctx = r.tsig_ctx + first = False + answer_index = 0 +- delete_mode = False +- expecting_SOA = False + if soa_rrset is None: + if not r.answer or r.answer[0].name != oname: +- raise dns.exception.FormError ++ raise dns.exception.FormError("No answer or RRset not for qname") + rrset = r.answer[0] + if rrset.rdtype != dns.rdatatype.SOA: + raise dns.exception.FormError("first RRset is not an SOA") + answer_index = 1 + soa_rrset = rrset.copy() + if rdtype == dns.rdatatype.IXFR: +- if soa_rrset[0].serial == serial: ++ if soa_rrset[0].serial <= serial: + # + # We're already up-to-date. + # +@@ -471,7 +471,14 @@ + expecting_SOA = False + elif rdtype == dns.rdatatype.IXFR: + delete_mode = not delete_mode +- if rrset == soa_rrset and not delete_mode: ++ # ++ # If this SOA RRset is equal to the first we saw then we're ++ # finished. If this is an IXFR we also check that we're seeing ++ # the record in the expected part of the response. ++ # ++ if rrset == soa_rrset and \ ++ (rdtype == dns.rdatatype.AXFR or \ ++ (rdtype == dns.rdatatype.IXFR and delete_mode)): + done = True + elif expecting_SOA: + # +diff -Naur dnspython-orig/dnspython3-1.11.1/dns/rdtypes/ANY/LOC.py dnspython/dnspython3-1.11.1/dns/rdtypes/ANY/LOC.py +--- dnspython-orig/dnspython3-1.11.1/dns/rdtypes/ANY/LOC.py 2011-07-09 10:08:27.000000000 -0400 ++++ dnspython/dnspython3-1.11.1/dns/rdtypes/ANY/LOC.py 2014-02-18 18:36:33.491753545 -0500 +@@ -23,6 +23,11 @@ + _pows = (1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, + 100000000, 1000000000, 10000000000) + ++# default values are in centimeters ++_default_size = 100.0 ++_default_hprec = 1000000.0 ++_default_vprec = 1000.0 ++ + def _exponent_of(what, desc): + exp = None + for i in range(len(_pows)): +@@ -98,13 +103,14 @@ + 'horizontal_precision', 'vertical_precision'] + + def __init__(self, rdclass, rdtype, latitude, longitude, altitude, +- size=1.0, hprec=10000.0, vprec=10.0): ++ size=_default_size, hprec=_default_hprec, vprec=_default_vprec): + """Initialize a LOC record instance. + + The parameters I{latitude} and I{longitude} may be either a 4-tuple + of integers specifying (degrees, minutes, seconds, milliseconds), + or they may be floating point values specifying the number of +- degrees. The other parameters are floats.""" ++ degrees. The other parameters are floats. Size, horizontal precision, ++ and vertical precision are specified in centimeters.""" + + super(LOC, self).__init__(rdclass, rdtype) + if isinstance(latitude, int): +@@ -141,8 +147,10 @@ + self.longitude[3], long_hemisphere, self.altitude / 100.0 + ) + +- if self.size != 1.0 or self.horizontal_precision != 10000.0 or \ +- self.vertical_precision != 10.0: ++ # do not print default values ++ if self.size != _default_size or \ ++ self.horizontal_precision != _default_hprec or \ ++ self.vertical_precision != _default_vprec: + text += " %0.2fm %0.2fm %0.2fm" % ( + self.size / 100.0, self.horizontal_precision / 100.0, + self.vertical_precision / 100.0 +@@ -152,9 +160,9 @@ + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + latitude = [0, 0, 0, 0] + longitude = [0, 0, 0, 0] +- size = 1.0 +- hprec = 10000.0 +- vprec = 10.0 ++ size = _default_size ++ hprec = _default_hprec ++ vprec = _default_vprec + + latitude[0] = tok.get_int() + t = tok.get_string() +@@ -240,8 +248,8 @@ + value = token.value + if value[-1] == 'm': + value = value[0 : -1] +- vprec = float(value) * 100.0 # m -> cm +- tok.get_eol() ++ vprec = float(value) * 100.0 # m -> cm ++ tok.get_eol() + + return cls(rdclass, rdtype, latitude, longitude, altitude, + size, hprec, vprec) +diff -Naur dnspython-orig/dnspython3-1.11.1/dns/rdtypes/ANY/LOC.py.orig dnspython/dnspython3-1.11.1/dns/rdtypes/ANY/LOC.py.orig +--- dnspython-orig/dnspython3-1.11.1/dns/rdtypes/ANY/LOC.py.orig 1969-12-31 19:00:00.000000000 -0500 ++++ dnspython/dnspython3-1.11.1/dns/rdtypes/ANY/LOC.py.orig 2014-02-18 18:36:33.491753545 -0500 +@@ -0,0 +1,334 @@ ++# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. ++# ++# Permission to use, copy, modify, and distribute this software and its ++# documentation for any purpose with or without fee is hereby granted, ++# provided that the above copyright notice and this permission notice ++# appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES ++# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR ++# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ++# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++import io ++import struct ++ ++import dns.exception ++import dns.rdata ++import dns.util ++ ++_pows = (1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, ++ 100000000, 1000000000, 10000000000) ++ ++def _exponent_of(what, desc): ++ exp = None ++ for i in range(len(_pows)): ++ if what // _pows[i] == 0: ++ exp = i - 1 ++ break ++ if exp is None or exp < 0: ++ raise dns.exception.SyntaxError("%s value out of bounds" % desc) ++ return exp ++ ++def _float_to_tuple(what): ++ if what < 0: ++ sign = -1 ++ what *= -1 ++ else: ++ sign = 1 ++ what = int(round(what * 3600000)) ++ degrees = what // 3600000 ++ what -= degrees * 3600000 ++ minutes = what // 60000 ++ what -= minutes * 60000 ++ seconds = what // 1000 ++ what -= seconds * 1000 ++ return (degrees * sign, minutes, seconds, what) ++ ++def _tuple_to_float(what): ++ if what[0] < 0: ++ sign = -1 ++ value = float(what[0]) * -1 ++ else: ++ sign = 1 ++ value = float(what[0]) ++ value += float(what[1]) / 60.0 ++ value += float(what[2]) / 3600.0 ++ value += float(what[3]) / 3600000.0 ++ return sign * value ++ ++def _encode_size(what, desc): ++ what = int(what); ++ exponent = _exponent_of(what, desc) & 0xF ++ base = what // pow(10, exponent) & 0xF ++ return base * 16 + exponent ++ ++def _decode_size(what, desc): ++ exponent = what & 0x0F ++ if exponent > 9: ++ raise dns.exception.SyntaxError("bad %s exponent" % desc) ++ base = (what & 0xF0) >> 4 ++ if base > 9: ++ raise dns.exception.SyntaxError("bad %s base" % desc) ++ return int(base) * pow(10, exponent) ++ ++class LOC(dns.rdata.Rdata): ++ """LOC record ++ ++ @ivar latitude: latitude ++ @type latitude: (int, int, int, int) tuple specifying the degrees, minutes, ++ seconds, and milliseconds of the coordinate. ++ @ivar longitude: longitude ++ @type longitude: (int, int, int, int) tuple specifying the degrees, ++ minutes, seconds, and milliseconds of the coordinate. ++ @ivar altitude: altitude ++ @type altitude: float ++ @ivar size: size of the sphere ++ @type size: float ++ @ivar horizontal_precision: horizontal precision ++ @type horizontal_precision: float ++ @ivar vertical_precision: vertical precision ++ @type vertical_precision: float ++ @see: RFC 1876""" ++ ++ __slots__ = ['latitude', 'longitude', 'altitude', 'size', ++ 'horizontal_precision', 'vertical_precision'] ++ ++ def __init__(self, rdclass, rdtype, latitude, longitude, altitude, ++ size=1.0, hprec=10000.0, vprec=10.0): ++ """Initialize a LOC record instance. ++ ++ The parameters I{latitude} and I{longitude} may be either a 4-tuple ++ of integers specifying (degrees, minutes, seconds, milliseconds), ++ or they may be floating point values specifying the number of ++ degrees. The other parameters are floats.""" ++ ++ super(LOC, self).__init__(rdclass, rdtype) ++ if isinstance(latitude, int): ++ latitude = float(latitude) ++ if isinstance(latitude, float): ++ latitude = _float_to_tuple(latitude) ++ self.latitude = latitude ++ if isinstance(longitude, int): ++ longitude = float(longitude) ++ if isinstance(longitude, float): ++ longitude = _float_to_tuple(longitude) ++ self.longitude = longitude ++ self.altitude = float(altitude) ++ self.size = float(size) ++ self.horizontal_precision = float(hprec) ++ self.vertical_precision = float(vprec) ++ ++ def to_text(self, origin=None, relativize=True, **kw): ++ if self.latitude[0] > 0: ++ lat_hemisphere = 'N' ++ lat_degrees = self.latitude[0] ++ else: ++ lat_hemisphere = 'S' ++ lat_degrees = -1 * self.latitude[0] ++ if self.longitude[0] > 0: ++ long_hemisphere = 'E' ++ long_degrees = self.longitude[0] ++ else: ++ long_hemisphere = 'W' ++ long_degrees = -1 * self.longitude[0] ++ text = "%d %d %d.%03d %s %d %d %d.%03d %s %0.2fm" % ( ++ lat_degrees, self.latitude[1], self.latitude[2], self.latitude[3], ++ lat_hemisphere, long_degrees, self.longitude[1], self.longitude[2], ++ self.longitude[3], long_hemisphere, self.altitude / 100.0 ++ ) ++ ++ if self.size != 1.0 or self.horizontal_precision != 10000.0 or \ ++ self.vertical_precision != 10.0: ++ text += " %0.2fm %0.2fm %0.2fm" % ( ++ self.size / 100.0, self.horizontal_precision / 100.0, ++ self.vertical_precision / 100.0 ++ ) ++ return text ++ ++ def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): ++ latitude = [0, 0, 0, 0] ++ longitude = [0, 0, 0, 0] ++ size = 1.0 ++ hprec = 10000.0 ++ vprec = 10.0 ++ ++ latitude[0] = tok.get_int() ++ t = tok.get_string() ++ if t.isdigit(): ++ latitude[1] = int(t) ++ t = tok.get_string() ++ if '.' in t: ++ (seconds, milliseconds) = t.split('.') ++ if not seconds.isdigit(): ++ raise dns.exception.SyntaxError('bad latitude seconds value') ++ latitude[2] = int(seconds) ++ if latitude[2] >= 60: ++ raise dns.exception.SyntaxError('latitude seconds >= 60') ++ l = len(milliseconds) ++ if l == 0 or l > 3 or not milliseconds.isdigit(): ++ raise dns.exception.SyntaxError('bad latitude milliseconds value') ++ if l == 1: ++ m = 100 ++ elif l == 2: ++ m = 10 ++ else: ++ m = 1 ++ latitude[3] = m * int(milliseconds) ++ t = tok.get_string() ++ elif t.isdigit(): ++ latitude[2] = int(t) ++ t = tok.get_string() ++ if t == 'S': ++ latitude[0] *= -1 ++ elif t != 'N': ++ raise dns.exception.SyntaxError('bad latitude hemisphere value') ++ ++ longitude[0] = tok.get_int() ++ t = tok.get_string() ++ if t.isdigit(): ++ longitude[1] = int(t) ++ t = tok.get_string() ++ if '.' in t: ++ (seconds, milliseconds) = t.split('.') ++ if not seconds.isdigit(): ++ raise dns.exception.SyntaxError('bad longitude seconds value') ++ longitude[2] = int(seconds) ++ if longitude[2] >= 60: ++ raise dns.exception.SyntaxError('longitude seconds >= 60') ++ l = len(milliseconds) ++ if l == 0 or l > 3 or not milliseconds.isdigit(): ++ raise dns.exception.SyntaxError('bad longitude milliseconds value') ++ if l == 1: ++ m = 100 ++ elif l == 2: ++ m = 10 ++ else: ++ m = 1 ++ longitude[3] = m * int(milliseconds) ++ t = tok.get_string() ++ elif t.isdigit(): ++ longitude[2] = int(t) ++ t = tok.get_string() ++ if t == 'W': ++ longitude[0] *= -1 ++ elif t != 'E': ++ raise dns.exception.SyntaxError('bad longitude hemisphere value') ++ ++ t = tok.get_string() ++ if t[-1] == 'm': ++ t = t[0 : -1] ++ altitude = float(t) * 100.0 # m -> cm ++ ++ token = tok.get().unescape() ++ if not token.is_eol_or_eof(): ++ value = token.value ++ if value[-1] == 'm': ++ value = value[0 : -1] ++ size = float(value) * 100.0 # m -> cm ++ token = tok.get().unescape() ++ if not token.is_eol_or_eof(): ++ value = token.value ++ if value[-1] == 'm': ++ value = value[0 : -1] ++ hprec = float(value) * 100.0 # m -> cm ++ token = tok.get().unescape() ++ if not token.is_eol_or_eof(): ++ value = token.value ++ if value[-1] == 'm': ++ value = value[0 : -1] ++ vprec = float(value) * 100.0 # m -> cm ++ tok.get_eol() ++ ++ return cls(rdclass, rdtype, latitude, longitude, altitude, ++ size, hprec, vprec) ++ ++ from_text = classmethod(from_text) ++ ++ def to_wire(self, file, compress = None, origin = None): ++ if self.latitude[0] < 0: ++ sign = -1 ++ degrees = -1 * self.latitude[0] ++ else: ++ sign = 1 ++ degrees = self.latitude[0] ++ milliseconds = (degrees * 3600000 + ++ self.latitude[1] * 60000 + ++ self.latitude[2] * 1000 + ++ self.latitude[3]) * sign ++ latitude = 0x80000000 + milliseconds ++ if self.longitude[0] < 0: ++ sign = -1 ++ degrees = -1 * self.longitude[0] ++ else: ++ sign = 1 ++ degrees = self.longitude[0] ++ milliseconds = (degrees * 3600000 + ++ self.longitude[1] * 60000 + ++ self.longitude[2] * 1000 + ++ self.longitude[3]) * sign ++ longitude = 0x80000000 + milliseconds ++ altitude = int(self.altitude) + 10000000 ++ size = _encode_size(self.size, "size") ++ hprec = _encode_size(self.horizontal_precision, "horizontal precision") ++ vprec = _encode_size(self.vertical_precision, "vertical precision") ++ wire = struct.pack("!BBBBIII", 0, size, hprec, vprec, latitude, ++ longitude, altitude) ++ file.write(wire) ++ ++ def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): ++ (version, size, hprec, vprec, latitude, longitude, altitude) = \ ++ struct.unpack("!BBBBIII", wire[current : current + rdlen]) ++ if latitude > 0x80000000: ++ latitude = float(latitude - 0x80000000) / 3600000 ++ else: ++ latitude = -1 * float(0x80000000 - latitude) / 3600000 ++ if latitude < -90.0 or latitude > 90.0: ++ raise dns.exception.FormError("bad latitude") ++ if longitude > 0x80000000: ++ longitude = float(longitude - 0x80000000) / 3600000 ++ else: ++ longitude = -1 * float(0x80000000 - longitude) / 3600000 ++ if longitude < -180.0 or longitude > 180.0: ++ raise dns.exception.FormError("bad longitude") ++ altitude = float(altitude) - 10000000.0 ++ size = _decode_size(size, "size") ++ hprec = _decode_size(hprec, "horizontal precision") ++ vprec = _decode_size(vprec, "vertical precision") ++ return cls(rdclass, rdtype, latitude, longitude, altitude, ++ size, hprec, vprec) ++ ++ from_wire = classmethod(from_wire) ++ ++ def _cmp(self, other): ++ f = io.BytesIO() ++ self.to_wire(f) ++ wire1 = f.getvalue() ++ f.seek(0) ++ f.truncate() ++ other.to_wire(f) ++ wire2 = f.getvalue() ++ f.close() ++ ++ return dns.util.cmp(wire1, wire2) ++ ++ def _get_float_latitude(self): ++ return _tuple_to_float(self.latitude) ++ ++ def _set_float_latitude(self, value): ++ self.latitude = _float_to_tuple(value) ++ ++ float_latitude = property(_get_float_latitude, _set_float_latitude, ++ doc="latitude as a floating point value") ++ ++ def _get_float_longitude(self): ++ return _tuple_to_float(self.longitude) ++ ++ def _set_float_longitude(self, value): ++ self.longitude = _float_to_tuple(value) ++ ++ float_longitude = property(_get_float_longitude, _set_float_longitude, ++ doc="longitude as a floating point value") +diff -Naur dnspython-orig/dnspython3-1.11.1/tests/dnssec.py dnspython/dnspython3-1.11.1/tests/dnssec.py +--- dnspython-orig/dnspython3-1.11.1/tests/dnssec.py 2013-03-31 06:35:33.000000000 -0400 ++++ dnspython/dnspython3-1.11.1/tests/dnssec.py 2014-02-18 18:36:33.492753557 -0500 +@@ -97,6 +97,40 @@ + example_ds_sha256 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS, + '18673 3 2 eb8344cbbf07c9d3d3d6c81d10c76653e28d8611a65e639ef8f716e4e4e5d913') + ++when3 = 1379801800 ++ ++abs_ecdsa256_keys = { abs_example : ++ dns.rrset.from_text('example.', 86400, 'IN', 'DNSKEY', ++ "256 3 13 +3ss1sCpdARVA61DJigEsL/8quo2a8MszKtn2gkkfxgzFs8S2UHtpb4N fY+XFmNW+JK6MsCkI3jHYN8eEQUgMw==", ++ "257 3 13 eJCEVH7AS3wnoaQpaNlAXH0W8wxymtT9P6P3qjN2ZCV641ED8pF7wZ5V yWfOpgTs6oaZevbJgehl/GaRPUgVyQ==") ++ } ++ ++abs_ecdsa256_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', ++ 'ns1.example. hostmaster.example. 4 10800 3600 604800 86400') ++ ++abs_other_ecdsa256_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', ++ 'ns1.example. hostmaster.example. 2 10800 3600 604800 86401') ++ ++abs_ecdsa256_soa_rrsig = dns.rrset.from_text('example.', 86400, 'IN', 'RRSIG', ++ "SOA 13 1 86400 20130921221753 20130921221638 7460 example. Sm09SOGz1ULB5D/duwdE2Zpn8bWbVBM77H6N1wPkc42LevvVO+kZEjpq 2nq4GOMJcih52667GIAbMrwmU5P2MQ==") ++ ++when4 = 1379804850 ++ ++abs_ecdsa384_keys = { abs_example : ++ dns.rrset.from_text('example.', 86400, 'IN', 'DNSKEY', ++ "256 3 14 1bG8qWviKNXQX3BIuG6/T5jrP1FISiLW/8qGF6BsM9DQtWYhhZUA3Owr OAEiyHAhQwjkN2kTvWiAYoPN80Ii+5ff9/atzY4F9W50P4l75Dj9PYrL HN/hLUgWMNVc9pvA", ++ "257 3 14 mSub2n0KRt6u2FaD5XJ3oQu0R4XvB/9vUJcyW6+oo0y+KzfQeTdkf1ro ZMVKoyWXW9zUKBYGJpMUIdbAxzrYi7f5HyZ3yDpBFz1hw9+o3CX+gtgb +RyhHfJDwwFXBid9") ++ } ++ ++abs_ecdsa384_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', ++ 'ns1.example. hostmaster.example. 2 10800 3600 604800 86400') ++ ++abs_other_ecdsa384_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', ++ 'ns1.example. hostmaster.example. 2 10800 3600 604800 86401') ++ ++abs_ecdsa384_soa_rrsig = dns.rrset.from_text('example.', 86400, 'IN', 'RRSIG', ++ "SOA 14 1 86400 20130929021229 20130921230729 63571 example. CrnCu34EeeRz0fEhL9PLlwjpBKGYW8QjBjFQTwd+ViVLRAS8tNkcDwQE NhSV89NEjj7ze1a/JcCfcJ+/mZgnvH4NHLNg3Tf6KuLZsgs2I4kKQXEk 37oIHravPEOlGYNI") ++ + class DNSSECValidatorTestCase(unittest.TestCase): + + def testAbsoluteRSAGood(self): +@@ -143,6 +177,35 @@ + ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA256') + self.assertTrue(ds == example_ds_sha256) + ++ @unittest.skipIf(not dns.dnssec._have_ecdsa, ++ "python ECDSA can not be imported") ++ def testAbsoluteECDSA256Good(self): ++ dns.dnssec.validate(abs_ecdsa256_soa, abs_ecdsa256_soa_rrsig, ++ abs_ecdsa256_keys, None, when3) ++ ++ @unittest.skipIf(not dns.dnssec._have_ecdsa, ++ "python ECDSA can not be imported") ++ def testAbsoluteECDSA256Bad(self): ++ def bad(): ++ dns.dnssec.validate(abs_other_ecdsa256_soa, abs_ecdsa256_soa_rrsig, ++ abs_ecdsa256_keys, None, when3) ++ self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) ++ ++ @unittest.skipIf(not dns.dnssec._have_ecdsa, ++ "python ECDSA can not be imported") ++ def testAbsoluteECDSA384Good(self): ++ dns.dnssec.validate(abs_ecdsa384_soa, abs_ecdsa384_soa_rrsig, ++ abs_ecdsa384_keys, None, when4) ++ ++ @unittest.skipIf(not dns.dnssec._have_ecdsa, ++ "python ECDSA can not be imported") ++ def testAbsoluteECDSA384Bad(self): ++ def bad(): ++ dns.dnssec.validate(abs_other_ecdsa384_soa, abs_ecdsa384_soa_rrsig, ++ abs_ecdsa384_keys, None, when4) ++ self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) ++ ++ + if __name__ == '__main__': + import_ok = False + try: +diff -Naur dnspython-orig/dnspython3-1.11.1/tests/dnssec.py.orig dnspython/dnspython3-1.11.1/tests/dnssec.py.orig +--- dnspython-orig/dnspython3-1.11.1/tests/dnssec.py.orig 1969-12-31 19:00:00.000000000 -0500 ++++ dnspython/dnspython3-1.11.1/tests/dnssec.py.orig 2014-02-18 18:36:33.492753557 -0500 +@@ -0,0 +1,156 @@ ++# Copyright (C) 2011 Nominum, Inc. ++# ++# Permission to use, copy, modify, and distribute this software and its ++# documentation for any purpose with or without fee is hereby granted, ++# provided that the above copyright notice and this permission notice ++# appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES ++# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR ++# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ++# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++import unittest ++ ++import dns.dnssec ++import dns.name ++import dns.rdata ++import dns.rdataclass ++import dns.rdatatype ++import dns.rrset ++ ++abs_dnspython_org = dns.name.from_text('dnspython.org') ++ ++abs_keys = { abs_dnspython_org : ++ dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'DNSKEY', ++ '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=', ++ '256 3 5 AwEAAdSSghOGjU33IQZgwZM2Hh771VGXX05olJK49FxpSyuEAjDBXY58 LGU9R2Zgeecnk/b9EAhFu/vCV9oECtiTCvwuVAkt9YEweqYDluQInmgP NGMJCKdSLlnX93DkjDw8rMYv5dqXCuSGPlKChfTJOLQxIAxGloS7lL+c 0CTZydAF') ++ } ++ ++abs_keys_duplicate_keytag = { abs_dnspython_org : ++ dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'DNSKEY', ++ '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=', ++ '256 3 5 AwEAAdSSg++++THIS/IS/NOT/THE/CORRECT/KEY++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ AaOSydAF', ++ '256 3 5 AwEAAdSSghOGjU33IQZgwZM2Hh771VGXX05olJK49FxpSyuEAjDBXY58 LGU9R2Zgeecnk/b9EAhFu/vCV9oECtiTCvwuVAkt9YEweqYDluQInmgP NGMJCKdSLlnX93DkjDw8rMYv5dqXCuSGPlKChfTJOLQxIAxGloS7lL+c 0CTZydAF') ++ } ++ ++rel_keys = { dns.name.empty : ++ dns.rrset.from_text('@', 3600, 'IN', 'DNSKEY', ++ '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=', ++ '256 3 5 AwEAAdSSghOGjU33IQZgwZM2Hh771VGXX05olJK49FxpSyuEAjDBXY58 LGU9R2Zgeecnk/b9EAhFu/vCV9oECtiTCvwuVAkt9YEweqYDluQInmgP NGMJCKdSLlnX93DkjDw8rMYv5dqXCuSGPlKChfTJOLQxIAxGloS7lL+c 0CTZydAF') ++ } ++ ++when = 1290250287 ++ ++abs_soa = dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'SOA', ++ 'howl.dnspython.org. hostmaster.dnspython.org. 2010020047 3600 1800 604800 3600') ++ ++abs_other_soa = dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'SOA', ++ 'foo.dnspython.org. hostmaster.dnspython.org. 2010020047 3600 1800 604800 3600') ++ ++abs_soa_rrsig = dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'RRSIG', ++ 'SOA 5 2 3600 20101127004331 20101119213831 61695 dnspython.org. sDUlltRlFTQw5ITFxOXW3TgmrHeMeNpdqcZ4EXxM9FHhIlte6V9YCnDw t6dvM9jAXdIEi03l9H/RAd9xNNW6gvGMHsBGzpvvqFQxIBR2PoiZA1mX /SWHZFdbt4xjYTtXqpyYvrMK0Dt7bUYPadyhPFCJ1B+I8Zi7B5WJEOd0 8vs=') ++ ++rel_soa = dns.rrset.from_text('@', 3600, 'IN', 'SOA', ++ 'howl hostmaster 2010020047 3600 1800 604800 3600') ++ ++rel_other_soa = dns.rrset.from_text('@', 3600, 'IN', 'SOA', ++ 'foo hostmaster 2010020047 3600 1800 604800 3600') ++ ++rel_soa_rrsig = dns.rrset.from_text('@', 3600, 'IN', 'RRSIG', ++ 'SOA 5 2 3600 20101127004331 20101119213831 61695 @ sDUlltRlFTQw5ITFxOXW3TgmrHeMeNpdqcZ4EXxM9FHhIlte6V9YCnDw t6dvM9jAXdIEi03l9H/RAd9xNNW6gvGMHsBGzpvvqFQxIBR2PoiZA1mX /SWHZFdbt4xjYTtXqpyYvrMK0Dt7bUYPadyhPFCJ1B+I8Zi7B5WJEOd0 8vs=') ++ ++sep_key = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DNSKEY, ++ '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=') ++ ++good_ds = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS, ++ '57349 5 2 53A79A3E7488AB44FFC56B2D1109F0699D1796DD977E72108B841F96 E47D7013') ++ ++when2 = 1290425644 ++ ++abs_example = dns.name.from_text('example') ++ ++abs_dsa_keys = { abs_example : ++ dns.rrset.from_text('example.', 86400, 'IN', 'DNSKEY', ++ '257 3 3 CI3nCqyJsiCJHTjrNsJOT4RaszetzcJPYuoH3F9ZTVt3KJXncCVR3bwn 1w0iavKljb9hDlAYSfHbFCp4ic/rvg4p1L8vh5s8ToMjqDNl40A0hUGQ Ybx5hsECyK+qHoajilUX1phYSAD8d9WAGO3fDWzUPBuzR7o85NiZCDxz yXuNVfni0uhj9n1KYhEO5yAbbruDGN89wIZcxMKuQsdUY2GYD93ssnBv a55W6XRABYWayKZ90WkRVODLVYLSn53Pj/wwxGH+XdhIAZJXimrZL4yl My7rtBsLMqq8Ihs4Tows7LqYwY7cp6y/50tw6pj8tFqMYcPUjKZV36l1 M/2t5BVg3i7IK61Aidt6aoC3TDJtzAxg3ZxfjZWJfhHjMJqzQIfbW5b9 q1mjFsW5EUv39RaNnX+3JWPRLyDqD4pIwDyqfutMsdk/Py3paHn82FGp CaOg+nicqZ9TiMZURN/XXy5JoXUNQ3RNvbHCUiPUe18KUkY6mTfnyHld 1l9YCWmzXQVClkx/hOYxjJ4j8Ife58+Obu5X', ++ '256 3 3 CJE1yb9YRQiw5d2xZrMUMR+cGCTt1bp1KDCefmYKmS+Z1+q9f42ETVhx JRiQwXclYwmxborzIkSZegTNYIV6mrYwbNB27Q44c3UGcspb3PiOw5TC jNPRYEcdwGvDZ2wWy+vkSV/S9tHXY8O6ODiE6abZJDDg/RnITyi+eoDL R3KZ5n/V1f1T1b90rrV6EewhBGQJpQGDogaXb2oHww9Tm6NfXyo7SoMM pbwbzOckXv+GxRPJIQNSF4D4A9E8XCksuzVVdE/0lr37+uoiAiPia38U 5W2QWe/FJAEPLjIp2eTzf0TrADc1pKP1wrA2ASpdzpm/aX3IB5RPp8Ew S9U72eBFZJAUwg635HxJVxH1maG6atzorR566E+e0OZSaxXS9o1o6QqN 3oPlYLGPORDiExilKfez3C/x/yioOupW9K5eKF0gmtaqrHX0oq9s67f/ RIM2xVaKHgG9Vf2cgJIZkhv7sntujr+E4htnRmy9P9BxyFxsItYxPI6Z bzygHAZpGhlI/7ltEGlIwKxyTK3ZKBm67q7B') ++ } ++ ++abs_dsa_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', ++ 'ns1.example. hostmaster.example. 2 10800 3600 604800 86400') ++ ++abs_other_dsa_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', ++ 'ns1.example. hostmaster.example. 2 10800 3600 604800 86401') ++ ++abs_dsa_soa_rrsig = dns.rrset.from_text('example.', 86400, 'IN', 'RRSIG', ++ 'SOA 3 1 86400 20101129143231 20101122112731 42088 example. CGul9SuBofsktunV8cJs4eRs6u+3NCS3yaPKvBbD+pB2C76OUXDZq9U=') ++ ++example_sep_key = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DNSKEY, ++ '257 3 3 CI3nCqyJsiCJHTjrNsJOT4RaszetzcJPYuoH3F9ZTVt3KJXncCVR3bwn 1w0iavKljb9hDlAYSfHbFCp4ic/rvg4p1L8vh5s8ToMjqDNl40A0hUGQ Ybx5hsECyK+qHoajilUX1phYSAD8d9WAGO3fDWzUPBuzR7o85NiZCDxz yXuNVfni0uhj9n1KYhEO5yAbbruDGN89wIZcxMKuQsdUY2GYD93ssnBv a55W6XRABYWayKZ90WkRVODLVYLSn53Pj/wwxGH+XdhIAZJXimrZL4yl My7rtBsLMqq8Ihs4Tows7LqYwY7cp6y/50tw6pj8tFqMYcPUjKZV36l1 M/2t5BVg3i7IK61Aidt6aoC3TDJtzAxg3ZxfjZWJfhHjMJqzQIfbW5b9 q1mjFsW5EUv39RaNnX+3JWPRLyDqD4pIwDyqfutMsdk/Py3paHn82FGp CaOg+nicqZ9TiMZURN/XXy5JoXUNQ3RNvbHCUiPUe18KUkY6mTfnyHld 1l9YCWmzXQVClkx/hOYxjJ4j8Ife58+Obu5X') ++ ++example_ds_sha1 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS, ++ '18673 3 1 71b71d4f3e11bbd71b4eff12cde69f7f9215bbe7') ++ ++example_ds_sha256 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS, ++ '18673 3 2 eb8344cbbf07c9d3d3d6c81d10c76653e28d8611a65e639ef8f716e4e4e5d913') ++ ++class DNSSECValidatorTestCase(unittest.TestCase): ++ ++ def testAbsoluteRSAGood(self): ++ dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys, None, when) ++ ++ def testDuplicateKeytag(self): ++ dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys_duplicate_keytag, None, when) ++ ++ def testAbsoluteRSABad(self): ++ def bad(): ++ dns.dnssec.validate(abs_other_soa, abs_soa_rrsig, abs_keys, None, ++ when) ++ self.assertRaises(dns.dnssec.ValidationFailure, bad) ++ ++ def testRelativeRSAGood(self): ++ dns.dnssec.validate(rel_soa, rel_soa_rrsig, rel_keys, ++ abs_dnspython_org, when) ++ ++ def testRelativeRSABad(self): ++ def bad(): ++ dns.dnssec.validate(rel_other_soa, rel_soa_rrsig, rel_keys, ++ abs_dnspython_org, when) ++ self.assertRaises(dns.dnssec.ValidationFailure, bad) ++ ++ def testMakeSHA256DS(self): ++ ds = dns.dnssec.make_ds(abs_dnspython_org, sep_key, 'SHA256') ++ self.assertTrue(ds == good_ds) ++ ++ def testAbsoluteDSAGood(self): ++ dns.dnssec.validate(abs_dsa_soa, abs_dsa_soa_rrsig, abs_dsa_keys, None, ++ when2) ++ ++ def testAbsoluteDSABad(self): ++ def bad(): ++ dns.dnssec.validate(abs_other_dsa_soa, abs_dsa_soa_rrsig, ++ abs_dsa_keys, None, when2) ++ self.assertRaises(dns.dnssec.ValidationFailure, bad) ++ ++ def testMakeExampleSHA1DS(self): ++ ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA1') ++ self.assertTrue(ds == example_ds_sha1) ++ ++ def testMakeExampleSHA256DS(self): ++ ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA256') ++ self.assertTrue(ds == example_ds_sha256) ++ ++if __name__ == '__main__': ++ import_ok = False ++ try: ++ import Crypto.Util.number ++ import_ok = True ++ except: ++ pass ++ if import_ok: ++ unittest.main() ++ else: ++ print('skipping DNSSEC tests because pycrypto is not installed') +diff -Naur dnspython-orig/dnspython3-1.11.1/tests/rdtypeanyloc.py dnspython/dnspython3-1.11.1/tests/rdtypeanyloc.py +--- dnspython-orig/dnspython3-1.11.1/tests/rdtypeanyloc.py 1969-12-31 19:00:00.000000000 -0500 ++++ dnspython/dnspython3-1.11.1/tests/rdtypeanyloc.py 2014-02-18 18:36:33.492753557 -0500 +@@ -0,0 +1,68 @@ ++# Copyright (C) 2014 Red Hat, Inc. ++# Author: Petr Spacek ++# ++# Permission to use, copy, modify, and distribute this software and its ++# documentation for any purpose with or without fee is hereby granted, ++# provided that the above copyright notice and this permission notice ++# appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES ++# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR ++# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ++# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++import unittest ++ ++import dns.rrset ++import dns.rdtypes.ANY.LOC ++ ++class RdtypeAnyLocTestCase(unittest.TestCase): ++ ++ def testEqual1(self): ++ '''Test default values for size, horizontal and vertical precision.''' ++ r1 = dns.rrset.from_text('foo', 300, 'IN', 'LOC', ++ '49 11 42.400 N 16 36 29.600 E 227.64m') ++ r2 = dns.rrset.from_text('FOO', 600, 'in', 'loc', ++ '49 11 42.400 N 16 36 29.600 E 227.64m ' ++ '1.00m 10000.00m 10.00m') ++ self.failUnless(r1 == r2, '"%s" != "%s"' % (r1, r2)) ++ ++ def testEqual2(self): ++ '''Test default values for size, horizontal and vertical precision.''' ++ r1 = dns.rdtypes.ANY.LOC.LOC(1, 29, (49, 11, 42, 400), ++ (16, 36, 29, 600), 22764.0) # centimeters ++ r2 = dns.rdtypes.ANY.LOC.LOC(1, 29, (49, 11, 42, 400), ++ (16, 36, 29, 600), 22764.0, # centimeters ++ 100.0, 1000000.00, 1000.0) # centimeters ++ self.failUnless(r1 == r2, '"%s" != "%s"' % (r1, r2)) ++ ++ def testEqual3(self): ++ '''Test size, horizontal and vertical precision parsers: 100 cm == 1 m. ++ ++ Parsers in from_text() and __init__() have to produce equal results.''' ++ r1 = dns.rdtypes.ANY.LOC.LOC(1, 29, (49, 11, 42, 400), ++ (16, 36, 29, 600), 22764.0, ++ 200.0, 1000.00, 200.0) # centimeters ++ r2 = dns.rrset.from_text('FOO', 600, 'in', 'loc', ++ '49 11 42.400 N 16 36 29.600 E 227.64m ' ++ '2.00m 10.00m 2.00m')[0] ++ self.failUnless(r1 == r2, '"%s" != "%s"' % (r1, r2)) ++ ++ def testEqual4(self): ++ '''Test size, horizontal and vertical precision parsers without unit. ++ ++ Parsers in from_text() and __init__() have produce equal result ++ for values with and without trailing "m".''' ++ r1 = dns.rdtypes.ANY.LOC.LOC(1, 29, (49, 11, 42, 400), ++ (16, 36, 29, 600), 22764.0, ++ 200.0, 1000.00, 200.0) # centimeters ++ r2 = dns.rrset.from_text('FOO', 600, 'in', 'loc', ++ '49 11 42.400 N 16 36 29.600 E 227.64 ' ++ '2 10 2')[0] # meters without explicit unit ++ self.failUnless(r1 == r2, '"%s" != "%s"' % (r1, r2)) ++ ++if __name__ == '__main__': ++ unittest.main() diff --git a/python-dns.spec b/python-dns.spec index c336138..d55c63f 100644 --- a/python-dns.spec +++ b/python-dns.spec @@ -22,7 +22,7 @@ Name: python-dns Version: 1.11.1 -Release: 1%{?dist} +Release: 2%{?dist} Summary: DNS toolkit for Python Group: Development/Languages @@ -37,6 +37,8 @@ Source3: http://www.dnspython.org/kits3/%{version}/dnspython3-%{version}. %if 0%{?rhel} == 5 Patch0: 0001-Don-t-fail-on-older-python-versions-because-of-hashe.patch %endif +Patch1: dnspython-1.11.1-ecdsa-loc.patch + BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) BuildArch: noarch @@ -136,6 +138,7 @@ pushd %{py2dir} %patch0 -p1 popd %endif +%patch1 -p1 %build pushd %{py2dir} @@ -254,6 +257,9 @@ rm -rf %{buildroot} %endif %changelog +* Tue Feb 18 2014 Paul Wouters - 1.11.1-2 +- Added LOC and ECDSA fixes from git (rhbz#1059594) + * Thu Sep 5 2013 Jeffrey C. Ollie - 1.11.1-1 - New since 1.11.0: -