Update to 2.0.0 (#1849341)
This commit is contained in:
parent
9c3e101100
commit
5d66b1e0ec
3
.gitignore
vendored
3
.gitignore
vendored
@ -22,3 +22,6 @@
|
|||||||
/dnspython-1.12.0GIT99fd864.tar.gz
|
/dnspython-1.12.0GIT99fd864.tar.gz
|
||||||
/dnspython-1.15.0.tar.gz
|
/dnspython-1.15.0.tar.gz
|
||||||
/dnspython-1.16.0.tar.gz
|
/dnspython-1.16.0.tar.gz
|
||||||
|
/v2.0.0rc1.tar.gz
|
||||||
|
/v2.0.0.tar.gz
|
||||||
|
/dnspython-2.0.0.tar.gz
|
||||||
|
99
base64.patch
99
base64.patch
@ -1,99 +0,0 @@
|
|||||||
From f36ac6022a2a3d5b067387908aa31932234a31e1 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Lumir Balhar <lbalhar@redhat.com>
|
|
||||||
Date: Fri, 17 Apr 2020 08:01:22 +0200
|
|
||||||
Subject: [PATCH] Backwards compatibility for base64 module
|
|
||||||
|
|
||||||
---
|
|
||||||
dns/tsigkeyring.py | 16 ++++++++++++----
|
|
||||||
tests/test_tsigkeyring.py | 39 +++++++++++++++++++++++++++++++++++++++
|
|
||||||
2 files changed, 51 insertions(+), 4 deletions(-)
|
|
||||||
create mode 100644 tests/test_tsigkeyring.py
|
|
||||||
|
|
||||||
diff --git a/dns/tsigkeyring.py b/dns/tsigkeyring.py
|
|
||||||
index 5e5fe1c..1dab2aa 100644
|
|
||||||
--- a/dns/tsigkeyring.py
|
|
||||||
+++ b/dns/tsigkeyring.py
|
|
||||||
@@ -19,7 +19,14 @@
|
|
||||||
|
|
||||||
from dns._compat import maybe_decode, maybe_encode
|
|
||||||
|
|
||||||
-import base64
|
|
||||||
+
|
|
||||||
+try:
|
|
||||||
+ # New in version 3.1
|
|
||||||
+ from base64 import decodebytes, encodebytes
|
|
||||||
+except ImportError:
|
|
||||||
+ # Deprecated since version 3.1 and removed since 3.9
|
|
||||||
+ from base64 import decodestring as decodebytes
|
|
||||||
+ from base64 import encodestring as encodebytes
|
|
||||||
|
|
||||||
import dns.name
|
|
||||||
|
|
||||||
@@ -32,7 +39,7 @@ def from_text(textring):
|
|
||||||
keyring = {}
|
|
||||||
for keytext in textring:
|
|
||||||
keyname = dns.name.from_text(keytext)
|
|
||||||
- secret = base64.decodestring(maybe_encode(textring[keytext]))
|
|
||||||
+ secret = decodebytes(textring[keytext].encode())
|
|
||||||
keyring[keyname] = secret
|
|
||||||
return keyring
|
|
||||||
|
|
||||||
@@ -44,7 +51,8 @@ def to_text(keyring):
|
|
||||||
|
|
||||||
textring = {}
|
|
||||||
for keyname in keyring:
|
|
||||||
- keytext = maybe_decode(keyname.to_text())
|
|
||||||
- secret = maybe_decode(base64.encodestring(keyring[keyname]))
|
|
||||||
+ keytext = keyname.to_text()
|
|
||||||
+ # rstrip to get rid of the \n encoding adds
|
|
||||||
+ secret = encodebytes(keyring[keyname]).decode().rstrip()
|
|
||||||
textring[keytext] = secret
|
|
||||||
return textring
|
|
||||||
diff --git a/tests/test_tsigkeyring.py b/tests/test_tsigkeyring.py
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..17177c0
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/tests/test_tsigkeyring.py
|
|
||||||
@@ -0,0 +1,39 @@
|
|
||||||
+# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
|
||||||
+
|
|
||||||
+try:
|
|
||||||
+ # New in version 3.1
|
|
||||||
+ from base64 import decodebytes
|
|
||||||
+except ImportError:
|
|
||||||
+ # Deprecated since version 3.1 and removed since 3.9
|
|
||||||
+ from base64 import decodestring as decodebytes
|
|
||||||
+
|
|
||||||
+import unittest
|
|
||||||
+
|
|
||||||
+import dns.tsigkeyring
|
|
||||||
+
|
|
||||||
+text_keyring = {
|
|
||||||
+ 'keyname.' : 'NjHwPsMKjdN++dOfE5iAiQ=='
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+rich_keyring = {
|
|
||||||
+ dns.name.from_text('keyname.') : \
|
|
||||||
+ decodebytes('NjHwPsMKjdN++dOfE5iAiQ=='.encode())
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+class TSIGKeyRingTestCase(unittest.TestCase):
|
|
||||||
+
|
|
||||||
+ def test_from_text(self):
|
|
||||||
+ """text keyring -> rich keyring"""
|
|
||||||
+ rkeyring = dns.tsigkeyring.from_text(text_keyring)
|
|
||||||
+ self.assertEqual(rkeyring, rich_keyring)
|
|
||||||
+
|
|
||||||
+ def test_to_text(self):
|
|
||||||
+ """text keyring -> rich keyring -> text keyring"""
|
|
||||||
+ tkeyring = dns.tsigkeyring.to_text(rich_keyring)
|
|
||||||
+ self.assertEqual(tkeyring, text_keyring)
|
|
||||||
+
|
|
||||||
+ def test_from_and_to_text(self):
|
|
||||||
+ """text keyring -> rich keyring -> text keyring"""
|
|
||||||
+ rkeyring = dns.tsigkeyring.from_text(text_keyring)
|
|
||||||
+ tkeyring = dns.tsigkeyring.to_text(rkeyring)
|
|
||||||
+ self.assertEqual(tkeyring, text_keyring)
|
|
||||||
--
|
|
||||||
2.25.2
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
diff -ru dnspython-1.16.0-orig/dns/namedict.py dnspython-1.16.0/dns/namedict.py
|
|
||||||
--- dnspython-1.16.0-orig/dns/namedict.py 2018-12-01 10:25:27.000000000 -0500
|
|
||||||
+++ dnspython-1.16.0/dns/namedict.py 2020-01-21 19:48:57.266576401 -0500
|
|
||||||
@@ -27,12 +27,16 @@
|
|
||||||
|
|
||||||
"""DNS name dictionary"""
|
|
||||||
|
|
||||||
-import collections
|
|
||||||
import dns.name
|
|
||||||
from ._compat import xrange
|
|
||||||
|
|
||||||
+try:
|
|
||||||
+ from collections.abc import MutableMapping
|
|
||||||
+except ImportError:
|
|
||||||
+ from collections import MutableMapping
|
|
||||||
|
|
||||||
-class NameDict(collections.MutableMapping):
|
|
||||||
+
|
|
||||||
+class NameDict(MutableMapping):
|
|
||||||
"""A dictionary whose keys are dns.name.Name objects.
|
|
||||||
|
|
||||||
In addition to being like a regular Python dictionary, this
|
|
@ -1,44 +1,29 @@
|
|||||||
%global pypi_name dnspython
|
%global pypi_name dnspython
|
||||||
%global py_package_name dns
|
%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
|
|
||||||
%bcond_without python2
|
|
||||||
|
|
||||||
# Disable dependency generator until it has test code
|
|
||||||
%{?python_disable_dependency_generator}
|
|
||||||
|
|
||||||
Name: python-%{py_package_name}
|
Name: python-%{py_package_name}
|
||||||
Version: 1.16.0
|
Version: 2.0.0
|
||||||
Release: 13%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: DNS toolkit for Python
|
Summary: DNS toolkit for Python
|
||||||
|
|
||||||
License: MIT
|
# The entire package is licensed with both licenses, see LICENSE file
|
||||||
|
License: ISC and MIT
|
||||||
URL: http://www.dnspython.org
|
URL: http://www.dnspython.org
|
||||||
|
|
||||||
Source0: http://www.dnspython.org/kits/%{version}/%{pypi_name}-%{version}.tar.gz
|
Source0: https://github.com/rthalley/%{pypi_name}/archive/v%{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
|
BuildArch: noarch
|
||||||
|
|
||||||
Patch0: unicode_label_escapify.patch
|
|
||||||
Patch1: collections_abc.patch
|
|
||||||
Patch2: base64.patch
|
|
||||||
Patch3: switch_to_python_cryptography.patch
|
|
||||||
|
|
||||||
BuildRequires: python3-devel
|
BuildRequires: python3-devel
|
||||||
BuildRequires: python3-setuptools
|
BuildRequires: python3-setuptools
|
||||||
BuildRequires: python3-cryptography
|
BuildRequires: python3-cryptography
|
||||||
|
BuildRequires: python3-trio
|
||||||
%if %{with python2}
|
BuildRequires: python3-curio
|
||||||
BuildRequires: python2-devel
|
BuildRequires: python3-sniffio
|
||||||
BuildRequires: python2-setuptools
|
BuildRequires: python3-requests
|
||||||
%endif
|
BuildRequires: python3-requests-toolbelt
|
||||||
|
BuildRequires: python3-idna
|
||||||
|
BuildRequires: python3-pytest
|
||||||
|
|
||||||
%global _description %{expand:
|
%global _description %{expand:
|
||||||
dnspython is a DNS toolkit for Python. It supports almost all record
|
dnspython is a DNS toolkit for Python. It supports almost all record
|
||||||
@ -54,19 +39,13 @@ manipulation of DNS zones, messages, names, and records.
|
|||||||
%description %_description
|
%description %_description
|
||||||
%package -n python3-%{py_package_name}
|
%package -n python3-%{py_package_name}
|
||||||
Summary: %{summary}
|
Summary: %{summary}
|
||||||
Recommends: python3-cryptography
|
|
||||||
%{?python_provide:%python_provide python3-%{py_package_name}}
|
%{?python_provide:%python_provide python3-%{py_package_name}}
|
||||||
|
|
||||||
%description -n python3-%{py_package_name} %_description
|
%description -n python3-%{py_package_name} %_description
|
||||||
|
|
||||||
%if %{with python2}
|
# curio extras cannot be packages because nothing provides python3.9dist(curio) >= 1.2
|
||||||
%package -n python2-%{py_package_name}
|
%{?python_extras_subpkg:%python_extras_subpkg -n python3-dns -i %{python3_sitelib}/*.egg-info dnssec trio doh idna}
|
||||||
Summary: %{summary}
|
|
||||||
%{?python_provide:%python_provide python2-%{py_package_name}}
|
|
||||||
|
|
||||||
%description -n python2-%{py_package_name} %_description
|
|
||||||
python2-dns has no support for DNSSEC.
|
|
||||||
%endif
|
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
%autosetup -p1 -n %{pypi_name}-%{version}
|
%autosetup -p1 -n %{pypi_name}-%{version}
|
||||||
@ -76,23 +55,12 @@ find examples -type f | xargs chmod a-x
|
|||||||
|
|
||||||
%build
|
%build
|
||||||
%py3_build
|
%py3_build
|
||||||
%if %{with python2}
|
|
||||||
%py2_build
|
|
||||||
%endif
|
|
||||||
|
|
||||||
%install
|
%install
|
||||||
%py3_install
|
%py3_install
|
||||||
%if %{with python2}
|
|
||||||
%py2_install
|
|
||||||
%endif
|
|
||||||
|
|
||||||
%check
|
%check
|
||||||
%{python3} setup.py test
|
%pytest
|
||||||
%if %{with python2}
|
|
||||||
cp %{SOURCE1} .
|
|
||||||
%{python2} setup.py test
|
|
||||||
rm typing.py{,?}
|
|
||||||
%endif
|
|
||||||
|
|
||||||
%files -n python3-%{py_package_name}
|
%files -n python3-%{py_package_name}
|
||||||
%license LICENSE
|
%license LICENSE
|
||||||
@ -100,15 +68,11 @@ rm typing.py{,?}
|
|||||||
%{python3_sitelib}/%{py_package_name}
|
%{python3_sitelib}/%{py_package_name}
|
||||||
%{python3_sitelib}/%{pypi_name}-*.egg-info
|
%{python3_sitelib}/%{pypi_name}-*.egg-info
|
||||||
|
|
||||||
%if %{with python2}
|
|
||||||
%files -n python2-%{py_package_name}
|
|
||||||
%license LICENSE
|
|
||||||
%doc README.md examples
|
|
||||||
%{python2_sitelib}/%{py_package_name}
|
|
||||||
%{python2_sitelib}/%{pypi_name}-*.egg-info
|
|
||||||
%endif
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu Jul 30 2020 Lumír Balhar <lbalhar@redhat.com> - 2.0.0-1
|
||||||
|
- Update to 2.0.0 (#1849341)
|
||||||
|
- python2-dns moved to its own SRPM
|
||||||
|
|
||||||
* Wed Jul 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1.16.0-13
|
* Wed Jul 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1.16.0-13
|
||||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
|
||||||
|
|
||||||
|
2
sources
2
sources
@ -1 +1 @@
|
|||||||
SHA512 (dnspython-1.16.0.tar.gz) = 41ddca2faf696d5d682551f517efd90c007011c1f6d9355d297d71a3fe84222a1e528945343d8c2276ad3957ceaab578f3df7c2c1709418ffcca01ccbb379359
|
SHA512 (dnspython-2.0.0.tar.gz) = 3b38850fcacb0dd25ac0345201474f297c402617e8d706f3061c42172d697103075098e62ca0ac4e0e29967e00407f32f41789ac7bf070fba5aec0af9882e0fb
|
||||||
|
@ -1,343 +0,0 @@
|
|||||||
From 087df702931f32eeb3a29957a8fe3fa31749d642 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Simo Sorce <simo@redhat.com>
|
|
||||||
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
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
|||||||
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[:]
|
|
Loading…
Reference in New Issue
Block a user