diff --git a/srcpkgs/python-dnspython/INSTALL.msg b/srcpkgs/python-dnspython/INSTALL.msg index 1ec1bee8adf..06fe4151e08 100644 --- a/srcpkgs/python-dnspython/INSTALL.msg +++ b/srcpkgs/python-dnspython/INSTALL.msg @@ -1 +1 @@ -In order to perform DNSSEC validation install python-crypto. +In order to perform DNSSEC validation install python-pycryptodome. diff --git a/srcpkgs/python-dnspython/patches/pycryptodome.patch b/srcpkgs/python-dnspython/patches/pycryptodome.patch new file mode 100644 index 00000000000..c4b905483ff --- /dev/null +++ b/srcpkgs/python-dnspython/patches/pycryptodome.patch @@ -0,0 +1,423 @@ +Backport of https://github.com/rthalley/dnspython/pull/290. + +--- dns/__init__.py ++++ dns/__init__.py +@@ -22,7 +22,6 @@ __all__ = [ + 'entropy', + 'exception', + 'flags', +- 'hash', + 'inet', + 'ipv4', + 'ipv6', +--- dns/dnssec.py ++++ dns/dnssec.py +@@ -20,7 +20,6 @@ import struct + import time + + import dns.exception +-import dns.hash + import dns.name + import dns.node + import dns.rdataset +@@ -28,7 +27,8 @@ import dns.rdata + import dns.rdatatype + import dns.rdataclass + from ._compat import string_types +- ++from Crypto.Hash import MD5, SHA1, SHA256, SHA384, SHA512 ++from Crypto.Signature import pkcs1_15, DSS + + class UnsupportedAlgorithm(dns.exception.DNSException): + +@@ -39,34 +39,34 @@ class ValidationFailure(dns.exception.DN + + """The DNSSEC signature is invalid.""" + +-RSAMD5 = 1 +-DH = 2 +-DSA = 3 +-ECC = 4 +-RSASHA1 = 5 +-DSANSEC3SHA1 = 6 +-RSASHA1NSEC3SHA1 = 7 +-RSASHA256 = 8 +-RSASHA512 = 10 +-ECDSAP256SHA256 = 13 +-ECDSAP384SHA384 = 14 ++ALGO_RSAMD5 = 1 ++ALGO_DH = 2 ++ALGO_DSA = 3 ++ALGO_ECC = 4 ++ALGO_RSASHA1 = 5 ++ALGO_DSANSEC3SHA1 = 6 ++ALGO_RSASHA1NSEC3SHA1 = 7 ++ALGO_RSASHA256 = 8 ++ALGO_RSASHA512 = 10 ++ALGO_ECDSAP256SHA256 = 13 ++ALGO_ECDSAP384SHA384 = 14 + 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, ++ 'RSAMD5': ALGO_RSAMD5, ++ 'DH': ALGO_DH, ++ 'DSA': ALGO_DSA, ++ 'ECC': ALGO_ECC, ++ 'RSASHA1': ALGO_RSASHA1, ++ 'DSANSEC3SHA1': ALGO_DSANSEC3SHA1, ++ 'RSASHA1NSEC3SHA1': ALGO_RSASHA1NSEC3SHA1, ++ 'RSASHA256': ALGO_RSASHA256, ++ 'RSASHA512': ALGO_RSASHA512, + 'INDIRECT': INDIRECT, +- 'ECDSAP256SHA256': ECDSAP256SHA256, +- 'ECDSAP384SHA384': ECDSAP384SHA384, ++ 'ECDSAP256SHA256': ALGO_ECDSAP256SHA256, ++ 'ECDSAP384SHA384': ALGO_ECDSAP384SHA384, + 'PRIVATEDNS': PRIVATEDNS, + 'PRIVATEOID': PRIVATEOID, + } +@@ -107,7 +107,7 @@ def _to_rdata(record, origin): + def key_id(key, origin=None): + rdata = _to_rdata(key, origin) + rdata = bytearray(rdata) +- if key.algorithm == RSAMD5: ++ if key.algorithm == ALGO_RSAMD5: + return (rdata[-3] << 8) + rdata[-2] + else: + total = 0 +@@ -123,10 +123,10 @@ def key_id(key, origin=None): + def make_ds(name, key, algorithm, origin=None): + if algorithm.upper() == 'SHA1': + dsalg = 1 +- hash = dns.hash.hashes['SHA1']() ++ hash = SHA1.new() + elif algorithm.upper() == 'SHA256': + dsalg = 2 +- hash = dns.hash.hashes['SHA256']() ++ hash = SHA256.new() + else: + raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm) + +@@ -162,51 +162,51 @@ def _find_candidate_keys(keys, rrsig): + + + def _is_rsa(algorithm): +- return algorithm in (RSAMD5, RSASHA1, +- RSASHA1NSEC3SHA1, RSASHA256, +- RSASHA512) ++ return algorithm in (ALGO_RSAMD5, ALGO_RSASHA1, ++ ALGO_RSASHA1NSEC3SHA1, ALGO_RSASHA256, ++ ALGO_RSASHA512) + + + def _is_dsa(algorithm): +- return algorithm in (DSA, DSANSEC3SHA1) ++ return algorithm in (ALGO_DSA, ALGO_DSANSEC3SHA1) + + + def _is_ecdsa(algorithm): +- return _have_ecdsa and (algorithm in (ECDSAP256SHA256, ECDSAP384SHA384)) ++ return _have_ecdsa and (algorithm in (ALGO_ECDSAP256SHA256, ALGO_ECDSAP384SHA384)) + + + def _is_md5(algorithm): +- return algorithm == RSAMD5 ++ return algorithm == ALGO_RSAMD5 + + + def _is_sha1(algorithm): +- return algorithm in (DSA, RSASHA1, +- DSANSEC3SHA1, RSASHA1NSEC3SHA1) ++ return algorithm in (ALGO_DSA, ALGO_RSASHA1, ++ ALGO_DSANSEC3SHA1, ALGO_RSASHA1NSEC3SHA1) + + + def _is_sha256(algorithm): +- return algorithm in (RSASHA256, ECDSAP256SHA256) ++ return algorithm in (ALGO_RSASHA256, ALGO_ECDSAP256SHA256) + + + def _is_sha384(algorithm): +- return algorithm == ECDSAP384SHA384 ++ return algorithm == ALGO_ECDSAP384SHA384 + + + def _is_sha512(algorithm): +- return algorithm == RSASHA512 ++ return algorithm == ALGO_RSASHA512 + + + def _make_hash(algorithm): + if _is_md5(algorithm): +- return dns.hash.hashes['MD5']() ++ return MD5.new() + if _is_sha1(algorithm): +- return dns.hash.hashes['SHA1']() ++ return SHA1.new() + if _is_sha256(algorithm): +- return dns.hash.hashes['SHA256']() ++ return SHA256.new() + if _is_sha384(algorithm): +- return dns.hash.hashes['SHA384']() ++ return SHA384.new() + if _is_sha512(algorithm): +- return dns.hash.hashes['SHA512']() ++ return SHA512.new() + raise ValidationFailure('unknown hash for algorithm %u' % algorithm) + + +@@ -284,11 +284,13 @@ def _validate_rrsig(rrset, rrsig, keys, + keyptr = keyptr[2:] + rsa_e = keyptr[0:bytes_] + rsa_n = keyptr[bytes_:] +- 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),) ++ try: ++ pubkey = Crypto.PublicKey.RSA.construct( ++ (Crypto.Util.number.bytes_to_long(rsa_n), ++ Crypto.Util.number.bytes_to_long(rsa_e))) ++ except ValueError: ++ raise ValidationFailure('invalid public key') ++ sig = rrsig.signature + elif _is_dsa(rrsig.algorithm): + keyptr = candidate_key.key + (t,) = struct.unpack('!B', keyptr[0:1]) +@@ -306,20 +308,19 @@ def _validate_rrsig(rrset, rrsig, keys, + 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)) ++ sig = rrsig.signature[1:] + elif _is_ecdsa(rrsig.algorithm): +- if rrsig.algorithm == ECDSAP256SHA256: ++ # use ecdsa for NIST-384p -- not currently supported by pycryptodome ++ ++ keyptr = candidate_key.key ++ ++ if rrsig.algorithm == ALGO_ECDSAP256SHA256: + curve = ecdsa.curves.NIST256p + key_len = 32 +- elif rrsig.algorithm == ECDSAP384SHA384: ++ elif rrsig.algorithm == ALGO_ECDSAP384SHA384: + curve = ecdsa.curves.NIST384p + key_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) +@@ -331,6 +332,7 @@ def _validate_rrsig(rrset, rrsig, keys, + 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) + +@@ -352,24 +354,31 @@ def _validate_rrsig(rrset, rrsig, keys, + 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 = struct.pack('!%dB' % (2 + padlen + 1), +- *([0, 1] + [0xFF] * padlen + [0])) + digest +- elif _is_dsa(rrsig.algorithm) or _is_ecdsa(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): ++ try: ++ if _is_rsa(rrsig.algorithm): ++ verifier = pkcs1_15.new(pubkey) ++ # will raise ValueError if verify fails: ++ verifier.verify(hash, sig) ++ elif _is_dsa(rrsig.algorithm): ++ verifier = DSS.new(pubkey, 'fips-186-3') ++ verifier.verify(hash, sig) ++ elif _is_ecdsa(rrsig.algorithm): ++ digest = hash.digest() ++ if pubkey.verify(digest, sig): ++ return ++ else: ++ raise ValueError ++ 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 we got here, we successfully verified so we can return without error + return ++ except ValueError: ++ # this happens on an individual validation failure ++ continue ++ # nothing verified -- raise failure: + raise ValidationFailure('verify failure') + + +@@ -401,10 +410,8 @@ def _validate(rrset, rrsigset, keys, ori + rrname = rrset.name + + if isinstance(rrsigset, tuple): +- rrsigname = rrsigset[0] + rrsigrdataset = rrsigset[1] + else: +- rrsigname = rrsigset.name + rrsigrdataset = rrsigset + + rrname = rrname.choose_relativity(origin) +@@ -422,7 +429,7 @@ def _validate(rrset, rrsigset, keys, ori + + + def _need_pycrypto(*args, **kwargs): +- raise NotImplementedError("DNSSEC validation requires pycrypto") ++ raise NotImplementedError("DNSSEC validation requires pycryptodome") + + try: + import Crypto.PublicKey.RSA +--- dns/hash.py ++++ /dev/null +@@ -1,31 +0,0 @@ +-# 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. +- +-"""Hashing backwards compatibility wrapper""" +- +-import hashlib +- +- +-hashes = {} +-hashes['MD5'] = hashlib.md5 +-hashes['SHA1'] = hashlib.sha1 +-hashes['SHA224'] = hashlib.sha224 +-hashes['SHA256'] = hashlib.sha256 +-hashes['SHA384'] = hashlib.sha384 +-hashes['SHA512'] = hashlib.sha512 +- +- +-def get(algorithm): +- return hashes[algorithm.upper()] +Index: dns/tsig.py +=================================================================== +--- dns/tsig.py ++++ dns/tsig.py +@@ -19,9 +19,9 @@ import hmac + import struct + + import dns.exception +-import dns.hash + import dns.rdataclass + import dns.name ++import dns.dnssec + from ._compat import long, string_types, text_type + + class BadTime(dns.exception.DNSException): +@@ -211,7 +211,7 @@ def get_algorithm(algorithm): + algorithm = dns.name.from_text(algorithm) + + try: +- return (algorithm.to_digestable(), dns.hash.hashes[_hashes[algorithm]]) ++ return (algorithm.to_digestable(), dns.dnssec._make_hash(algorithm)) + except KeyError: + raise NotImplementedError("TSIG algorithm " + str(algorithm) + + " is not supported") +--- tests/test_dnssec.py ++++ tests/test_dnssec.py +@@ -156,22 +156,22 @@ abs_other_ecdsa384_soa = dns.rrset.from_ + 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") + +-@unittest.skipUnless(import_ok, "skipping DNSSEC tests because pycrypto is not" ++@unittest.skipUnless(import_ok, "skipping DNSSEC tests because pycryptodome is not" + " installed") + class DNSSECValidatorTestCase(unittest.TestCase): + + @unittest.skipUnless(dns.dnssec._have_pycrypto, +- "PyCrypto cannot be imported") ++ "Pycryptodome cannot be imported") + def testAbsoluteRSAGood(self): + dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys, None, when) + + @unittest.skipUnless(dns.dnssec._have_pycrypto, +- "PyCrypto cannot be imported") ++ "Pycryptodome cannot be imported") + def testDuplicateKeytag(self): + dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys_duplicate_keytag, None, when) + + @unittest.skipUnless(dns.dnssec._have_pycrypto, +- "PyCrypto cannot be imported") ++ "Pycryptodome cannot be imported") + def testAbsoluteRSABad(self): + def bad(): + dns.dnssec.validate(abs_other_soa, abs_soa_rrsig, abs_keys, None, +@@ -179,13 +179,13 @@ class DNSSECValidatorTestCase(unittest.T + self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) + + @unittest.skipUnless(dns.dnssec._have_pycrypto, +- "PyCrypto cannot be imported") ++ "Pycryptodome cannot be imported") + def testRelativeRSAGood(self): + dns.dnssec.validate(rel_soa, rel_soa_rrsig, rel_keys, + abs_dnspython_org, when) + + @unittest.skipUnless(dns.dnssec._have_pycrypto, +- "PyCrypto cannot be imported") ++ "Pycryptodome cannot be imported") + def testRelativeRSABad(self): + def bad(): + dns.dnssec.validate(rel_other_soa, rel_soa_rrsig, rel_keys, +@@ -197,13 +197,13 @@ class DNSSECValidatorTestCase(unittest.T + self.failUnless(ds == good_ds) + + @unittest.skipUnless(dns.dnssec._have_pycrypto, +- "PyCrypto cannot be imported") ++ "Pycryptodome cannot be imported") + def testAbsoluteDSAGood(self): + dns.dnssec.validate(abs_dsa_soa, abs_dsa_soa_rrsig, abs_dsa_keys, None, + when2) + + @unittest.skipUnless(dns.dnssec._have_pycrypto, +- "PyCrypto cannot be imported") ++ "Pycryptodome cannot be imported") + def testAbsoluteDSABad(self): + def bad(): + dns.dnssec.validate(abs_other_dsa_soa, abs_dsa_soa_rrsig, diff --git a/srcpkgs/python-dnspython/python3-dnspython.INSTALL.msg b/srcpkgs/python-dnspython/python3-dnspython.INSTALL.msg index 42f1d177a9f..bfebe283394 100644 --- a/srcpkgs/python-dnspython/python3-dnspython.INSTALL.msg +++ b/srcpkgs/python-dnspython/python3-dnspython.INSTALL.msg @@ -1 +1 @@ -In order to perform DNSSEC validation install python3-crypto. +In order to perform DNSSEC validation install python3-pycryptodome. diff --git a/srcpkgs/python-dnspython/template b/srcpkgs/python-dnspython/template index 0c423f0938a..49699fe4507 100644 --- a/srcpkgs/python-dnspython/template +++ b/srcpkgs/python-dnspython/template @@ -1,7 +1,7 @@ # Template file for 'python-dnspython' pkgname=python-dnspython version=1.15.0 -revision=4 +revision=5 noarch=yes wrksrc="dnspython-${version}" build_style=python-module