]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
dns/dnssec: support both pycryptodome and pycryptodomex
authorTomas Krizek <tomas.krizek@nic.cz>
Wed, 18 Jul 2018 12:56:31 +0000 (14:56 +0200)
committerTomas Krizek <tomas.krizek@nic.cz>
Fri, 20 Jul 2018 14:24:17 +0000 (16:24 +0200)
ChangeLog
dns/dnssec.py
doc/dnssec.rst
doc/installation.rst
setup.py
tests/test_dnssec.py

index 1e15697bfc83b913da359fa19a4aa17d99d19fdf..0c76f96956855c701b819c17d5c0b40c978a0a78 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,8 @@
 2017-12-21  Daniel Robbins  <drobbins@funtoo.org>
 
        * dns/dnssec.py: migrated code from pycrypto (apparently no
-         longer maintained) to pycryptodome. All tests passing.
+         longer maintained) to pycryptodome/pycryptodomex.
+         All tests passing.
 
 2018-07-18  Tomas Krizek  <tomas.krizek@nic.cz>
 
index b154b10bd08afdd1f3e92c9aed89b5345de65ca0..634c934b3501557fea04078737e94020297b432c 100644 (file)
@@ -27,8 +27,7 @@ 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):
     """The DNSSEC algorithm is not supported."""
@@ -327,9 +326,9 @@ def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None):
             rsa_e = keyptr[0:bytes_]
             rsa_n = keyptr[bytes_:]
             try:
-                pubkey = Crypto.PublicKey.RSA.construct(
-                    (Crypto.Util.number.bytes_to_long(rsa_n),
-                     Crypto.Util.number.bytes_to_long(rsa_e)))
+                pubkey = CryptoRSA.construct(
+                    (number.bytes_to_long(rsa_n),
+                     number.bytes_to_long(rsa_e)))
             except ValueError:
                 raise ValidationFailure('invalid public key')
             sig = rrsig.signature
@@ -345,11 +344,11 @@ def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None):
             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)))
+            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:]
         elif _is_ecdsa(rrsig.algorithm):
             # use ecdsa for NIST-384p -- not currently supported by pycryptodome
@@ -363,8 +362,8 @@ def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None):
                 curve = ecdsa.curves.NIST384p
                 key_len = 48
 
-            x = Crypto.Util.number.bytes_to_long(keyptr[0:key_len])
-            y = Crypto.Util.number.bytes_to_long(keyptr[key_len:key_len * 2])
+            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)
@@ -373,8 +372,8 @@ def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None):
             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))
+            sig = ecdsa.ecdsa.Signature(number.bytes_to_long(r),
+                                        number.bytes_to_long(s))
 
         else:
             raise ValidationFailure('unknown algorithm %u' % rrsig.algorithm)
@@ -474,36 +473,47 @@ def _validate(rrset, rrsigset, keys, origin=None, now=None):
 
 
 def _need_pycrypto(*args, **kwargs):
-    raise NotImplementedError("DNSSEC validation requires pycryptodome")
+    raise NotImplementedError("DNSSEC validation requires pycryptodome/pycryptodomex")
+
 
 try:
-    import Crypto.PublicKey.RSA
-    import Crypto.PublicKey.DSA
-    import Crypto.Util.number
-    validate = _validate
-    validate_rrsig = _validate_rrsig
-    _have_pycrypto = True
+    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
 except ImportError:
     validate = _need_pycrypto
     validate_rrsig = _need_pycrypto
     _have_pycrypto = False
+    _have_ecdsa = False
+else:
+    validate = _validate
+    validate_rrsig = _validate_rrsig
+    _have_pycrypto = True
 
-try:
-    import ecdsa
-    import ecdsa.ecdsa
-    import ecdsa.ellipticcurve
-    import ecdsa.keys
-    _have_ecdsa = True
-
-    class ECKeyWrapper(object):
+    try:
+        import ecdsa
+        import ecdsa.ecdsa
+        import ecdsa.ellipticcurve
+        import ecdsa.keys
+    except ImportError:
+        _have_ecdsa = False
+    else:
+        _have_ecdsa = True
 
-        def __init__(self, key, key_len):
-            self.key = key
-            self.key_len = key_len
+        class ECKeyWrapper(object):
 
