summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomas Krizek <tomas.krizek@nic.cz>2018-07-18 14:56:31 +0200
committerTomas Krizek <tomas.krizek@nic.cz>2018-07-20 16:24:17 +0200
commitc15a34bc0ee818620fdb23a2a2bc0366f23feab0 (patch)
tree0c7fefb5d52f97b41ca122b12da96beb4e1b5fdf
parent8d7a84a2dfeffd2d080296898aadb3503cc237e1 (diff)
downloaddnspython-c15a34bc0ee818620fdb23a2a2bc0366f23feab0.tar.gz
dns/dnssec: support both pycryptodome and pycryptodomex
-rw-r--r--ChangeLog3
-rw-r--r--dns/dnssec.py84
-rw-r--r--doc/dnssec.rst4
-rw-r--r--doc/installation.rst4
-rwxr-xr-xsetup.py2
-rw-r--r--tests/test_dnssec.py26
6 files changed, 58 insertions, 65 deletions
diff --git a/ChangeLog b/ChangeLog
index 1e15697..0c76f96 100644
--- 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>
diff --git a/dns/dnssec.py b/dns/dnssec.py
index b154b10..634c934 100644
--- a/dns/dnssec.py
+++ b/dns/dnssec.py
@@ -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)
diff --git a/doc/dnssec.rst b/doc/dnssec.rst
index 64f08b3..115f973 100644
--- a/doc/dnssec.rst
+++ b/doc/dnssec.rst
@@ -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
-----------------
diff --git a/doc/installation.rst b/doc/installation.rst
index 7854f3d..e480655 100644
--- a/doc/installation.rst
+++ b/doc/installation.rst
@@ -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.
diff --git a/setup.py b/setup.py
index b4511fa..d190eb6 100755
--- 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'],
},
}
diff --git a/tests/test_dnssec.py b/tests/test_dnssec.py
index 9fb037e..78b1cdc 100644
--- a/tests/test_dnssec.py
+++ b/tests/test_dnssec.py
@@ -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,