diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a2a190e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/dnspython-1.16.0.tar.gz diff --git a/python2-dns.spec b/python2-dns.spec new file mode 100644 index 0000000..c7d5151 --- /dev/null +++ b/python2-dns.spec @@ -0,0 +1,489 @@ +%global pypi_name dnspython +%global py_package_name dns + +# python2-dns exists because mailman and trac-spamfilter-plugin +# need it and both have fesco exception to stay in fedora for a while +# https://pagure.io/fesco/issue/2312 +# https://pagure.io/fesco/issue/2266 + +# Disable dependency generator until it has test code +%{?python_disable_dependency_generator} + +Name: python2-%{py_package_name} +Version: 1.16.0 +Release: 13%{?dist} +Summary: DNS toolkit for Python + +License: ISC and MIT +URL: http://www.dnspython.org + +Source0: http://www.dnspython.org/kits/%{version}/%{pypi_name}-%{version}.tar.gz + +# A no-op typing module for import compatibility +# This avoids the build dependency on python2-typing +Source1: typing.py + +BuildArch: noarch + +Patch0: unicode_label_escapify.patch +Patch1: switch_to_python_cryptography.patch + +BuildRequires: python2-devel +BuildRequires: python2-setuptools + +%description +dnspython is a DNS toolkit for Python. It supports almost all record +types. It can be used for queries, zone transfers, and dynamic +updates. It supports TSIG authenticated messages and EDNS0. + +dnspython provides both high and low level access to DNS. The high +level classes perform queries for data of a given name, type, and +class, and return an answer set. The low level classes allow direct +manipulation of DNS zones, messages, names, and records. + +python2-dns has no support for DNSSEC. + +%prep +%autosetup -p1 -n %{pypi_name}-%{version} + +# strip exec permissions so that we don't pick up dependencies from docs +find examples -type f | xargs chmod a-x + +%build +%py2_build + +%install +%py2_install + +%check +cp %{SOURCE1} . +%{python2} setup.py test +rm typing.py{,?} + +%files +%license LICENSE +%doc README.md examples +%{python2_sitelib}/%{py_package_name}/ +%{python2_sitelib}/%{pypi_name}-*.egg-info/ + +%changelog +* Thu Jul 23 2020 Lumír Balhar - 1.16.0-13 +- Package forked to python2-dns + +* Sun May 24 2020 Miro Hrončok - 1.16.0-12 +- Rebuilt for Python 3.9 + +* Tue Apr 28 2020 Lumír Balhar - 1.16.0-11 +- Switch crypto backend to python-cryptography +Related to: rhbz#1819086 + +* Fri Apr 17 2020 Lumír Balhar - 1.16.0-10 +- Bring python2 subpackage back +- Fix weak dependencies + +* Wed Apr 15 2020 Paul Wouters - 1.16.0-9 +- Remove python2 and "other_python3" support +- Resolves: rhbz#1802998 Make pycryptodomex and ecdsa weak dependencies of python-dns +- Resolves: rhbz#1801247 python-certbot-dns-rfc2136 fails to build with Python 3.9: base64.decodestring() was removed + +* Mon Feb 03 2020 Miro Hrončok - 1.16.0-8 +- Drop build dependency on python2-typing + +* Thu Jan 30 2020 Fedora Release Engineering - 1.16.0-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Tue Jan 21 2020 Avram Lubkin - 1.16.0-6 +- Enable unicode patch (rhbz#1731100) +- Fix collections.abc import for Python 3.9 (rhbz#1792919) + +* Tue Nov 05 2019 Paul Howarth - 1.16.0-5 +- Use pycryptodomex instead of pycrypto +- Also use python-ecdsa (except with Python 2) + +* Thu Oct 03 2019 Miro Hrončok - 1.16.0-4 +- Rebuilt for Python 3.8.0rc1 (#1748018) + +* Tue Aug 20 2019 Miro Hrončok - 1.16.0-3 +- Reintroduce dropped python2-dns, it is still needed + +* Mon Aug 19 2019 Miro Hrončok - 1.16.0-2 +- Rebuilt for Python 3.8 + +* Sat Jul 27 2019 Avram Lubkin - 1.16.0-1 +- Latest Release +- Cleanup spec +- Patch to fix unicode escapes +- Drop el6 from master (el6 requires patch for 1.16.0) + +* Fri Jul 26 2019 Fedora Release Engineering - 1.15.0-11 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Sat Feb 02 2019 Fedora Release Engineering - 1.15.0-10 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Sat Jul 14 2018 Fedora Release Engineering - 1.15.0-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Thu Jul 12 2018 Paul Wouters - 1.15.0-8 +- Resolves: rhbz#1600418 - NVR of python-dns is lower in rawhide than in f28 + +* Tue Jun 19 2018 Miro Hrončok - 1.15.0-7 +- Rebuilt for Python 3.7 + +* Fri Feb 09 2018 Fedora Release Engineering - 1.15.0-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Fri Sep 29 2017 Troy Dawson - 1.15.0-5 +- Cleanup spec file conditionals + +* Thu Jul 27 2017 Fedora Release Engineering - 1.15.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Sat Feb 11 2017 Fedora Release Engineering - 1.15.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Tue Dec 13 2016 Miro Hrončok - 1.15.0-2 +- Rebuild for Python 3.6 + +* Tue Oct 04 2016 Avram Lubkin - 1.15.0-1 +- Latest Release + +* Wed Jun 15 2016 Avram Lubkin - 1.14.0-1 +- Latest Release + +* Sun Mar 27 2016 Avram Lubkin - 1.12.0GIT99fd864-1 +- Latest Snapshot +- Fixed SRPM naming for EPEL7+ + +* Fri Feb 12 2016 Avram Lubkin - 1.12.0GITa4774ee-1 +- Latest Snapshot +- Drop EPEL5 from master spec +- Patch to support EL6 +- Disable python2 package for EPEL7+ + +* Mon Feb 01 2016 Avram Lubkin - 1.12.0GIT465785f-4 +- Changed Python2 package name to python2-dns for Fedora 24+ + +* Fri Jan 22 2016 Avram Lubkin - 1.12.0GIT465785f-3 +- Using python3_pkgversion to support python34 package in el7 +- Build Python3 package for el7+ + +* Tue Nov 10 2015 Fedora Release Engineering - 1.12.0GIT465785f-2 +- Rebuilt for https://fedoraproject.org/wiki/Changes/python3.5 + +* Fri Sep 11 2015 Petr Spacek - 1.12.0GIT465785f +- Rebase to GIT snapshots 465785f85f87508209117264c677080e901e957c (Python 2) + and 1b0c15086f0e5f6eacc06d77a119280c31731b3c (Python 3) + to pull in latest fixes + +* Thu Jun 18 2015 Fedora Release Engineering - 1.12.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Sat Jun 07 2014 Fedora Release Engineering - 1.11.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Wed May 28 2014 Kalev Lember - 1.11.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Changes/Python_3.4 + +* 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: +- +- Nothing +- +- Bugs fixed since 1.11.1: +- +- dns.resolver.Resolver erroneously referred to 'retry_servfail' +- instead of 'self.retry_servfail'. +- +- dns.tsigkeyring.to_text() would fail trying to convert the +- keyname to text. +- +- Multi-message TSIGs were broken for algorithms other than +- HMAC-MD5 because we weren't passing the right digest module to +- the HMAC code. +- +- dns.dnssec._find_candidate_keys() tried to extract the key +- from the wrong variable name. +- +- $GENERATE tests were not backward compatible with python 2.4. +- +- APL RR trailing zero suppression didn't work due to insufficient +- python 3 porting. [dnspython3 only] + +* Sun Aug 04 2013 Fedora Release Engineering - 1.11.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Sun Jul 7 2013 Jeffrey C. Ollie - 1.11.0-2 +- Integrate Python 2.6 packaging, EPEL5, EPEL6 support + +* Sun Jul 7 2013 Jeffrey C. Ollie - 1.11.0-1 +- New since 1.10.0: +- +- $GENERATE support +- +- TLSA RR support +- +- Added set_flags() method to dns.resolver.Resolver +- +- Bugs fixed since 1.10.0: +- +- Names with offsets >= 2^14 are no longer added to the +- compression table. +- +- The "::" syntax is not used to shorten a single 16-bit section +- of the text form an IPv6 address. +- +- Caches are now locked. +- +- YXDOMAIN is raised if seen by the resolver. +- +- Empty rdatasets are not printed. +- +- DNSKEY key tags are no longer assumed to be unique. + +* Sat Feb 16 2013 Jamie Nguyen - 1.10.0-3 +- add python3-dns subpackage (rhbz#911933) + +* Thu Feb 14 2013 Fedora Release Engineering - 1.10.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Mon Sep 17 2012 Paul Wouters - 1.10.0-1 +- Updated to 1.10.0 +- Patch to support TLSA RRtype + +* Sat Jul 21 2012 Fedora Release Engineering - 1.9.4-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Sat Jan 14 2012 Fedora Release Engineering - 1.9.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Mon Mar 28 2011 Jeffrey C. Ollie - 1.9.4-1 +- +- dnspython 1.9.4 has been released and is available at +- http://www.dnspython.org/kits/1.9.4/ +- +- There is no new functionality in this release; just a few bug fixes +- in RRSIG and SIG code. +- +- I will be eliminating legacy code for earlier versions of DNSSEC in a +- future release of dnspython. + +* Fri Mar 25 2011 Jeffrey C. Ollie - 1.9.3-1 +- +- New since 1.9.2: +- +- A boolean parameter, 'raise_on_no_answer', has been added to +- the query() methods. In no-error, no-data situations, this +- parameter determines whether NoAnswer should be raised or not. +- If True, NoAnswer is raised. If False, then an Answer() +- object with a None rrset will be returned. +- +- Resolver Answer() objects now have a canonical_name field. +- +- Rdata now have a __hash__ method. +- +- Bugs fixed since 1.9.2: +- +- Dnspython was erroneously doing case-insensitive comparisons +- of the names in NSEC and RRSIG RRs. +- +- We now use "is" and not "==" when testing what section an RR +- is in. +- +- The resolver now disallows metaqueries. + +* Tue Feb 08 2011 Fedora Release Engineering - 1.9.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Thu Dec 2 2010 Jeffrey C. Ollie - 1.9.2-2 +- Build Python 2.6 subpackage for EPEL 5 + +* Tue Nov 23 2010 Jeffrey C. Ollie - 1.9.2-1 +- It's brown paper bag time :) The fix for the import problems was +- actually bad, but didn't show up in testing because the test suite's +- conditional importing code hid the problem. +- +- Any, 1.9.2 is out. +- +- Sorry for the churn! + +* Mon Nov 22 2010 Jeffrey C. Ollie - 1.9.1-1 +- New since 1.9.0: +- +- Nothing. +- +- Bugs fixed since 1.9.0 +- +- The dns.dnssec module didn't work with DSA due to namespace +- contamination from a "from"-style import. +- +- New since 1.8.0: +- +- dnspython now uses poll() instead of select() when available. +- +- Basic DNSSEC validation can be done using dns.dnsec.validate() +- and dns.dnssec.validate_rrsig() if you have PyCrypto 2.3 or +- later installed. Complete secure resolution is not yet +- available. +- +- Added key_id() to the DNSSEC module, which computes the DNSSEC +- key id of a DNSKEY rdata. +- +- Added make_ds() to the DNSSEC module, which returns the DS RR +- for a given DNSKEY rdata. +- +- dnspython now raises an exception if HMAC-SHA284 or +- HMAC-SHA512 are used with a Python older than 2.5.2. (Older +- Pythons do not compute the correct value.) +- +- Symbolic constants are now available for TSIG algorithm names. +- +- Bugs fixed since 1.8.0 +- +- dns.resolver.zone_for_name() didn't handle a query response +- with a CNAME or DNAME correctly in some cases. +- +- When specifying rdata types and classes as text, Unicode +- strings may now be used. +- +- Hashlib compatibility issues have been fixed. +- +- dns.message now imports dns.edns. +- +- The TSIG algorithm value was passed incorrectly to use_tsig() +- in some cases. + +* Fri Aug 13 2010 Jeffrey C. Ollie - 1.8.0-3 +- Add a patch from upstream to fix a Python 2.7 issue. + +* Thu Jul 22 2010 David Malcolm - 1.8.0-2.1 +- Rebuilt for https://fedoraproject.org/wiki/Features/Python_2.7/MassRebuild + +* Wed Jan 27 2010 Jeffrey C. Ollie - 1.8.0-1.1 +- Fix error + +* Wed Jan 27 2010 Jeffrey C. Ollie - 1.8.0-1 +- New since 1.7.1: +- +- Support for hmac-sha1, hmac-sha224, hmac-sha256, hmac-sha384 and +- hmac-sha512 has been contributed by Kevin Chen. +- +- The tokenizer's tokens are now Token objects instead of (type, +- value) tuples. +- +- Bugs fixed since 1.7.1: +- +- Escapes in masterfiles now work correctly. Previously they were +- only working correctly when the text involved was part of a domain +- name. +- +- When constructing a DDNS update, if the present() method was used +- with a single rdata, a zero TTL was not added. +- +- The entropy pool needed locking to be thread safe. +- +- The entropy pool's reading of /dev/random could cause dnspython to +- block. +- +- The entropy pool did buffered reads, potentially consuming more +- randomness than we needed. +- +- The entropy pool did not seed with high quality randomness on +- Windows. +- +- SRV records were compared incorrectly. +- +- In the e164 query function, the resolver parameter was not used. + +* Sun Jul 26 2009 Fedora Release Engineering - 1.7.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Fri Jun 19 2009 Jeffrey C. Ollie - 1.7.1-1 +- New since 1.7.0: +- +- Nothing +- +- Bugs fixed since 1.7.0: +- +- The 1.7.0 kitting process inadventently omitted the code for the +- DLV RR. +- +- Negative DDNS prerequisites are now handled correctly. + +* Fri Jun 19 2009 Jeffrey C. Ollie - 1.7.0-1 +- New since 1.6.0: +- +- Rdatas now have a to_digestable() method, which returns the +- DNSSEC canonical form of the rdata, suitable for use in +- signature computations. +- +- The NSEC3, NSEC3PARAM, DLV, and HIP RR types are now supported. +- +- An entropy module has been added and is used to randomize query ids. +- +- EDNS0 options are now supported. +- +- UDP IXFR is now supported. +- +- The wire format parser now has a 'one_rr_per_rrset' mode, which +- suppresses the usual coalescing of all RRs of a given type into a +- single RRset. +- +- Various helpful DNSSEC-related constants are now defined. +- +- The resolver's query() method now has an optional 'source' parameter, +- allowing the source IP address to be specified. +- +- Bugs fixed since 1.6.0: +- +- On Windows, the resolver set the domain incorrectly. +- +- DS RR parsing only allowed one Base64 chunk. +- +- TSIG validation didn't always use absolute names. +- +- NSEC.to_text() only printed the last window. +- +- We did not canonicalize IPv6 addresses before comparing them; we +- would thus treat equivalent but different textual forms, e.g. +- "1:00::1" and "1::1" as being non-equivalent. +- +- If the peer set a TSIG error, we didn't raise an exception. +- +- Some EDNS bugs in the message code have been fixed (see the ChangeLog +- for details). + +* Thu Feb 26 2009 Fedora Release Engineering - 1.6.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Sat Nov 29 2008 Jeffrey C. Ollie - 1.6.0-3 +- Rebuild for Python 2.6 + +* Fri Aug 29 2008 Tom "spot" Callaway - 1.6.0-2 +- fix license tag + +* Tue Dec 4 2007 Jeffrey C. Ollie - 1.6.0-1 +- Update to 1.6.0 + +* Tue Oct 9 2007 Jeffrey C. Ollie - 1.5.0-2 +- Follow new Python egg packaging specs + +* Thu Jan 11 2007 Jeffrey C. Ollie - 1.5.0-1 +- Update to 1.5.0 + +* Fri Dec 8 2006 Jeffrey C. Ollie - 1.4.0-3 +- Bump release for rebuild with Python 2.5 + +* Mon Aug 14 2006 Jeffrey C. Ollie - 1.4.0-2 +- No longer ghost *.pyo files, thus further simplifying the files section. + +* Sat Aug 5 2006 Jeffrey C. Ollie - 1.4.0-1 +- Update to 1.4.0 +- Remove unneeded python-abi requires +- Remove unneeded python_sitearch macro + +* Fri May 26 2006 Jeffrey C. Ollie - 1.3.5-1 +- First version for Fedora Extras diff --git a/sources b/sources new file mode 100644 index 0000000..8cf193c --- /dev/null +++ b/sources @@ -0,0 +1 @@ +SHA512 (dnspython-1.16.0.tar.gz) = 41ddca2faf696d5d682551f517efd90c007011c1f6d9355d297d71a3fe84222a1e528945343d8c2276ad3957ceaab578f3df7c2c1709418ffcca01ccbb379359 diff --git a/switch_to_python_cryptography.patch b/switch_to_python_cryptography.patch new file mode 100644 index 0000000..b7cfab7 --- /dev/null +++ b/switch_to_python_cryptography.patch @@ -0,0 +1,343 @@ +From 087df702931f32eeb3a29957a8fe3fa31749d642 Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Tue, 28 Apr 2020 10:08:02 +0200 +Subject: [PATCH] Switch to python cryptography + +Original patch: https://github.com/simo5/dnspython/commit/bfe84d523bd4fde7b2655857d78bba85ed05f43c +The same change in master: https://github.com/rthalley/dnspython/pull/449 +--- + dns/dnssec.py | 168 ++++++++++++++++++++----------------------- + setup.py | 2 +- + tests/test_dnssec.py | 12 +--- + 3 files changed, 79 insertions(+), 103 deletions(-) + +diff --git a/dns/dnssec.py b/dns/dnssec.py +index 35da6b5..73e92da 100644 +--- a/dns/dnssec.py ++++ b/dns/dnssec.py +@@ -17,6 +17,7 @@ + + """Common DNSSEC-related functions and constants.""" + ++import hashlib # used in make_ds() to avoid pycrypto dependency + from io import BytesIO + import struct + import time +@@ -165,10 +166,10 @@ def make_ds(name, key, algorithm, origin=None): + + if algorithm.upper() == 'SHA1': + dsalg = 1 +- hash = SHA1.new() ++ hash = hashlib.sha1() + elif algorithm.upper() == 'SHA256': + dsalg = 2 +- hash = SHA256.new() ++ hash = hashlib.sha256() + else: + raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm) + +@@ -214,7 +215,7 @@ def _is_dsa(algorithm): + + + def _is_ecdsa(algorithm): +- return _have_ecdsa and (algorithm in (ECDSAP256SHA256, ECDSAP384SHA384)) ++ return (algorithm in (ECDSAP256SHA256, ECDSAP384SHA384)) + + + def _is_md5(algorithm): +@@ -240,18 +241,26 @@ def _is_sha512(algorithm): + + def _make_hash(algorithm): + if _is_md5(algorithm): +- return MD5.new() ++ return hashes.MD5() + if _is_sha1(algorithm): +- return SHA1.new() ++ return hashes.SHA1() + if _is_sha256(algorithm): +- return SHA256.new() ++ return hashes.SHA256() + if _is_sha384(algorithm): +- return SHA384.new() ++ return hashes.SHA384() + if _is_sha512(algorithm): +- return SHA512.new() ++ return hashes.SHA512() ++ if algorithm == ED25519: ++ return hashes.SHA512() ++ if algorithm == ED448: ++ return hashes.SHAKE256(114) + raise ValidationFailure('unknown hash for algorithm %u' % algorithm) + + ++def _bytes_to_long(b): ++ return int.from_bytes(b, 'big') ++ ++ + def _make_algorithm_id(algorithm): + if _is_md5(algorithm): + oid = [0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05] +@@ -316,8 +325,6 @@ def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None): + if rrsig.inception > now: + raise ValidationFailure('not yet valid') + +- hash = _make_hash(rrsig.algorithm) +- + if _is_rsa(rrsig.algorithm): + keyptr = candidate_key.key + (bytes_,) = struct.unpack('!B', keyptr[0:1]) +@@ -328,9 +335,9 @@ def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None): + rsa_e = keyptr[0:bytes_] + rsa_n = keyptr[bytes_:] + try: +- pubkey = CryptoRSA.construct( +- (number.bytes_to_long(rsa_n), +- number.bytes_to_long(rsa_e))) ++ public_key = rsa.RSAPublicNumbers( ++ _bytes_to_long(rsa_e), ++ _bytes_to_long(rsa_n)).public_key(default_backend()) + except ValueError: + raise ValidationFailure('invalid public key') + sig = rrsig.signature +@@ -346,42 +353,47 @@ def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None): + dsa_g = keyptr[0:octets] + keyptr = keyptr[octets:] + dsa_y = keyptr[0:octets] +- pubkey = CryptoDSA.construct( +- (number.bytes_to_long(dsa_y), +- number.bytes_to_long(dsa_g), +- number.bytes_to_long(dsa_p), +- number.bytes_to_long(dsa_q))) +- sig = rrsig.signature[1:] ++ try: ++ public_key = dsa.DSAPublicNumbers( ++ _bytes_to_long(dsa_y), ++ dsa.DSAParameterNumbers( ++ _bytes_to_long(dsa_p), ++ _bytes_to_long(dsa_q), ++ _bytes_to_long(dsa_g))).public_key(default_backend()) ++ except ValueError: ++ raise ValidationFailure('invalid public key') ++ sig_r = rrsig.signature[1:21] ++ sig_s = rrsig.signature[21:] ++ sig = utils.encode_dss_signature(_bytes_to_long(sig_r), ++ _bytes_to_long(sig_s)) + elif _is_ecdsa(rrsig.algorithm): +- # use ecdsa for NIST-384p -- not currently supported by pycryptodome +- + keyptr = candidate_key.key +- + if rrsig.algorithm == ECDSAP256SHA256: +- curve = ecdsa.curves.NIST256p +- key_len = 32 ++ curve = ec.SECP256R1() ++ octets = 32 + elif rrsig.algorithm == ECDSAP384SHA384: +- curve = ecdsa.curves.NIST384p +- key_len = 48 +- +- x = number.bytes_to_long(keyptr[0:key_len]) +- y = number.bytes_to_long(keyptr[key_len:key_len * 2]) +- if not ecdsa.ecdsa.point_is_valid(curve.generator, x, y): +- raise ValidationFailure('invalid ECDSA key') +- 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(number.bytes_to_long(r), +- number.bytes_to_long(s)) ++ curve = ec.SECP384R1() ++ octets = 48 ++ ecdsa_x = keyptr[0:octets] ++ ecdsa_y = keyptr[octets:octets * 2] ++ try: ++ public_key = ec.EllipticCurvePublicNumbers( ++ curve=curve, ++ x=_bytes_to_long(ecdsa_x), ++ y=_bytes_to_long(ecdsa_y)).public_key(default_backend()) ++ except ValueError: ++ raise ValidationFailure('invalid public key') ++ sig_r = rrsig.signature[0:octets] ++ sig_s = rrsig.signature[octets:] ++ sig = utils.encode_dss_signature(_bytes_to_long(sig_r), ++ _bytes_to_long(sig_s)) + + else: + raise ValidationFailure('unknown algorithm %u' % rrsig.algorithm) + +- hash.update(_to_rdata(rrsig, origin)[:18]) +- hash.update(rrsig.signer.to_digestable(origin)) ++ data = b'' ++ data += _to_rdata(rrsig, origin)[:18] ++ data += rrsig.signer.to_digestable(origin) + + if rrsig.labels < len(rrname) - 1: + suffix = rrname.split(rrsig.labels + 1)[1] +@@ -391,25 +403,21 @@ def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None): + rrsig.original_ttl) + rrlist = sorted(rdataset) + for rr in rrlist: +- hash.update(rrnamebuf) +- hash.update(rrfixed) ++ data += rrnamebuf ++ data += rrfixed + rrdata = rr.to_digestable(origin) + rrlen = struct.pack('!H', len(rrdata)) +- hash.update(rrlen) +- hash.update(rrdata) ++ data += rrlen ++ data += rrdata + ++ chosen_hash = _make_hash(rrsig.algorithm) + try: + if _is_rsa(rrsig.algorithm): +- verifier = pkcs1_15.new(pubkey) +- # will raise ValueError if verify fails: +- verifier.verify(hash, sig) ++ public_key.verify(sig, data, padding.PKCS1v15(), chosen_hash) + elif _is_dsa(rrsig.algorithm): +- verifier = DSS.new(pubkey, 'fips-186-3') +- verifier.verify(hash, sig) ++ public_key.verify(sig, data, chosen_hash) + elif _is_ecdsa(rrsig.algorithm): +- digest = hash.digest() +- if not pubkey.verify(digest, sig): +- raise ValueError ++ public_key.verify(sig, data, ec.ECDSA(chosen_hash)) + else: + # Raise here for code clarity; this won't actually ever happen + # since if the algorithm is really unknown we'd already have +@@ -417,7 +425,7 @@ def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None): + raise ValidationFailure('unknown algorithm %u' % rrsig.algorithm) + # If we got here, we successfully verified so we can return without error + return +- except ValueError: ++ except InvalidSignature: + # this happens on an individual validation failure + continue + # nothing verified -- raise failure: +@@ -472,48 +480,24 @@ def _validate(rrset, rrsigset, keys, origin=None, now=None): + raise ValidationFailure("no RRSIGs validated") + + +-def _need_pycrypto(*args, **kwargs): +- raise NotImplementedError("DNSSEC validation requires pycryptodome/pycryptodomex") ++def _need_pyca(*args, **kwargs): ++ raise NotImplementedError("DNSSEC validation requires python cryptography") + + + try: +- try: +- # test we're using pycryptodome, not pycrypto (which misses SHA1 for example) +- from Crypto.Hash import MD5, SHA1, SHA256, SHA384, SHA512 +- from Crypto.PublicKey import RSA as CryptoRSA, DSA as CryptoDSA +- from Crypto.Signature import pkcs1_15, DSS +- from Crypto.Util import number +- except ImportError: +- from Cryptodome.Hash import MD5, SHA1, SHA256, SHA384, SHA512 +- from Cryptodome.PublicKey import RSA as CryptoRSA, DSA as CryptoDSA +- from Cryptodome.Signature import pkcs1_15, DSS +- from Cryptodome.Util import number ++ from cryptography.exceptions import InvalidSignature ++ from cryptography.hazmat.backends import default_backend ++ from cryptography.hazmat.primitives import hashes ++ from cryptography.hazmat.primitives.asymmetric import padding ++ from cryptography.hazmat.primitives.asymmetric import utils ++ from cryptography.hazmat.primitives.asymmetric import dsa ++ from cryptography.hazmat.primitives.asymmetric import ec ++ from cryptography.hazmat.primitives.asymmetric import rsa + except ImportError: +- validate = _need_pycrypto +- validate_rrsig = _need_pycrypto +- _have_pycrypto = False +- _have_ecdsa = False ++ validate = _need_pyca ++ validate_rrsig = _need_pyca ++ _have_pyca = False + else: + validate = _validate + validate_rrsig = _validate_rrsig +- _have_pycrypto = True +- +- try: +- import ecdsa +- import ecdsa.ecdsa +- import ecdsa.ellipticcurve +- import ecdsa.keys +- except ImportError: +- _have_ecdsa = False +- else: +- _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 = number.bytes_to_long(digest) +- return self.key.pubkey.verifies(diglong, sig) ++ _have_pyca = True +diff --git a/setup.py b/setup.py +index 743d43c..2ee38a7 100755 +--- a/setup.py ++++ b/setup.py +@@ -75,7 +75,7 @@ direct manipulation of DNS zones, messages, names, and records.""", + 'provides': ['dns'], + 'extras_require': { + 'IDNA': ['idna>=2.1'], +- 'DNSSEC': ['pycryptodome', 'ecdsa>=0.13'], ++ 'DNSSEC': ['cryptography>=2.3'], + }, + 'ext_modules': ext_modules if compile_cython else None, + 'zip_safe': False if compile_cython else None, +diff --git a/tests/test_dnssec.py b/tests/test_dnssec.py +index c87862a..20b52b2 100644 +--- a/tests/test_dnssec.py ++++ b/tests/test_dnssec.py +@@ -151,8 +151,8 @@ abs_ecdsa384_soa_rrsig = dns.rrset.from_text('example.', 86400, 'IN', 'RRSIG', + + + +-@unittest.skipUnless(dns.dnssec._have_pycrypto, +- "Pycryptodome cannot be imported") ++@unittest.skipUnless(dns.dnssec._have_pyca, ++ "Python Cryptography cannot be imported") + class DNSSECValidatorTestCase(unittest.TestCase): + + def testAbsoluteRSAGood(self): # type: () -> None +@@ -199,28 +199,20 @@ class DNSSECValidatorTestCase(unittest.TestCase): + ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA256') + self.failUnless(ds == example_ds_sha256) + +- @unittest.skipUnless(dns.dnssec._have_ecdsa, +- "python ECDSA cannot be imported") + def testAbsoluteECDSA256Good(self): # type: () -> None + dns.dnssec.validate(abs_ecdsa256_soa, abs_ecdsa256_soa_rrsig, + abs_ecdsa256_keys, None, when3) + +- @unittest.skipUnless(dns.dnssec._have_ecdsa, +- "python ECDSA cannot be imported") + def testAbsoluteECDSA256Bad(self): # type: () -> None + def bad(): # type: () -> None + dns.dnssec.validate(abs_other_ecdsa256_soa, abs_ecdsa256_soa_rrsig, + abs_ecdsa256_keys, None, when3) + self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) + +- @unittest.skipUnless(dns.dnssec._have_ecdsa, +- "python ECDSA cannot be imported") + def testAbsoluteECDSA384Good(self): # type: () -> None + dns.dnssec.validate(abs_ecdsa384_soa, abs_ecdsa384_soa_rrsig, + abs_ecdsa384_keys, None, when4) + +- @unittest.skipUnless(dns.dnssec._have_ecdsa, +- "python ECDSA cannot be imported") + def testAbsoluteECDSA384Bad(self): # type: () -> None + def bad(): # type: () -> None + dns.dnssec.validate(abs_other_ecdsa384_soa, abs_ecdsa384_soa_rrsig, +-- +2.26.2 + diff --git a/typing.py b/typing.py new file mode 100644 index 0000000..0508422 --- /dev/null +++ b/typing.py @@ -0,0 +1,4 @@ +Set = Dict = None + +def cast(type, obj): + return obj diff --git a/unicode_label_escapify.patch b/unicode_label_escapify.patch new file mode 100644 index 0000000..58e5aa8 --- /dev/null +++ b/unicode_label_escapify.patch @@ -0,0 +1,110 @@ +diff -ru dnspython-1.16.0-orig/dns/name.py dnspython-1.16.0/dns/name.py +--- dnspython-1.16.0-orig/dns/name.py 2018-12-05 08:35:40.000000000 -0500 ++++ dnspython-1.16.0/dns/name.py 2020-01-22 01:07:53.319289996 -0500 +@@ -195,16 +195,10 @@ + self.allow_pure_ascii = allow_pure_ascii + self.strict_decode = strict_decode + +- def is_all_ascii(self, label): +- for c in label: +- if ord(c) > 0x7f: +- return False +- return True +- + def encode(self, label): + if label == '': + return b'' +- if self.allow_pure_ascii and self.is_all_ascii(label): ++ if self.allow_pure_ascii and is_all_ascii(label): + return label.encode('ascii') + if not have_idna_2008: + raise NoIDNA2008 +@@ -230,6 +224,7 @@ + raise IDNAException(idna_exception=e) + + _escaped = bytearray(b'"().;\\@$') ++_escaped_text = u'"().;\\@$' + + IDNA_2003_Practical = IDNA2003Codec(False) + IDNA_2003_Strict = IDNA2003Codec(True) +@@ -263,7 +258,9 @@ + if isinstance(label, binary_type): + label = label.decode() + for c in label: +- if c > u'\x20' and c < u'\x7f': ++ if c in _escaped_text: ++ text += u'\\' + c ++ elif c > u'\x20' and c < u'\x7f': + text += c + else: + if c >= u'\x7f': +@@ -827,7 +824,7 @@ + if text == u'@': + text = u'' + if text: +- if text == u'.': ++ if text in [u'.', u'\u3002', u'\uff0e', u'\uff61']: + return Name([b'']) # no Unicode "u" on this constant! + for c in text: + if escaping: +@@ -870,6 +867,13 @@ + return Name(labels) + + ++def is_all_ascii(text): ++ for c in text: ++ if ord(c) > 0x7f: ++ return False ++ return True ++ ++ + def from_text(text, origin=root, idna_codec=None): + """Convert text into a Name object. + +@@ -886,7 +890,18 @@ + """ + + if isinstance(text, text_type): +- return from_unicode(text, origin, idna_codec) ++ if not is_all_ascii(text): ++ # Some codepoint in the input text is > 127, so IDNA applies. ++ return from_unicode(text, origin, idna_codec) ++ # The input is all ASCII, so treat this like an ordinary non-IDNA ++ # domain name. Note that "all ASCII" is about the input text, ++ # not the codepoints in the domain name. E.g. if text has value ++ # ++ # r'\150\151\152\153\154\155\156\157\158\159' ++ # ++ # then it's still "all ASCII" even though the domain name has ++ # codepoints > 127. ++ text = text.encode('ascii') + if not isinstance(text, binary_type): + raise ValueError("input to from_text() must be a string") + if not (origin is None or isinstance(origin, Name)): +diff -ru dnspython-1.16.0-orig/tests/test_name.py dnspython-1.16.0/tests/test_name.py +--- dnspython-1.16.0-orig/tests/test_name.py 2018-12-01 10:48:40.000000000 -0500 ++++ dnspython-1.16.0/tests/test_name.py 2020-01-21 23:19:07.998492185 -0500 +@@ -255,6 +255,23 @@ + t = dns.name.root.to_unicode() + self.assertEqual(t, '.') + ++ def testToText12(self): ++ n = dns.name.from_text(r'a\.b.c') ++ t = n.to_unicode() ++ self.assertEqual(t, r'a\.b.c.') ++ ++ def testToText13(self): ++ n = dns.name.from_text(r'\150\151\152\153\154\155\156\157\158\159.') ++ t = n.to_text() ++ self.assertEqual(t, r'\150\151\152\153\154\155\156\157\158\159.') ++ ++ def testToText14(self): ++ # You can't send this to_unicode() as it wasn't unicode to begin with. ++ def bad(): ++ n = dns.name.from_text(r'\150\151\152\153\154\155\156\157\158\159.') ++ t = n.to_unicode() ++ self.failUnlessRaises(UnicodeDecodeError, bad) ++ + def testSlice1(self): + n = dns.name.from_text(r'a.b.c.', origin=None) + s = n[:]