-        def verify(self, digest, sig):
-            diglong = Crypto.Util.number.bytes_to_long(digest)
-            return self.key.pubkey.verifies(diglong, sig)
+            def __init__(self, key, key_len):
+                self.key = key
+                self.key_len = key_len
 
-except ImportError:
-    _have_ecdsa = False
+            def verify(self, digest, sig):
+                diglong = number.bytes_to_long(digest)
+                return self.key.pubkey.verifies(diglong, sig)
index 64f08b3c932ff005e7bffd604bafab2502fe7947..115f9734ae941357203caf8e91a7759d92733df0 100644 (file)
@@ -6,8 +6,8 @@ DNSSEC
 
 Dnspython can do simple DNSSEC signature validation, but currently has no
 facilities for signing.  In order to use DNSSEC functions, you must have
-``pycryptodome`` installed.  If you want to do elliptic curves, you must also
-have ``ecdsa`` installed.
+``pycryptodome`` or ``pycryptodomex`` installed.  If you want to do elliptic
+curves, you must also have ``ecdsa`` installed.
 
 DNSSEC Algorithms
 -----------------
index 7854f3daac1cb22ff5d326cb11e948357eb4d589..e480655afe58d551dddbd12979bf11f0b2b69aa3 100644 (file)
@@ -45,8 +45,8 @@ Optional Modules
 
 The following modules are optional, but recommended for full functionality.
 
-If ``pycryptodome`` is installed, then dnspython will be able to do low-level
-DNSSEC RSA and DSA signature validation.
+If ``pycryptodome`` / ``pycryptodomex`` is installed, then dnspython will be
+able to do low-level DNSSEC RSA and DSA signature validation.
 
 If ``ecdsa`` is installed, then Elliptic Curve signature algorithms will
 be available for low-level DNSSEC signature validation.
index b4511fa37253e374fa14e9593ab043ba30767c63..d190eb62f6c6bacc2579af7d70ceaa58f22c609d 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -62,7 +62,7 @@ direct manipulation of DNS zones, messages, names, and records.""",
     'provides': ['dns'],
     'extras_require': {
         'IDNA': ['idna>=2.1'],
-        'DNSSEC': ['pycrypto>=2.6.1', 'ecdsa>=0.13'],
+        'DNSSEC': ['pycryptodome', 'ecdsa>=0.13'],
         },
     }
 
index 9fb037e1721ef3918c1aa545ff8803b1c2ea1fc2..78b1cdc963b7b9be1bd184819b3a3bb262772188 100644 (file)
@@ -20,12 +20,6 @@ try:
 except ImportError:
     import unittest
 
-try:
-    import Crypto.Util.number  # pylint: disable=unused-import
-    import_ok = True
-except ImportError:
-    import_ok = False
-
 import dns.dnssec
 import dns.name
 import dns.rdata
@@ -156,36 +150,28 @@ abs_other_ecdsa384_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA',
 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 pycryptodome is not"
-                                " installed")
+
+
+@unittest.skipUnless(dns.dnssec._have_pycrypto,
+                     "Pycryptodome cannot be imported")
 class DNSSECValidatorTestCase(unittest.TestCase):
 
-    @unittest.skipUnless(dns.dnssec._have_pycrypto,
-                         "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,
-                         "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,
-                         "Pycryptodome cannot be imported")
     def testAbsoluteRSABad(self):
         def bad():
             dns.dnssec.validate(abs_other_soa, abs_soa_rrsig, abs_keys, None,
                                 when)
         self.failUnlessRaises(dns.dnssec.ValidationFailure, bad)
 
-    @unittest.skipUnless(dns.dnssec._have_pycrypto,
-                         "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,
-                         "Pycryptodome cannot be imported")
     def testRelativeRSABad(self):
         def bad():
             dns.dnssec.validate(rel_other_soa, rel_soa_rrsig, rel_keys,
@@ -196,14 +182,10 @@ class DNSSECValidatorTestCase(unittest.TestCase):
         ds = dns.dnssec.make_ds(abs_dnspython_org, sep_key, 'SHA256')
         self.failUnless(ds == good_ds)
 
-    @unittest.skipUnless(dns.dnssec._have_pycrypto,
-                         "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,
-                         "Pycryptodome cannot be imported")
     def testAbsoluteDSABad(self):
         def bad():
             dns.dnssec.validate(abs_other_dsa_soa, abs_dsa_soa_rrsig,