Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:chajain:branches:Cloud:Openstack:Master
python-dnspython
pycryptodome.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File pycryptodome.patch of Package python-dnspython
From 10b8a42c90d037880fbfc81fb71adb27251252e3 Mon Sep 17 00:00:00 2001 From: Daniel Robbins <drobbins@funtoo.org> Date: Thu, 21 Dec 2017 09:24:40 -0700 Subject: [PATCH] Update DNSSEC code to use pycryptodome instead of pycrypto. These changes make dnspython *incompatible* with pycrypto -- pycryptodome must be used. The ecdsa module continues to be used for ECDSA support. --- ChangeLog | 5 ++ dns/__init__.py | 1 - dns/dnssec.py | 161 +++++++++++++++++++++++++++------------------------ dns/hash.py | 31 ---------- dns/tsig.py | 4 +- doc/dnssec.rst | 9 ++- doc/installation.rst | 4 +- tests/test_dnssec.py | 16 ++--- 8 files changed, 105 insertions(+), 126 deletions(-) delete mode 100644 dns/hash.py Index: dnspython-1.15.0/dns/__init__.py =================================================================== --- dnspython-1.15.0.orig/dns/__init__.py +++ dnspython-1.15.0/dns/__init__.py @@ -22,7 +22,6 @@ __all__ = [ 'entropy', 'exception', 'flags', - 'hash', 'inet', 'ipv4', 'ipv6', Index: dnspython-1.15.0/dns/dnssec.py =================================================================== --- dnspython-1.15.0.orig/dns/dnssec.py +++ dnspython-1.15.0/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 Index: dnspython-1.15.0/dns/hash.py =================================================================== --- dnspython-1.15.0.orig/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: dnspython-1.15.0/dns/tsig.py =================================================================== --- dnspython-1.15.0.orig/dns/tsig.py +++ dnspython-1.15.0/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") Index: dnspython-1.15.0/tests/test_dnssec.py =================================================================== --- dnspython-1.15.0.orig/tests/test_dnssec.py +++ dnspython-1.15.0/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,
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor